xref: /aoo41x/main/svx/source/svdraw/svdmark.cxx (revision cdf0e10c)
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 
31 ////////////////////////////////////////////////////////////////////////////////////////////////////
32 
33 #include <svx/svdmark.hxx>
34 #include <svx/svdetc.hxx>
35 #include <svx/svdobj.hxx>
36 #include <svx/svdpage.hxx>
37 #include "svx/svditer.hxx"
38 #include <svx/svdpagv.hxx>
39 #include <svx/svdopath.hxx> // zur Abschaltung
40 #include <svx/svdogrp.hxx>  // des Cache bei
41 #include <svx/svdorect.hxx> // GetMarkDescription
42 #include "svx/svdstr.hrc"   // Namen aus der Resource
43 #include "svx/svdglob.hxx"  // StringCache
44 
45 ////////////////////////////////////////////////////////////////////////////////////////////////////
46 #include <svx/obj3d.hxx>
47 #include <svx/scene3d.hxx>
48 #include <svl/brdcst.hxx>
49 #include <svx/svdoedge.hxx>
50 
51 ////////////////////////////////////////////////////////////////////////////////////////////////////
52 
53 class ImpSdrUShortContSorter: public ContainerSorter
54 {
55 public:
56 	ImpSdrUShortContSorter(Container& rNewCont)
57 	:	ContainerSorter(rNewCont)
58 	{}
59 
60 	virtual int Compare(const void* pElem1, const void* pElem2) const;
61 };
62 
63 int ImpSdrUShortContSorter::Compare(const void* pElem1, const void* pElem2) const
64 {
65 	sal_uInt16 n1((sal_uInt16)((sal_uIntPtr)pElem1));
66 	sal_uInt16 n2((sal_uInt16)((sal_uIntPtr)pElem2));
67 
68 	return ((n1 < n2) ? (-1) : (n1 > n2) ? (1) : (0));
69 }
70 
71 void SdrUShortCont::Sort() const
72 {
73 	ImpSdrUShortContSorter aSort(*((Container*)(&maArray)));
74 	aSort.DoSort();
75 	((SdrUShortCont*)this)->mbSorted = sal_True;
76 
77 	sal_uLong nNum(GetCount());
78 
79 	if(nNum > 1)
80 	{
81 		nNum--;
82 		sal_uInt16 nVal0 = GetObject(nNum);
83 
84 		while(nNum > 0)
85 		{
86 			nNum--;
87 			sal_uInt16 nVal1 = GetObject(nNum);
88 
89 			if(nVal1 == nVal0)
90 			{
91 				((SdrUShortCont*)this)->Remove(nNum);
92 			}
93 
94 			nVal0 = nVal1;
95 		}
96 	}
97 }
98 
99 void SdrUShortCont::CheckSort(sal_uLong nPos)
100 {
101 	sal_uLong nAnz(maArray.Count());
102 
103 	if(nPos > nAnz)
104 		nPos = nAnz;
105 
106 	sal_uInt16 nAktVal = GetObject(nPos);
107 
108 	if(nPos > 0)
109 	{
110 		sal_uInt16 nPrevVal = GetObject(nPos - 1);
111 
112 		if(nPrevVal >= nAktVal)
113 			mbSorted = sal_False;
114 	}
115 
116 	if(nPos < nAnz - 1)
117 	{
118 		sal_uInt16 nNextVal = GetObject(nPos + 1);
119 
120 		if(nNextVal <= nAktVal)
121 			mbSorted = sal_False;
122 	}
123 }
124 
125 std::set< sal_uInt16 > SdrUShortCont::getContainer()
126 {
127 	std::set< sal_uInt16 > aSet;
128 
129 	sal_uInt32 nAnz = maArray.Count();
130 	while(nAnz)
131 		aSet.insert( GetObject(--nAnz) );
132 
133 	return aSet;
134 }
135 
136 ////////////////////////////////////////////////////////////////////////////////////////////////////
137 
138 SdrMark::SdrMark(SdrObject* pNewObj, SdrPageView* pNewPageView)
139 :	mpSelectedSdrObject(pNewObj),
140 	mpPageView(pNewPageView),
141 	mpPoints(0L),
142 	mpLines(0L),
143 	mpGluePoints(0L),
144 	mbCon1(sal_False),
145 	mbCon2(sal_False),
146 	mnUser(0)
147 {
148 	if(mpSelectedSdrObject)
149 	{
150 		mpSelectedSdrObject->AddObjectUser( *this );
151 	}
152 }
153 
154 SdrMark::SdrMark(const SdrMark& rMark)
155 :	ObjectUser(),
156     mpSelectedSdrObject(0L),
157 	mpPageView(0L),
158 	mpPoints(0L),
159 	mpLines(0L),
160 	mpGluePoints(0L),
161 	mbCon1(sal_False),
162 	mbCon2(sal_False),
163 	mnUser(0)
164 {
165 	*this = rMark;
166 }
167 
168 SdrMark::~SdrMark()
169 {
170 	if(mpSelectedSdrObject)
171 	{
172 		mpSelectedSdrObject->RemoveObjectUser( *this );
173 	}
174 
175 	if(mpPoints)
176 	{
177 		delete mpPoints;
178 	}
179 
180 	if(mpLines)
181 	{
182 		delete mpLines;
183 	}
184 
185 	if(mpGluePoints)
186 	{
187 		delete mpGluePoints;
188 	}
189 }
190 
191 void SdrMark::ObjectInDestruction(const SdrObject& rObject)
192 {
193     (void) rObject; // avoid warnings
194 	OSL_ENSURE(mpSelectedSdrObject && mpSelectedSdrObject == &rObject, "SdrMark::ObjectInDestruction: called form object different from hosted one (!)");
195 	OSL_ENSURE(mpSelectedSdrObject, "SdrMark::ObjectInDestruction: still seleceted SdrObject is deleted, deselect first (!)");
196 	mpSelectedSdrObject = 0L;
197 }
198 
199 void SdrMark::SetMarkedSdrObj(SdrObject* pNewObj)
200 {
201 	if(mpSelectedSdrObject)
202 	{
203 		mpSelectedSdrObject->RemoveObjectUser( *this );
204 	}
205 
206 	mpSelectedSdrObject = pNewObj;
207 
208 	if(mpSelectedSdrObject)
209 	{
210 		mpSelectedSdrObject->AddObjectUser( *this );
211 	}
212 }
213 
214 SdrObject* SdrMark::GetMarkedSdrObj() const
215 {
216 	return mpSelectedSdrObject;
217 }
218 
219 SdrMark& SdrMark::operator=(const SdrMark& rMark)
220 {
221 	SetMarkedSdrObj(rMark.mpSelectedSdrObject);
222 	mpPageView = rMark.mpPageView;
223 	mbCon1 = rMark.mbCon1;
224 	mbCon2 = rMark.mbCon2;
225 	mnUser = rMark.mnUser;
226 
227 	if(!rMark.mpPoints)
228 	{
229 		if(mpPoints)
230 		{
231 			delete mpPoints;
232 			mpPoints = 0L;
233 		}
234 	}
235 	else
236 	{
237 		if(!mpPoints)
238 		{
239 			mpPoints = new SdrUShortCont(*rMark.mpPoints);
240 		}
241 		else
242 		{
243 			*mpPoints = *rMark.mpPoints;
244 		}
245 	}
246 
247 	if(!rMark.mpLines)
248 	{
249 		if(mpLines)
250 		{
251 			delete mpLines;
252 			mpLines = 0L;
253 		}
254 	}
255 	else
256 	{
257 		if(!mpLines)
258 		{
259 			mpLines = new SdrUShortCont(*rMark.mpLines);
260 		}
261 		else
262 		{
263 			*mpLines = *rMark.mpLines;
264 		}
265 	}
266 
267 	if(!rMark.mpGluePoints)
268 	{
269 		if(mpGluePoints)
270 		{
271 			delete mpGluePoints;
272 			mpGluePoints = 0L;
273 		}
274 	}
275 	else
276 	{
277 		if(!mpGluePoints)
278 		{
279 			mpGluePoints = new SdrUShortCont(*rMark.mpGluePoints);
280 		}
281 		else
282 		{
283 			*mpGluePoints = *rMark.mpGluePoints;
284 		}
285 	}
286 
287 	return *this;
288 }
289 
290 sal_Bool SdrMark::operator==(const SdrMark& rMark) const
291 {
292 	sal_Bool bRet(mpSelectedSdrObject == rMark.mpSelectedSdrObject && mpPageView == rMark.mpPageView && mbCon1 == rMark.mbCon1 && mbCon2 == rMark.mbCon2 && mnUser == rMark.mnUser);
293 
294 	if((mpPoints != 0L) != (rMark.mpPoints != 0L))
295 		bRet = sal_False;
296 
297 	if((mpLines != 0L) != (rMark.mpLines != 0L))
298 		bRet = sal_False;
299 
300 	if((mpGluePoints != 0L) != (rMark.mpGluePoints != 0L))
301 		bRet = sal_False;
302 
303 	if(bRet && mpPoints && *mpPoints != *rMark.mpPoints)
304 		bRet = sal_False;
305 
306 	if(bRet && mpLines && *mpLines != *rMark.mpLines)
307 		bRet = sal_False;
308 
309 	if(bRet && mpGluePoints && *mpGluePoints != *rMark.mpGluePoints)
310 		bRet = sal_False;
311 
312 	return bRet;
313 }
314 
315 SdrPage* SdrMark::GetPage() const
316 {
317 	return (mpSelectedSdrObject ? mpSelectedSdrObject->GetPage() : 0);
318 }
319 
320 SdrObjList* SdrMark::GetObjList() const
321 {
322 	return (mpSelectedSdrObject ? mpSelectedSdrObject->GetObjList() : 0);
323 }
324 
325 ////////////////////////////////////////////////////////////////////////////////////////////////////
326 
327 class ImpSdrMarkListSorter: public ContainerSorter
328 {
329 public:
330 	ImpSdrMarkListSorter(Container& rNewCont)
331         :	ContainerSorter(rNewCont)
332 	{}
333 
334 	virtual int Compare(const void* pElem1, const void* pElem2) const;
335 };
336 
337 int ImpSdrMarkListSorter::Compare(const void* pElem1, const void* pElem2) const
338 {
339 	SdrObject* pObj1 = ((SdrMark*)pElem1)->GetMarkedSdrObj();
340 	SdrObject* pObj2 = ((SdrMark*)pElem2)->GetMarkedSdrObj();
341 	SdrObjList* pOL1 = (pObj1) ? pObj1->GetObjList() : 0L;
342 	SdrObjList* pOL2 = (pObj2) ? pObj2->GetObjList() : 0L;
343 
344 	if (pOL1 == pOL2)
345     {
346         // AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
347         // for 64bit compliance, #i78198#) because internally in SdrObject
348         // both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
349         sal_uInt32 nObjOrd1((pObj1) ? pObj1->GetNavigationPosition() : 0);
350         sal_uInt32 nObjOrd2((pObj2) ? pObj2->GetNavigationPosition() : 0);
351 
352         return (nObjOrd1 < nObjOrd2 ? -1 : 1);
353     }
354 	else
355 	{
356 		return ((long)pOL1 < (long)pOL2) ? -1 : 1;
357 	}
358 }
359 
360 ////////////////////////////////////////////////////////////////////////////////////////////////////
361 
362 void SdrMarkList::ForceSort() const
363 {
364 	if(!mbSorted)
365 	{
366 		((SdrMarkList*)this)->ImpForceSort();
367 	}
368 }
369 
370 void SdrMarkList::ImpForceSort()
371 {
372 	if(!mbSorted)
373 	{
374 		mbSorted = sal_True;
375 		sal_uLong nAnz = maList.Count();
376 
377 		// remove invalid
378 		if(nAnz > 0 )
379 		{
380 			SdrMark* pAkt = (SdrMark*)maList.First();
381 			while( pAkt )
382 			{
383 				if(pAkt->GetMarkedSdrObj() == 0)
384 				{
385 					maList.Remove();
386 					delete pAkt;
387 				}
388 				pAkt= (SdrMark*)maList.Next();
389 			}
390 			nAnz = maList.Count();
391 		}
392 
393 		if(nAnz > 1)
394 		{
395 			ImpSdrMarkListSorter aSort(maList);
396 			aSort.DoSort();
397 
398 			// remove duplicates
399 			if(maList.Count() > 1)
400 			{
401 				SdrMark* pAkt = (SdrMark*)maList.Last();
402 				SdrMark* pCmp = (SdrMark*)maList.Prev();
403 
404 				while(pCmp)
405 				{
406 					if(pAkt->GetMarkedSdrObj() == pCmp->GetMarkedSdrObj() && pAkt->GetMarkedSdrObj())
407 					{
408 						// Con1/Con2 Merging
409 						if(pCmp->IsCon1())
410 							pAkt->SetCon1(sal_True);
411 
412 						if(pCmp->IsCon2())
413 							pAkt->SetCon2(sal_True);
414 
415 						// pCmp loeschen.
416 						maList.Remove();
417 
418 						delete pCmp;
419 					}
420 					else
421 					{
422 						pAkt = pCmp;
423 					}
424 
425 					pCmp = (SdrMark*)maList.Prev();
426 				}
427 			}
428 		}
429 	}
430 }
431 
432 void SdrMarkList::Clear()
433 {
434 	for(sal_uLong i(0L); i < GetMarkCount(); i++)
435 	{
436 		SdrMark* pMark = GetMark(i);
437 		delete pMark;
438 	}
439 
440 	maList.Clear();
441 	SetNameDirty();
442 }
443 
444 void SdrMarkList::operator=(const SdrMarkList& rLst)
445 {
446 	Clear();
447 
448 	for(sal_uLong i(0L); i < rLst.GetMarkCount(); i++)
449 	{
450 		SdrMark* pMark = rLst.GetMark(i);
451 		SdrMark* pNeuMark = new SdrMark(*pMark);
452 		maList.Insert(pNeuMark, CONTAINER_APPEND);
453 	}
454 
455 	maMarkName = rLst.maMarkName;
456 	mbNameOk = rLst.mbNameOk;
457 	maPointName = rLst.maPointName;
458 	mbPointNameOk = rLst.mbPointNameOk;
459 	maGluePointName = rLst.maGluePointName;
460 	mbGluePointNameOk = rLst.mbGluePointNameOk;
461 	mbSorted = rLst.mbSorted;
462 }
463 
464 sal_uLong SdrMarkList::FindObject(const SdrObject* pObj) const
465 {
466 	// #109658#
467 	//
468 	// Since relying on OrdNums is not allowed for the selection because objects in the
469 	// selection may not be inserted in a list if they are e.g. modified ATM, i changed
470 	// this loop to just look if the object pointer is in the selection.
471 	//
472 	// Problem is that GetOrdNum() which is const, internally casts to non-const and
473 	// hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
474 	// is not inserted in a object list.
475 	// Since this may be by purpose and necessary somewhere else i decided that it is
476 	// less dangerous to change this method then changing SdrObject::GetOrdNum().
477 	if(pObj && maList.Count())
478 	{
479 		for(sal_uLong a(0L); a < maList.Count(); a++)
480 		{
481 			if(((SdrMark*)(maList.GetObject(a)))->GetMarkedSdrObj() == pObj)
482 			{
483 				return a;
484 			}
485 		}
486 	}
487 
488 	return CONTAINER_ENTRY_NOTFOUND;
489 }
490 
491 void SdrMarkList::InsertEntry(const SdrMark& rMark, sal_Bool bChkSort)
492 {
493 	SetNameDirty();
494 	sal_uLong nAnz(maList.Count());
495 
496 	if(!bChkSort || !mbSorted || nAnz == 0)
497 	{
498 		if(!bChkSort)
499 			mbSorted = sal_False;
500 
501 		maList.Insert(new SdrMark(rMark), CONTAINER_APPEND);
502 	}
503 	else
504 	{
505 		SdrMark* pLast = GetMark(sal_uLong(nAnz - 1));
506 		const SdrObject* pLastObj = pLast->GetMarkedSdrObj();
507 		const SdrObject* pNeuObj = rMark.GetMarkedSdrObj();
508 
509 		if(pLastObj == pNeuObj)
510 		{
511 			// Aha, den gibt's schon
512 			// Con1/Con2 Merging
513 			if(rMark.IsCon1())
514 				pLast->SetCon1(sal_True);
515 
516 			if(rMark.IsCon2())
517 				pLast->SetCon2(sal_True);
518 		}
519 		else
520 		{
521 			SdrMark* pKopie = new SdrMark(rMark);
522 			maList.Insert(pKopie, CONTAINER_APPEND);
523 
524 			// und nun checken, ob die Sortierung noch ok ist
525 			const SdrObjList* pLastOL = pLastObj!=0L ? pLastObj->GetObjList() : 0L;
526 			const SdrObjList* pNeuOL = pNeuObj !=0L ? pNeuObj ->GetObjList() : 0L;
527 
528 			if(pLastOL == pNeuOL)
529 			{
530 				const sal_uLong nLastNum(pLastObj!=0L ? pLastObj->GetOrdNum() : 0);
531 				const sal_uLong nNeuNum(pNeuObj !=0L ? pNeuObj ->GetOrdNum() : 0);
532 
533 				if(nNeuNum < nLastNum)
534 				{
535 					// irgendwann muss mal sortiert werden
536 					mbSorted = sal_False;
537 				}
538 			}
539 			else
540 			{
541 				// irgendwann muss mal sortiert werden
542 				mbSorted = sal_False;
543 			}
544 		}
545 	}
546 
547 	return;
548 }
549 
550 void SdrMarkList::DeleteMark(sal_uLong nNum)
551 {
552 	SdrMark* pMark = GetMark(nNum);
553 	DBG_ASSERT(pMark!=0L,"DeleteMark: MarkEntry nicht gefunden");
554 
555 	if(pMark)
556 	{
557 		maList.Remove(nNum);
558 		delete pMark;
559 		SetNameDirty();
560 	}
561 }
562 
563 void SdrMarkList::ReplaceMark(const SdrMark& rNewMark, sal_uLong nNum)
564 {
565 	SdrMark* pMark = GetMark(nNum);
566 	DBG_ASSERT(pMark!=0L,"ReplaceMark: MarkEntry nicht gefunden");
567 
568 	if(pMark)
569 	{
570 		delete pMark;
571 		SetNameDirty();
572 		SdrMark* pKopie = new SdrMark(rNewMark);
573 		maList.Replace(pKopie, nNum);
574 		mbSorted = sal_False;
575 	}
576 }
577 
578 void SdrMarkList::Merge(const SdrMarkList& rSrcList, sal_Bool bReverse)
579 {
580 	sal_uLong nAnz(rSrcList.maList.Count());
581 
582 	if(rSrcList.mbSorted)
583 	{
584 		// Merging ohne ein Sort bei rSrcList zu erzwingen
585 		bReverse = sal_False;
586 	}
587 
588 	if(!bReverse)
589 	{
590 		for(sal_uLong i(0L); i < nAnz; i++)
591 		{
592 			SdrMark* pM = (SdrMark*)(rSrcList.maList.GetObject(i));
593 			InsertEntry(*pM);
594 		}
595 	}
596 	else
597 	{
598 		for(sal_uLong i(nAnz); i > 0;)
599 		{
600 			i--;
601 			SdrMark* pM = (SdrMark*)(rSrcList.maList.GetObject(i));
602 			InsertEntry(*pM);
603 		}
604 	}
605 }
606 
607 sal_Bool SdrMarkList::DeletePageView(const SdrPageView& rPV)
608 {
609 	sal_Bool bChgd(sal_False);
610 
611 	for(sal_uLong i(GetMarkCount()); i > 0; )
612 	{
613 		i--;
614 		SdrMark* pMark = GetMark(i);
615 
616 		if(pMark->GetPageView()==&rPV)
617 		{
618 			maList.Remove(i);
619 			delete pMark;
620 			SetNameDirty();
621 			bChgd = sal_True;
622 		}
623 	}
624 
625 	return bChgd;
626 }
627 
628 sal_Bool SdrMarkList::InsertPageView(const SdrPageView& rPV)
629 {
630 	sal_Bool bChgd(sal_False);
631 	DeletePageView(rPV); // erstmal alle raus, dann die ganze Seite hinten dran
632 	SdrObject* pObj;
633 	const SdrObjList* pOL = rPV.GetObjList();
634 	sal_uLong nObjAnz(pOL->GetObjCount());
635 
636 	for(sal_uLong nO(0L); nO < nObjAnz; nO++)
637 	{
638 		pObj = pOL->GetObj(nO);
639 		sal_Bool bDoIt(rPV.IsObjMarkable(pObj));
640 
641 		if(bDoIt)
642 		{
643 			SdrMark* pM = new SdrMark(pObj, (SdrPageView*)&rPV);
644 			maList.Insert(pM, CONTAINER_APPEND);
645 			SetNameDirty();
646 			bChgd = sal_True;
647 		}
648 	}
649 
650 	return bChgd;
651 }
652 
653 const XubString& SdrMarkList::GetMarkDescription() const
654 {
655 	sal_uLong nAnz(GetMarkCount());
656 
657 	if(mbNameOk && 1L == nAnz)
658 	{
659 		// Bei Einfachselektion nur Textrahmen cachen
660 		const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
661 		const SdrTextObj* pTextObj = PTR_CAST(SdrTextObj, pObj);
662 
663 		if(!pTextObj || !pTextObj->IsTextFrame())
664 		{
665 			((SdrMarkList*)(this))->mbNameOk = sal_False;
666 		}
667 	}
668 
669 	if(!mbNameOk)
670 	{
671 		SdrMark* pMark = GetMark(0);
672 		XubString aNam;
673 
674 		if(!nAnz)
675 		{
676 			((SdrMarkList*)(this))->maMarkName = ImpGetResStr(STR_ObjNameNoObj);
677 		}
678 		else if(1L == nAnz)
679 		{
680 			if(pMark->GetMarkedSdrObj())
681 			{
682 				pMark->GetMarkedSdrObj()->TakeObjNameSingul(aNam);
683 			}
684 		}
685 		else
686 		{
687 			if(pMark->GetMarkedSdrObj())
688 			{
689 				pMark->GetMarkedSdrObj()->TakeObjNamePlural(aNam);
690 				XubString aStr1;
691 				sal_Bool bEq(sal_True);
692 
693 				for(sal_uLong i = 1; i < GetMarkCount() && bEq; i++)
694 				{
695 					SdrMark* pMark2 = GetMark(i);
696 					pMark2->GetMarkedSdrObj()->TakeObjNamePlural(aStr1);
697 					bEq = aNam.Equals(aStr1);
698 				}
699 
700 				if(!bEq)
701 				{
702 					aNam = ImpGetResStr(STR_ObjNamePlural);
703 				}
704 			}
705 
706 			aNam.Insert(sal_Unicode(' '), 0);
707 			aNam.Insert(UniString::CreateFromInt32(nAnz), 0);
708 		}
709 
710 		((SdrMarkList*)(this))->maMarkName = aNam;
711 		((SdrMarkList*)(this))->mbNameOk = sal_True;
712 	}
713 
714 	return maMarkName;
715 }
716 
717 const XubString& SdrMarkList::GetPointMarkDescription(sal_Bool bGlue) const
718 {
719 	sal_Bool& rNameOk = (sal_Bool&)(bGlue ? mbGluePointNameOk : mbPointNameOk);
720 	XubString& rName = (XubString&)(bGlue ? maGluePointName : maPointName);
721 	sal_uLong nMarkAnz(GetMarkCount());
722 	sal_uLong nMarkPtAnz(0L);
723 	sal_uLong nMarkPtObjAnz(0L);
724 	sal_uLong n1stMarkNum(ULONG_MAX);
725 
726 	for(sal_uLong nMarkNum(0L); nMarkNum < nMarkAnz; nMarkNum++)
727 	{
728 		const SdrMark* pMark = GetMark(nMarkNum);
729 		const SdrUShortCont* pPts = bGlue ? pMark->GetMarkedGluePoints() : pMark->GetMarkedPoints();
730 		sal_uLong nAnz(pPts ? pPts->GetCount() : 0);
731 
732 		if(nAnz)
733 		{
734 			if(n1stMarkNum == ULONG_MAX)
735 			{
736 				n1stMarkNum = nMarkNum;
737 			}
738 
739 			nMarkPtAnz += nAnz;
740 			nMarkPtObjAnz++;
741 		}
742 
743 		if(nMarkPtObjAnz > 1 && rNameOk)
744 		{
745 			// vorzeitige Entscheidung
746 			return rName;
747 		}
748 	}
749 
750 	if(rNameOk && 1L == nMarkPtObjAnz)
751 	{
752 		// Bei Einfachselektion nur Textrahmen cachen
753 		const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
754 		const SdrTextObj* pTextObj = PTR_CAST(SdrTextObj,pObj);
755 
756 		if(!pTextObj || !pTextObj->IsTextFrame())
757 		{
758 			rNameOk = sal_False;
759 		}
760 	}
761 
762 	if(!nMarkPtObjAnz)
763 	{
764 		rName.Erase();
765 		rNameOk = sal_True;
766 	}
767 	else if(!rNameOk)
768 	{
769 		const SdrMark* pMark = GetMark(n1stMarkNum);
770 		XubString aNam;
771 
772 		if(1L == nMarkPtObjAnz)
773 		{
774 			if(pMark->GetMarkedSdrObj())
775 			{
776 				pMark->GetMarkedSdrObj()->TakeObjNameSingul(aNam);
777 			}
778 		}
779 		else
780 		{
781 			if(pMark->GetMarkedSdrObj())
782 			{
783 				pMark->GetMarkedSdrObj()->TakeObjNamePlural(aNam);
784 			}
785 
786 			XubString aStr1;
787 			sal_Bool bEq(sal_True);
788 
789 			for(sal_uLong i(n1stMarkNum + 1L); i < GetMarkCount() && bEq; i++)
790 			{
791 				const SdrMark* pMark2 = GetMark(i);
792 				const SdrUShortCont* pPts = bGlue ? pMark2->GetMarkedGluePoints() : pMark2->GetMarkedPoints();
793 
794 				if(pPts && pPts->GetCount() && pMark2->GetMarkedSdrObj())
795 				{
796 					pMark2->GetMarkedSdrObj()->TakeObjNamePlural(aStr1);
797 					bEq = aNam.Equals(aStr1);
798 				}
799 			}
800 
801 			if(!bEq)
802 			{
803 				aNam = ImpGetResStr(STR_ObjNamePlural);
804 			}
805 
806 			aNam.Insert(sal_Unicode(' '), 0);
807 			aNam.Insert(UniString::CreateFromInt32(nMarkPtObjAnz), 0);
808 		}
809 
810 		XubString aStr1;
811 
812 		if(1L == nMarkPtAnz)
813 		{
814 			aStr1 = (ImpGetResStr(bGlue ? STR_ViewMarkedGluePoint : STR_ViewMarkedPoint));
815 		}
816 		else
817 		{
818 			aStr1 = (ImpGetResStr(bGlue ? STR_ViewMarkedGluePoints : STR_ViewMarkedPoints));
819 			aStr1.SearchAndReplaceAscii("%2", UniString::CreateFromInt32(nMarkPtAnz));
820 		}
821 
822 		aStr1.SearchAndReplaceAscii("%1", aNam);
823 		rName = aStr1;
824 		rNameOk = sal_True;
825 	}
826 
827 	return rName;
828 }
829 
830 sal_Bool SdrMarkList::TakeBoundRect(SdrPageView* pPV, Rectangle& rRect) const
831 {
832 	sal_Bool bFnd(sal_False);
833 	Rectangle aR;
834 
835 	for(sal_uLong i(0L); i < GetMarkCount(); i++)
836 	{
837 		SdrMark* pMark = GetMark(i);
838 
839 		if(!pPV || pMark->GetPageView() == pPV)
840 		{
841 			if(pMark->GetMarkedSdrObj())
842 			{
843 				aR = pMark->GetMarkedSdrObj()->GetCurrentBoundRect();
844 
845 				if(bFnd)
846 				{
847 					rRect.Union(aR);
848 				}
849 				else
850 				{
851 					rRect = aR;
852 					bFnd = sal_True;
853 				}
854 			}
855 		}
856 	}
857 
858 	return bFnd;
859 }
860 
861 sal_Bool SdrMarkList::TakeSnapRect(SdrPageView* pPV, Rectangle& rRect) const
862 {
863 	sal_Bool bFnd(sal_False);
864 
865 	for(sal_uLong i(0L); i < GetMarkCount(); i++)
866 	{
867 		SdrMark* pMark = GetMark(i);
868 
869 		if(!pPV || pMark->GetPageView() == pPV)
870 		{
871 			if(pMark->GetMarkedSdrObj())
872 			{
873 				Rectangle aR(pMark->GetMarkedSdrObj()->GetSnapRect());
874 
875 				if(bFnd)
876 				{
877 					rRect.Union(aR);
878 				}
879 				else
880 				{
881 					rRect = aR;
882 					bFnd = sal_True;
883 				}
884 			}
885 		}
886 	}
887 
888 	return bFnd;
889 }
890 
891 ////////////////////////////////////////////////////////////////////////////////////////////////////
892 
893 namespace sdr
894 {
895 	ViewSelection::ViewSelection()
896 	:	mbEdgesOfMarkedNodesDirty(sal_False)
897 	{
898 	}
899 
900 	void ViewSelection::SetEdgesOfMarkedNodesDirty()
901 	{
902 		if(!mbEdgesOfMarkedNodesDirty)
903 		{
904 			mbEdgesOfMarkedNodesDirty = sal_True;
905 			maEdgesOfMarkedNodes.Clear();
906 			maMarkedEdgesOfMarkedNodes.Clear();
907 			maAllMarkedObjects.Clear();
908 		}
909 	}
910 
911 	const SdrMarkList& ViewSelection::GetEdgesOfMarkedNodes() const
912 	{
913 		if(mbEdgesOfMarkedNodesDirty)
914 		{
915 			((ViewSelection*)this)->ImpForceEdgesOfMarkedNodes();
916 		}
917 
918 		return maEdgesOfMarkedNodes;
919 	}
920 
921 	const SdrMarkList& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
922 	{
923 		if(mbEdgesOfMarkedNodesDirty)
924 		{
925 			((ViewSelection*)this)->ImpForceEdgesOfMarkedNodes();
926 		}
927 
928 		return maMarkedEdgesOfMarkedNodes;
929 	}
930 
931 	const List& ViewSelection::GetAllMarkedObjects() const
932 	{
933 		if(mbEdgesOfMarkedNodesDirty)
934 		{
935 			((ViewSelection*)this)->ImpForceEdgesOfMarkedNodes();
936 		}
937 
938 		return maAllMarkedObjects;
939 	}
940 
941 	void ViewSelection::ImplCollectCompleteSelection(SdrObject* pObj)
942 	{
943 		if(pObj)
944 		{
945 			sal_Bool bIsGroup(pObj->IsGroupObject());
946 
947 			if(bIsGroup && pObj->ISA(E3dObject) && !pObj->ISA(E3dScene))
948 			{
949 				bIsGroup = sal_False;
950 			}
951 
952 			if(bIsGroup)
953 			{
954 				SdrObjList* pList = pObj->GetSubList();
955 
956 				for(sal_uLong a(0L); a < pList->GetObjCount(); a++)
957 				{
958 					SdrObject* pObj2 = pList->GetObj(a);
959 					ImplCollectCompleteSelection(pObj2);
960 				}
961 			}
962 
963 			maAllMarkedObjects.Insert(pObj, LIST_APPEND);
964 		}
965 	}
966 
967 	void ViewSelection::ImpForceEdgesOfMarkedNodes()
968 	{
969 		if(mbEdgesOfMarkedNodesDirty)
970 		{
971 			mbEdgesOfMarkedNodesDirty = sal_False;
972 			maMarkedObjectList.ForceSort();
973 			maEdgesOfMarkedNodes.Clear();
974 			maMarkedEdgesOfMarkedNodes.Clear();
975 			maAllMarkedObjects.Clear();
976 
977 			// #126320# GetMarkCount after ForceSort
978 			const sal_uLong nMarkAnz(maMarkedObjectList.GetMarkCount());
979 
980 			for(sal_uLong a(0L); a < nMarkAnz; a++)
981 			{
982 				SdrObject* pCandidate = maMarkedObjectList.GetMark(a)->GetMarkedSdrObj();
983 
984 				if(pCandidate)
985 				{
986 					// build transitive hull
987 					ImplCollectCompleteSelection(pCandidate);
988 
989 					if(pCandidate->IsNode())
990 					{
991 						// travel over broadcaster/listener to access edges connected to the selected object
992 						const SfxBroadcaster* pBC = pCandidate->GetBroadcaster();
993 
994 						if(pBC)
995 						{
996 							sal_uInt16 nLstAnz(pBC->GetListenerCount());
997 
998 							for(sal_uInt16 nl(0); nl < nLstAnz; nl++)
999 							{
1000 								SfxListener* pLst = pBC->GetListener(nl);
1001 								SdrEdgeObj* pEdge = PTR_CAST(SdrEdgeObj, pLst);
1002 
1003 								if(pEdge && pEdge->IsInserted() && pEdge->GetPage() == pCandidate->GetPage())
1004 								{
1005 									SdrMark aM(pEdge, maMarkedObjectList.GetMark(a)->GetPageView());
1006 
1007 									if(pEdge->GetConnectedNode(sal_True) == pCandidate)
1008 									{
1009 										aM.SetCon1(sal_True);
1010 									}
1011 
1012 									if(pEdge->GetConnectedNode(sal_False) == pCandidate)
1013 									{
1014 										aM.SetCon2(sal_True);
1015 									}
1016 
1017 									if(CONTAINER_ENTRY_NOTFOUND == maMarkedObjectList.FindObject(pEdge))
1018 									{
1019 										// nachsehen, ob er selbst markiert ist
1020 										maEdgesOfMarkedNodes.InsertEntry(aM);
1021 									}
1022 									else
1023 									{
1024 										maMarkedEdgesOfMarkedNodes.InsertEntry(aM);
1025 									}
1026 								}
1027 							}
1028 						}
1029 					}
1030 				}
1031 			}
1032 
1033 			maEdgesOfMarkedNodes.ForceSort();
1034 			maMarkedEdgesOfMarkedNodes.ForceSort();
1035 		}
1036 	}
1037 } // end of namespace sdr
1038 
1039 ////////////////////////////////////////////////////////////////////////////////////////////////////
1040 // eof
1041