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/svdedtv.hxx>
21 #include <editeng/outliner.hxx>
22 #include <svx/svdundo.hxx>
23 #include <svx/svdogrp.hxx> // for grouping objects
24 #include <svx/svdovirt.hxx> // for VirtualObject bundling (Writer)
25 #include <svx/svdopath.hxx> // for CombineObjects
26 #include <svx/svdpage.hxx>
27 #include <svx/svdpagv.hxx>
28 #include "svx/svditer.hxx"
29 #include <svx/svdograf.hxx> // for Possibilities
30 #include <svx/svdoole2.hxx> // and Mtf-Import
31 #include "svx/svdstr.hrc" // names taken from the resource
32 #include "svx/svdglob.hxx" // StringCache
33 #include "svdfmtf.hxx"
34 #include <svx/svdetc.hxx>
35 #include <sfx2/basedlgs.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <editeng/outlobj.hxx>
38 #include <editeng/eeitem.hxx>
39 #include <basegfx/polygon/b2dpolypolygon.hxx>
40 #include <basegfx/polygon/b2dpolypolygontools.hxx>
42 #include <svx/svxdlg.hxx>
43 #include <svx/dialogs.hrc>
46 #include <svx/svdoashp.hxx>
47 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
52 SdrObject
* SdrEditView::GetMaxToTopObj(SdrObject
* /*pObj*/) const
57 SdrObject
* SdrEditView::GetMaxToBtmObj(SdrObject
* /*pObj*/) const
62 void SdrEditView::ObjOrderChanged(SdrObject
* /*pObj*/, sal_uIntPtr
/*nOldPos*/, sal_uIntPtr
/*nNewPos*/)
66 void SdrEditView::MovMarkedToTop()
68 sal_uIntPtr nAnz
=GetMarkedObjectCount();
71 const bool bUndo
= IsUndoEnabled();
74 BegUndo(ImpGetResStr(STR_EditMovToTop
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOTOP
);
78 for (nm
=0; nm
<nAnz
; nm
++)
79 { // All Ordnums have to be correct!
80 GetMarkedObjectByIndex(nm
)->GetOrdNum();
83 SdrObjList
* pOL0
=NULL
;
84 sal_uIntPtr nNewPos
=0;
88 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
89 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
90 SdrObjList
* pOL
=pObj
->GetObjList();
93 nNewPos
=sal_uIntPtr(pOL
->GetObjCount()-1);
96 sal_uIntPtr nNowPos
=pObj
->GetOrdNumDirect();
97 const Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
98 sal_uIntPtr nCmpPos
=nNowPos
+1;
99 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
102 sal_uIntPtr nMaxPos
=pMaxObj
->GetOrdNum();
106 nNewPos
=nMaxPos
; // neither go faster...
108 nNewPos
=nNowPos
; // nor go in the other direction
111 while (nCmpPos
<nNewPos
&& !bEnd
)
113 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
116 OSL_FAIL("MovMarkedToTop(): Reference object not found.");
119 else if (pCmpObj
==pMaxObj
)
125 else if (rBR
.IsOver(pCmpObj
->GetCurrentBoundRect()))
135 if (nNowPos
!=nNewPos
)
138 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
140 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
141 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
150 MarkListHasChanged();
154 void SdrEditView::MovMarkedToBtm()
156 sal_uIntPtr nAnz
=GetMarkedObjectCount();
159 const bool bUndo
= IsUndoEnabled();
162 BegUndo(ImpGetResStr(STR_EditMovToBtm
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOBTM
);
166 for (nm
=0; nm
<nAnz
; nm
++)
167 { // All Ordnums have to be correct!
168 GetMarkedObjectByIndex(nm
)->GetOrdNum();
172 SdrObjList
* pOL0
=NULL
;
173 sal_uIntPtr nNewPos
=0;
174 for (nm
=0; nm
<nAnz
; nm
++)
176 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
177 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
178 SdrObjList
* pOL
=pObj
->GetObjList();
184 sal_uIntPtr nNowPos
=pObj
->GetOrdNumDirect();
185 const Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
186 sal_uIntPtr nCmpPos
=nNowPos
; if (nCmpPos
>0) nCmpPos
--;
187 SdrObject
* pMaxObj
=GetMaxToBtmObj(pObj
);
190 sal_uIntPtr nMinPos
=pMaxObj
->GetOrdNum()+1;
192 nNewPos
=nMinPos
; // neither go faster...
194 nNewPos
=nNowPos
; // nor go in the other direction
197 // nNewPos in this case is the "maximum" position
198 // the object may reach without going faster than the object before
199 // it (multiple selection).
200 while (nCmpPos
>nNewPos
&& !bEnd
)
202 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
205 OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
208 else if (pCmpObj
==pMaxObj
)
214 else if (rBR
.IsOver(pCmpObj
->GetCurrentBoundRect()))
224 if (nNowPos
!=nNewPos
)
227 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
229 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
230 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
239 MarkListHasChanged();
243 void SdrEditView::PutMarkedToTop()
245 PutMarkedInFrontOfObj(NULL
);
248 void SdrEditView::PutMarkedInFrontOfObj(const SdrObject
* pRefObj
)
250 sal_uIntPtr nAnz
=GetMarkedObjectCount();
253 const bool bUndo
= IsUndoEnabled();
255 BegUndo(ImpGetResStr(STR_EditPutToTop
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOTOP
);
261 // Make "in front of the object" work, even if the
262 // selected objects are already in front of the other object
263 sal_uIntPtr nRefMark
=TryToFindMarkedObject(pRefObj
);
265 if (nRefMark
!=CONTAINER_ENTRY_NOTFOUND
)
267 aRefMark
=*GetSdrMarkByIndex(nRefMark
);
268 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
271 if (nRefMark
!=CONTAINER_ENTRY_NOTFOUND
)
273 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
278 for (nm
=0; nm
<nAnz
; nm
++)
279 { // All Ordnums have to be correct!
280 GetMarkedObjectByIndex(nm
)->GetOrdNum();
283 SdrObjList
* pOL0
=NULL
;
284 sal_uIntPtr nNewPos
=0;
288 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
289 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
292 SdrObjList
* pOL
=pObj
->GetObjList();
295 nNewPos
=sal_uIntPtr(pOL
->GetObjCount()-1);
298 sal_uIntPtr nNowPos
=pObj
->GetOrdNumDirect();
299 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
302 sal_uIntPtr nMaxOrd
=pMaxObj
->GetOrdNum(); // sadly doesn't work any other way
306 nNewPos
=nMaxOrd
; // neither go faster...
308 nNewPos
=nNowPos
; // nor go into the other direction
312 if (pRefObj
->GetObjList()==pObj
->GetObjList())
314 sal_uIntPtr nMaxOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any other way
316 nNewPos
=nMaxOrd
; // neither go faster...
318 nNewPos
=nNowPos
; // nor go into the other direction
322 nNewPos
=nNowPos
; // different PageView, so don't change
325 if (nNowPos
!=nNewPos
)
328 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
330 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
331 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
334 } // if (pObj!=pRefObj)
335 } // for loop over all selected objects
341 MarkListHasChanged();
345 void SdrEditView::PutMarkedToBtm()
347 PutMarkedBehindObj(NULL
);
350 void SdrEditView::PutMarkedBehindObj(const SdrObject
* pRefObj
)
352 sal_uIntPtr nAnz
=GetMarkedObjectCount();
355 const bool bUndo
= IsUndoEnabled();
358 BegUndo(ImpGetResStr(STR_EditPutToBtm
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOBTM
);
363 // Make "behind the object" work, even if the
364 // selected objects are already behind the other object
365 sal_uIntPtr nRefMark
=TryToFindMarkedObject(pRefObj
);
367 if (nRefMark
!=CONTAINER_ENTRY_NOTFOUND
)
369 aRefMark
=*GetSdrMarkByIndex(nRefMark
);
370 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
373 if (nRefMark
!=CONTAINER_ENTRY_NOTFOUND
)
375 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
380 for (nm
=0; nm
<nAnz
; nm
++) { // All Ordnums have to be correct!
381 GetMarkedObjectByIndex(nm
)->GetOrdNum();
384 SdrObjList
* pOL0
=NULL
;
385 sal_uIntPtr nNewPos
=0;
386 for (nm
=0; nm
<nAnz
; nm
++) {
387 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
388 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
390 SdrObjList
* pOL
=pObj
->GetObjList();
395 sal_uIntPtr nNowPos
=pObj
->GetOrdNumDirect();
396 SdrObject
* pMinObj
=GetMaxToBtmObj(pObj
);
398 sal_uIntPtr nMinOrd
=pMinObj
->GetOrdNum()+1; // sadly doesn't work any differently
399 if (nNewPos
<nMinOrd
) nNewPos
=nMinOrd
; // neither go faster...
400 if (nNewPos
>nNowPos
) nNewPos
=nNowPos
; // nor go into the other direction
403 if (pRefObj
->GetObjList()==pObj
->GetObjList()) {
404 sal_uIntPtr nMinOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any differently
405 if (nNewPos
<nMinOrd
) nNewPos
=nMinOrd
; // neither go faster...
406 if (nNewPos
>nNowPos
) nNewPos
=nNowPos
; // nor go into the other direction
408 nNewPos
=nNowPos
; // different PageView, so don't change
411 if (nNowPos
!=nNewPos
) {
413 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
415 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
416 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
419 } // if (pObj!=pRefObj)
420 } // for loop over all selected objects
426 MarkListHasChanged();
430 void SdrEditView::ReverseOrderOfMarked()
433 sal_uIntPtr nMarkAnz
=GetMarkedObjectCount();
438 bool bUndo
= IsUndoEnabled();
440 BegUndo(ImpGetResStr(STR_EditRevOrder
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_REVORDER
);
444 // take into account selection across multiple PageViews
446 while (b
<nMarkAnz
&& GetSdrPageViewOfMarkedByIndex(b
) == GetSdrPageViewOfMarkedByIndex(a
)) b
++;
448 SdrObjList
* pOL
=GetSdrPageViewOfMarkedByIndex(a
)->GetObjList();
450 if (a
<c
) { // make sure OrdNums aren't dirty
451 GetMarkedObjectByIndex(a
)->GetOrdNum();
454 SdrObject
* pObj1
=GetMarkedObjectByIndex(a
);
455 SdrObject
* pObj2
=GetMarkedObjectByIndex(c
);
456 sal_uIntPtr nOrd1
=pObj1
->GetOrdNumDirect();
457 sal_uIntPtr nOrd2
=pObj2
->GetOrdNumDirect();
460 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1
,nOrd1
,nOrd2
));
461 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2
,nOrd2
-1,nOrd1
));
463 pOL
->SetObjectOrdNum(nOrd1
,nOrd2
);
464 // Obj 2 has moved forward by one position, so now nOrd2-1
465 pOL
->SetObjectOrdNum(nOrd2
-1,nOrd1
);
466 // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
471 } while (a
<nMarkAnz
);
477 MarkListHasChanged();
481 void SdrEditView::ImpCheckToTopBtmPossible()
483 sal_uIntPtr nAnz
=GetMarkedObjectCount();
487 { // special-casing for single selection
488 SdrObject
* pObj
=GetMarkedObjectByIndex(0);
489 SdrObjList
* pOL
=pObj
->GetObjList();
490 sal_uIntPtr nMax
=pOL
->GetObjCount();
492 sal_uIntPtr nObjNum
=pObj
->GetOrdNum();
493 SdrObject
* pRestrict
=GetMaxToTopObj(pObj
);
494 if (pRestrict
!=NULL
) {
495 sal_uIntPtr nRestrict
=pRestrict
->GetOrdNum();
496 if (nRestrict
<nMax
) nMax
=nRestrict
;
498 pRestrict
=GetMaxToBtmObj(pObj
);
499 if (pRestrict
!=NULL
) {
500 sal_uIntPtr nRestrict
=pRestrict
->GetOrdNum();
501 if (nRestrict
>nMin
) nMin
=nRestrict
;
503 bToTopPossible
=nObjNum
<sal_uIntPtr(nMax
-1);
504 bToBtmPossible
=nObjNum
>nMin
;
505 } else { // multiple selection
507 SdrObjList
* pOL0
=NULL
;
509 while (!bToBtmPossible
&& nm
<nAnz
) { // check 'send to background'
510 SdrObject
* pObj
=GetMarkedObjectByIndex(nm
);
511 SdrObjList
* pOL
=pObj
->GetObjList();
516 sal_uIntPtr nPos
=pObj
->GetOrdNum();
517 bToBtmPossible
=nPos
>sal_uIntPtr(nPos0
+1);
524 while (!bToTopPossible
&& nm
>0) { // check 'bring to front'
526 SdrObject
* pObj
=GetMarkedObjectByIndex(nm
);
527 SdrObjList
* pOL
=pObj
->GetObjList();
529 nPos0
=pOL
->GetObjCount();
532 sal_uIntPtr nPos
=pObj
->GetOrdNum();
533 bToTopPossible
=nPos
+1<sal_uIntPtr(nPos0
);
539 ////////////////////////////////////////////////////////////////////////////////////////////////////
541 ////////////////////////////////////////////////////////////////////////////////////////////////////
543 void SdrEditView::ImpCopyAttributes(const SdrObject
* pSource
, SdrObject
* pDest
) const
546 SdrObjList
* pOL
=pSource
->GetSubList();
547 if (pOL
!=NULL
&& !pSource
->Is3DObj()) { // get first non-group object from group
548 SdrObjListIter
aIter(*pOL
,IM_DEEPNOGROUPS
);
549 pSource
=aIter
.Next();
555 SfxItemSet
aSet(pMod
->GetItemPool(),
556 SDRATTR_START
, SDRATTR_NOTPERSIST_FIRST
-1,
557 SDRATTR_NOTPERSIST_LAST
+1, SDRATTR_END
,
558 EE_ITEMS_START
, EE_ITEMS_END
,
561 aSet
.Put(pSource
->GetMergedItemSet());
563 pDest
->ClearMergedItem();
564 pDest
->SetMergedItemSet(aSet
);
566 pDest
->NbcSetLayer(pSource
->GetLayer());
567 pDest
->NbcSetStyleSheet(pSource
->GetStyleSheet(), sal_True
);
571 sal_Bool
SdrEditView::ImpCanConvertForCombine1(const SdrObject
* pObj
) const
573 // new condition IsLine() to be able to combine simple Lines
574 sal_Bool
bIsLine(sal_False
);
576 const SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
,pObj
);
580 bIsLine
= pPath
->IsLine();
583 SdrObjTransformInfoRec aInfo
;
584 pObj
->TakeObjInfo(aInfo
);
586 return (aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
|| bIsLine
);
589 sal_Bool
SdrEditView::ImpCanConvertForCombine(const SdrObject
* pObj
) const
591 SdrObjList
* pOL
= pObj
->GetSubList();
593 if(pOL
&& !pObj
->Is3DObj())
595 SdrObjListIter
aIter(*pOL
, IM_DEEPNOGROUPS
);
597 while(aIter
.IsMore())
599 SdrObject
* pObj1
= aIter
.Next();
601 // all members of a group have to be convertible
602 if(!ImpCanConvertForCombine1(pObj1
))
610 if(!ImpCanConvertForCombine1(pObj
))
619 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon1(const SdrObject
* pObj
, sal_Bool bCombine
) const
621 basegfx::B2DPolyPolygon aRetval
;
622 SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pObj
);
624 if(bCombine
&& pPath
&& !pObj
->GetOutlinerParaObject())
626 aRetval
= pPath
->GetPathPoly();
630 SdrObject
* pConvObj
= pObj
->ConvertToPolyObj(bCombine
, sal_False
);
634 SdrObjList
* pOL
= pConvObj
->GetSubList();
638 SdrObjListIter
aIter(*pOL
, IM_DEEPNOGROUPS
);
640 while(aIter
.IsMore())
642 SdrObject
* pObj1
= aIter
.Next();
643 pPath
= PTR_CAST(SdrPathObj
, pObj1
);
647 aRetval
.append(pPath
->GetPathPoly());
653 pPath
= PTR_CAST(SdrPathObj
, pConvObj
);
657 aRetval
= pPath
->GetPathPoly();
661 SdrObject::Free( pConvObj
);
668 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon(const SdrObject
* pObj
, sal_Bool bCombine
) const
670 SdrObjList
* pOL
= pObj
->GetSubList();
672 if(pOL
&& !pObj
->Is3DObj())
674 basegfx::B2DPolyPolygon aRetval
;
675 SdrObjListIter
aIter(*pOL
, IM_DEEPNOGROUPS
);
677 while(aIter
.IsMore())
679 SdrObject
* pObj1
= aIter
.Next();
680 aRetval
.append(ImpGetPolyPolygon1(pObj1
, bCombine
));
687 return ImpGetPolyPolygon1(pObj
, bCombine
);
691 basegfx::B2DPolygon
SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon
& rPolyPolygon
) const
693 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
697 return basegfx::B2DPolygon();
699 else if(1L == nPolyCount
)
701 return rPolyPolygon
.getB2DPolygon(0L);
705 basegfx::B2DPolygon
aRetval(rPolyPolygon
.getB2DPolygon(0L));
707 for(sal_uInt32
a(1L); a
< nPolyCount
; a
++)
709 basegfx::B2DPolygon
aCandidate(rPolyPolygon
.getB2DPolygon(a
));
713 if(aCandidate
.count())
715 const basegfx::B2DPoint
aCA(aCandidate
.getB2DPoint(0L));
716 const basegfx::B2DPoint
aCB(aCandidate
.getB2DPoint(aCandidate
.count() - 1L));
717 const basegfx::B2DPoint
aRA(aRetval
.getB2DPoint(0L));
718 const basegfx::B2DPoint
aRB(aRetval
.getB2DPoint(aRetval
.count() - 1L));
720 const double fRACA(basegfx::B2DVector(aCA
- aRA
).getLength());
721 const double fRACB(basegfx::B2DVector(aCB
- aRA
).getLength());
722 const double fRBCA(basegfx::B2DVector(aCA
- aRB
).getLength());
723 const double fRBCB(basegfx::B2DVector(aCB
- aRB
).getLength());
725 const double fSmallestRA(fRACA
< fRACB
? fRACA
: fRACB
);
726 const double fSmallestRB(fRBCA
< fRBCB
? fRBCA
: fRBCB
);
728 if(fSmallestRA
< fSmallestRB
)
734 const double fSmallestCA(fRACA
< fRBCA
? fRACA
: fRBCA
);
735 const double fSmallestCB(fRACB
< fRBCB
? fRACB
: fRBCB
);
737 if(fSmallestCB
< fSmallestCA
)
743 // append candidate to retval
744 aRetval
.append(aCandidate
);
749 aRetval
= aCandidate
;
757 // for distribution dialog function
758 struct ImpDistributeEntry
765 typedef vector
< ImpDistributeEntry
*> ImpDistributeEntryList
;
767 void SdrEditView::DistributeMarkedObjects()
769 sal_uInt32
nMark(GetMarkedObjectCount());
773 SfxItemSet
aNewAttr(pMod
->GetItemPool());
775 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
778 AbstractSvxDistributeDialog
*pDlg
= pFact
->CreateSvxDistributeDialog(NULL
, aNewAttr
);
779 DBG_ASSERT(pDlg
, "Dialogdiet fail!");
781 sal_uInt16 nResult
= pDlg
->Execute();
783 if(nResult
== RET_OK
)
785 SvxDistributeHorizontal eHor
= pDlg
->GetDistributeHor();
786 SvxDistributeVertical eVer
= pDlg
->GetDistributeVer();
787 ImpDistributeEntryList aEntryList
;
788 ImpDistributeEntryList::iterator itEntryList
;
789 sal_uInt32 nFullLength
;
791 const bool bUndo
= IsUndoEnabled();
795 if(eHor
!= SvxDistributeHorizontalNone
)
797 // build sorted entry list
800 for( sal_uInt32 a
= 0; a
< nMark
; a
++ )
802 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
803 ImpDistributeEntry
* pNew
= new ImpDistributeEntry
;
805 pNew
->mpObj
= pMark
->GetMarkedSdrObj();
809 case SvxDistributeHorizontalLeft
:
811 pNew
->mnPos
= pNew
->mpObj
->GetSnapRect().Left();
814 case SvxDistributeHorizontalCenter
:
816 pNew
->mnPos
= (pNew
->mpObj
->GetSnapRect().Right() + pNew
->mpObj
->GetSnapRect().Left()) / 2;
819 case SvxDistributeHorizontalDistance
:
821 pNew
->mnLength
= pNew
->mpObj
->GetSnapRect().GetWidth() + 1;
822 nFullLength
+= pNew
->mnLength
;
823 pNew
->mnPos
= (pNew
->mpObj
->GetSnapRect().Right() + pNew
->mpObj
->GetSnapRect().Left()) / 2;
826 case SvxDistributeHorizontalRight
:
828 pNew
->mnPos
= pNew
->mpObj
->GetSnapRect().Right();
834 for ( itEntryList
= aEntryList
.begin();
835 itEntryList
< aEntryList
.end() && (*itEntryList
)->mnPos
< pNew
->mnPos
;
838 if ( itEntryList
< aEntryList
.end() )
839 aEntryList
.insert( itEntryList
, pNew
);
841 aEntryList
.push_back( pNew
);
844 if(eHor
== SvxDistributeHorizontalDistance
)
846 // calculate room in-between
847 sal_Int32 nWidth
= GetAllMarkedBoundRect().GetWidth() + 1;
848 double fStepWidth
= ((double)nWidth
- (double)nFullLength
) / (double)(aEntryList
.size() - 1);
849 double fStepStart
= (double)aEntryList
[ 0 ]->mnPos
;
850 fStepStart
+= fStepWidth
+ (double)((aEntryList
[ 0 ]->mnLength
+ aEntryList
[ 1 ]->mnLength
) / 2);
852 // move entries 1..n-1
853 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
855 ImpDistributeEntry
* pCurr
= aEntryList
[ i
];
856 ImpDistributeEntry
* pNext
= aEntryList
[ i
+ 1];
857 sal_Int32 nDelta
= (sal_Int32
)(fStepStart
+ 0.5) - pCurr
->mnPos
;
859 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr
->mpObj
));
860 pCurr
->mpObj
->Move(Size(nDelta
, 0));
861 fStepStart
+= fStepWidth
+ (double)((pCurr
->mnLength
+ pNext
->mnLength
) / 2);
866 // calculate distances
867 sal_Int32 nWidth
= aEntryList
[ aEntryList
.size() - 1 ]->mnPos
- aEntryList
[ 0 ]->mnPos
;
868 double fStepWidth
= (double)nWidth
/ (double)(aEntryList
.size() - 1);
869 double fStepStart
= (double)aEntryList
[ 0 ]->mnPos
;
870 fStepStart
+= fStepWidth
;
872 // move entries 1..n-1
873 for( size_t i
= 1 ; i
< aEntryList
.size()-1 ; ++i
)
875 ImpDistributeEntry
* pCurr
= aEntryList
[ i
];
876 sal_Int32 nDelta
= (sal_Int32
)(fStepStart
+ 0.5) - pCurr
->mnPos
;
878 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr
->mpObj
));
879 pCurr
->mpObj
->Move(Size(nDelta
, 0));
880 fStepStart
+= fStepWidth
;
885 for ( size_t i
= 0, n
= aEntryList
.size(); i
< n
; ++i
)
886 delete aEntryList
[ i
];
890 if(eVer
!= SvxDistributeVerticalNone
)
892 // build sorted entry list
895 for( sal_uInt32 a
= 0; a
< nMark
; a
++ )
897 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
898 ImpDistributeEntry
* pNew
= new ImpDistributeEntry
;
900 pNew
->mpObj
= pMark
->GetMarkedSdrObj();
904 case SvxDistributeVerticalTop
:
906 pNew
->mnPos
= pNew
->mpObj
->GetSnapRect().Top();
909 case SvxDistributeVerticalCenter
:
911 pNew
->mnPos
= (pNew
->mpObj
->GetSnapRect().Bottom() + pNew
->mpObj
->GetSnapRect().Top()) / 2;
914 case SvxDistributeVerticalDistance
:
916 pNew
->mnLength
= pNew
->mpObj
->GetSnapRect().GetHeight() + 1;
917 nFullLength
+= pNew
->mnLength
;
918 pNew
->mnPos
= (pNew
->mpObj
->GetSnapRect().Bottom() + pNew
->mpObj
->GetSnapRect().Top()) / 2;
921 case SvxDistributeVerticalBottom
:
923 pNew
->mnPos
= pNew
->mpObj
->GetSnapRect().Bottom();
929 for ( itEntryList
= aEntryList
.begin();
930 itEntryList
< aEntryList
.end() && (*itEntryList
)->mnPos
< pNew
->mnPos
;
933 if ( itEntryList
< aEntryList
.end() )
934 aEntryList
.insert( itEntryList
, pNew
);
936 aEntryList
.push_back( pNew
);
939 if(eVer
== SvxDistributeVerticalDistance
)
941 // calculate room in-between
942 sal_Int32 nHeight
= GetAllMarkedBoundRect().GetHeight() + 1;
943 double fStepWidth
= ((double)nHeight
- (double)nFullLength
) / (double)(aEntryList
.size() - 1);
944 double fStepStart
= (double)aEntryList
[ 0 ]->mnPos
;
945 fStepStart
+= fStepWidth
+ (double)((aEntryList
[ 0 ]->mnLength
+ aEntryList
[ 1 ]->mnLength
) / 2);
947 // move entries 1..n-1
948 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
950 ImpDistributeEntry
* pCurr
= aEntryList
[ i
];
951 ImpDistributeEntry
* pNext
= aEntryList
[ i
+ 1 ];
952 sal_Int32 nDelta
= (sal_Int32
)(fStepStart
+ 0.5) - pCurr
->mnPos
;
954 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr
->mpObj
));
955 pCurr
->mpObj
->Move(Size(0, nDelta
));
956 fStepStart
+= fStepWidth
+ (double)((pCurr
->mnLength
+ pNext
->mnLength
) / 2);
961 // calculate distances
962 sal_Int32 nHeight
= aEntryList
[ aEntryList
.size() - 1 ]->mnPos
- aEntryList
[ 0 ]->mnPos
;
963 double fStepWidth
= (double)nHeight
/ (double)(aEntryList
.size() - 1);
964 double fStepStart
= (double)aEntryList
[ 0 ]->mnPos
;
965 fStepStart
+= fStepWidth
;
967 // move entries 1..n-1
968 for(size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
970 ImpDistributeEntry
* pCurr
= aEntryList
[ i
];
971 sal_Int32 nDelta
= (sal_Int32
)(fStepStart
+ 0.5) - pCurr
->mnPos
;
973 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr
->mpObj
));
974 pCurr
->mpObj
->Move(Size(0, nDelta
));
975 fStepStart
+= fStepWidth
;
980 for ( size_t i
= 0, n
= aEntryList
.size(); i
< n
; ++i
)
981 delete aEntryList
[ i
];
985 // UNDO-Comment and end of UNDO
986 SetUndoComment(ImpGetResStr(STR_DistributeMarkedObjects
));
997 void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode
)
999 // #i73441# check content
1000 if(AreObjectsMarked())
1002 SdrMarkList aRemove
;
1003 SortMarkedObjects();
1005 const bool bUndo
= IsUndoEnabled();
1010 sal_uInt32 nInsPos
=0xFFFFFFFF;
1011 const SdrObject
* pAttrObj
= NULL
;
1012 basegfx::B2DPolyPolygon aMergePolyPolygonA
;
1013 basegfx::B2DPolyPolygon aMergePolyPolygonB
;
1015 SdrObjList
* pInsOL
= NULL
;
1016 SdrPageView
* pInsPV
= NULL
;
1017 bool bFirstObjectComplete(false);
1019 // make sure selected objects are contour objects
1020 // since now basegfx::tools::adaptiveSubdivide() is used, it is no longer
1021 // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
1022 // mechanisms. In a next step the polygon clipper will even be able to clip curves...
1023 // ConvertMarkedToPolyObj(sal_True);
1024 ConvertMarkedToPathObj(sal_True
);
1025 OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
1027 for(sal_uInt32 a
=0;a
<GetMarkedObjectCount();a
++)
1029 SdrMark
* pM
= GetSdrMarkByIndex(a
);
1030 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1032 if(ImpCanConvertForCombine(pObj
))
1037 nInsPos
= pObj
->GetOrdNum() + 1;
1038 pInsPV
= pM
->GetPageView();
1039 pInsOL
= pObj
->GetObjList();
1041 // #i76891# use single iteration from SJ here which works on SdrObjects and takes
1042 // groups into account by itself
1043 SdrObjListIter
aIter(*pObj
, IM_DEEPWITHGROUPS
);
1045 while(aIter
.IsMore())
1047 SdrObject
* pCandidate
= aIter
.Next();
1048 SdrPathObj
* pPathObj
= PTR_CAST(SdrPathObj
, pCandidate
);
1051 basegfx::B2DPolyPolygon
aTmpPoly(pPathObj
->GetPathPoly());
1053 // #i76891# unfortunately ConvertMarkedToPathObj has converted all
1054 // involved polygon data to curve segments, even if not necessary.
1055 // It is better to try to reduce to more simple polygons.
1056 aTmpPoly
= basegfx::tools::simplifyCurveSegments(aTmpPoly
);
1058 // for each part polygon as preparation, remove self-intersections
1059 // correct orientations and get rid of possible neutral polygons.
1060 aTmpPoly
= basegfx::tools::prepareForPolygonOperation(aTmpPoly
);
1062 if(!bFirstObjectComplete
)
1064 // #i111987# Also need to collect ORed source shape when more than
1065 // a single polygon is involved
1066 if(aMergePolyPolygonA
.count())
1068 aMergePolyPolygonA
= basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA
, aTmpPoly
);
1072 aMergePolyPolygonA
= aTmpPoly
;
1077 if(aMergePolyPolygonB
.count())
1079 // to topologically correctly collect the 2nd polygon
1080 // group it is necessary to OR the parts (each is seen as
1081 // XOR-FillRule polygon and they are drawn over each-other)
1082 aMergePolyPolygonB
= basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonB
, aTmpPoly
);
1086 aMergePolyPolygonB
= aTmpPoly
;
1092 // was there something added to the first polygon?
1093 if(!bFirstObjectComplete
&& aMergePolyPolygonA
.count())
1095 bFirstObjectComplete
= true;
1098 // move object to temporary delete list
1099 aRemove
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1105 case SDR_MERGE_MERGE
:
1107 // merge all contained parts (OR)
1108 static bool bTestXOR(false);
1111 aMergePolyPolygonA
= basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA
, aMergePolyPolygonB
);
1115 aMergePolyPolygonA
= basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA
, aMergePolyPolygonB
);
1119 case SDR_MERGE_SUBSTRACT
:
1121 // Substract B from A
1122 aMergePolyPolygonA
= basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA
, aMergePolyPolygonB
);
1125 case SDR_MERGE_INTERSECT
:
1128 aMergePolyPolygonA
= basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA
, aMergePolyPolygonB
);
1133 // #i73441# check insert list before taking actions
1136 SdrPathObj
* pPath
= new SdrPathObj(OBJ_PATHFILL
, aMergePolyPolygonA
);
1137 ImpCopyAttributes(pAttrObj
, pPath
);
1138 SdrInsertReason
aReason(SDRREASON_VIEWCALL
, pAttrObj
);
1139 pInsOL
->InsertObject(pPath
, nInsPos
, &aReason
);
1141 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1142 MarkObj(pPath
, pInsPV
, sal_False
, sal_True
);
1145 aRemove
.ForceSort();
1148 case SDR_MERGE_MERGE
:
1151 ImpGetResStr(STR_EditMergeMergePoly
),
1152 aRemove
.GetMarkDescription());
1155 case SDR_MERGE_SUBSTRACT
:
1158 ImpGetResStr(STR_EditMergeSubstractPoly
),
1159 aRemove
.GetMarkDescription());
1162 case SDR_MERGE_INTERSECT
:
1165 ImpGetResStr(STR_EditMergeIntersectPoly
),
1166 aRemove
.GetMarkDescription());
1170 DeleteMarkedList(aRemove
);
1177 void SdrEditView::CombineMarkedObjects(sal_Bool bNoPolyPoly
)
1179 // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1180 // create a 2nd Undo-action and Undo-Comment.
1182 bool bUndo
= IsUndoEnabled();
1184 // Undo-String will be set later
1186 BegUndo(String(), String(), bNoPolyPoly
? SDRREPFUNC_OBJ_COMBINE_ONEPOLY
: SDRREPFUNC_OBJ_COMBINE_POLYPOLY
);
1188 // #105899# First, guarantee that all objects are converted to polyobjects,
1189 // especially for SdrGrafObj with bitmap filling this is necessary to not
1190 // loose the bitmap filling.
1193 // ConvertMarkedToPolyObj was too strong here, it will loose quality and
1194 // information when curve objects are combined. This can be replaced by
1195 // using ConvertMarkedToPathObj without changing the previous fix.
1198 // Instead of simply passing sal_True as LineToArea, use bNoPolyPoly as info
1199 // if this command is a 'Combine' or a 'Connect' command. On Connect it's sal_True.
1200 // To not concert line segments with a set line width to polygons in that case,
1201 // use this info. Do not convert LineToArea on Connect commands.
1202 // ConvertMarkedToPathObj(!bNoPolyPoly);
1204 // This is used for Combine and Connect. In no case it is necessary to force
1205 // the content to curve, but it is also not good to force to polygons. Thus,
1206 // curve is the less information loosing one. Remember: This place is not
1208 // LineToArea is never necessary, both commands are able to take over the
1209 // set line style and to display it correctly. Thus, i will use a
1210 // ConvertMarkedToPathObj with a sal_False in any case. Only drawback is that
1211 // simple polygons will be changed to curves, but with no information loss.
1212 ConvertMarkedToPathObj(sal_False
/* bLineToArea */);
1214 // continue as before
1215 basegfx::B2DPolyPolygon aPolyPolygon
;
1216 SdrObjList
* pAktOL
= 0L;
1217 SdrMarkList aRemoveMerker
;
1219 SortMarkedObjects();
1220 sal_uInt32
nInsPos(0xFFFFFFFF);
1221 SdrObjList
* pInsOL
= 0L;
1222 SdrPageView
* pInsPV
= 0L;
1223 const sal_uInt32
nAnz(GetMarkedObjectCount());
1224 const SdrObject
* pAttrObj
= 0L;
1226 for(sal_uInt32
a(nAnz
); a
> 0L; )
1229 SdrMark
* pM
= GetSdrMarkByIndex(a
);
1230 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1231 SdrObjList
* pThisOL
= pObj
->GetObjList();
1233 if(pAktOL
!= pThisOL
)
1238 if(ImpCanConvertForCombine(pObj
))
1240 // remember objects to be able to copy attributes
1243 // unfortunately ConvertMarkedToPathObj has converted all
1244 // involved polygon data to curve segments, even if not necessary.
1245 // It is better to try to reduce to more simple polygons.
1246 basegfx::B2DPolyPolygon
aTmpPoly(basegfx::tools::simplifyCurveSegments(ImpGetPolyPolygon(pObj
, sal_True
)));
1247 aPolyPolygon
.insert(0L, aTmpPoly
);
1251 nInsPos
= pObj
->GetOrdNum() + 1L;
1252 pInsPV
= pM
->GetPageView();
1253 pInsOL
= pObj
->GetObjList();
1256 aRemoveMerker
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1262 basegfx::B2DPolygon
aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon
));
1263 aPolyPolygon
.clear();
1264 aPolyPolygon
.append(aCombinedPolygon
);
1267 const sal_uInt32
nPolyCount(aPolyPolygon
.count());
1271 SdrObjKind eKind
= OBJ_PATHFILL
;
1275 aPolyPolygon
.setClosed(true);
1279 // check for Polyline
1280 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0L));
1281 const sal_uInt32
nPointCount(aPolygon
.count());
1283 if(nPointCount
<= 2L)
1285 eKind
= OBJ_PATHLINE
;
1289 if(!aPolygon
.isClosed())
1291 const basegfx::B2DPoint
aPointA(aPolygon
.getB2DPoint(0L));
1292 const basegfx::B2DPoint
aPointB(aPolygon
.getB2DPoint(nPointCount
- 1L));
1293 const double fDistance(basegfx::B2DVector(aPointB
- aPointA
).getLength());
1294 const double fJoinTolerance(10.0);
1296 if(fDistance
< fJoinTolerance
)
1298 aPolyPolygon
.setClosed(true);
1302 eKind
= OBJ_PATHLINE
;
1308 SdrPathObj
* pPath
= new SdrPathObj(eKind
,aPolyPolygon
);
1310 // attributes of the lowest object
1311 ImpCopyAttributes(pAttrObj
, pPath
);
1313 // If LineStyle of pAttrObj is XLINE_NONE force to XLINE_SOLID to make visible.
1314 const XLineStyle eLineStyle
= ((const XLineStyleItem
&)pAttrObj
->GetMergedItem(XATTR_LINESTYLE
)).GetValue();
1315 const XFillStyle eFillStyle
= ((const XFillStyleItem
&)pAttrObj
->GetMergedItem(XATTR_FILLSTYLE
)).GetValue();
1317 // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1318 bool bIsClosedPathObj(pAttrObj
->ISA(SdrPathObj
) && ((SdrPathObj
*)pAttrObj
)->IsClosed());
1320 if(XLINE_NONE
== eLineStyle
&& (XFILL_NONE
== eFillStyle
|| !bIsClosedPathObj
))
1322 pPath
->SetMergedItem(XLineStyleItem(XLINE_SOLID
));
1325 SdrInsertReason
aReason(SDRREASON_VIEWCALL
,pAttrObj
);
1326 pInsOL
->InsertObject(pPath
,nInsPos
,&aReason
);
1328 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1330 // Here was a severe error: Without UnmarkAllObj, the new object was marked
1331 // additionally to the two ones which are deleted below. As long as those are
1332 // in the UNDO there is no problem, but as soon as they get deleted, the
1333 // MarkList will contain deleted objects -> GPF.
1334 UnmarkAllObj(pInsPV
);
1335 MarkObj(pPath
, pInsPV
, sal_False
, sal_True
);
1338 // build an UndoComment from the objects actually used
1339 aRemoveMerker
.ForceSort(); // important for remove (see below)
1341 SetUndoComment(ImpGetResStr(bNoPolyPoly
?STR_EditCombine_OnePoly
:STR_EditCombine_PolyPoly
),aRemoveMerker
.GetMarkDescription());
1343 // remove objects actually used from the list
1344 DeleteMarkedList(aRemoveMerker
);
1349 ////////////////////////////////////////////////////////////////////////////////////////////////////
1351 ////////////////////////////////////////////////////////////////////////////////////////////////////
1353 sal_Bool
SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon
& rPpolyPolygon
, sal_Bool bMakeLines
) const
1355 sal_Bool
bCan(sal_False
);
1356 const sal_uInt32
nPolygonCount(rPpolyPolygon
.count());
1358 if(nPolygonCount
>= 2L)
1360 // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1363 else if(bMakeLines
&& 1L == nPolygonCount
)
1365 // #i69172# ..or with at least 2 edges (curves or lines)
1366 const basegfx::B2DPolygon
aPolygon(rPpolyPolygon
.getB2DPolygon(0L));
1367 const sal_uInt32
nPointCount(aPolygon
.count());
1369 if(nPointCount
> 2L)
1378 sal_Bool
SdrEditView::ImpCanDismantle(const SdrObject
* pObj
, sal_Bool bMakeLines
) const
1380 bool bOtherObjs(false); // true=objects other than PathObj's existent
1381 bool bMin1PolyPoly(false); // sal_True=at least 1 PolyPolygon with more than one Polygon existent
1382 SdrObjList
* pOL
= pObj
->GetSubList();
1386 // group object -- check all members if they're PathObjs
1387 SdrObjListIter
aIter(*pOL
, IM_DEEPNOGROUPS
);
1389 while(aIter
.IsMore() && !bOtherObjs
)
1391 const SdrObject
* pObj1
= aIter
.Next();
1392 const SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pObj1
);
1396 if(ImpCanDismantle(pPath
->GetPathPoly(), bMakeLines
))
1398 bMin1PolyPoly
= true;
1401 SdrObjTransformInfoRec aInfo
;
1402 pObj1
->TakeObjInfo(aInfo
);
1404 if(!aInfo
.bCanConvToPath
)
1406 // happens e. g. in the case of FontWork
1418 const SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pObj
);
1419 const SdrObjCustomShape
* pCustomShape
= PTR_CAST(SdrObjCustomShape
, pObj
);
1424 if(ImpCanDismantle(pPath
->GetPathPoly(),bMakeLines
))
1426 bMin1PolyPoly
= true;
1429 SdrObjTransformInfoRec aInfo
;
1430 pObj
->TakeObjInfo(aInfo
);
1432 // new condition IsLine() to be able to break simple Lines
1433 if(!(aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
) && !pPath
->IsLine())
1435 // happens e. g. in the case of FontWork
1439 else if(pCustomShape
)
1443 // allow break command
1444 bMin1PolyPoly
= true;
1452 return bMin1PolyPoly
&& !bOtherObjs
;
1455 void SdrEditView::ImpDismantleOneObject(const SdrObject
* pObj
, SdrObjList
& rOL
, sal_uIntPtr
& rPos
, SdrPageView
* pPV
, sal_Bool bMakeLines
)
1457 const SdrPathObj
* pSrcPath
= PTR_CAST(SdrPathObj
, pObj
);
1458 const SdrObjCustomShape
* pCustomShape
= PTR_CAST(SdrObjCustomShape
, pObj
);
1460 const bool bUndo
= IsUndoEnabled();
1464 // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1465 SdrObject
* pLast
= 0; // to be able to apply OutlinerParaObject
1466 const basegfx::B2DPolyPolygon
& rPolyPolygon(pSrcPath
->GetPathPoly());
1467 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
1469 for(sal_uInt32
a(0); a
< nPolyCount
; a
++)
1471 const basegfx::B2DPolygon
& rCandidate(rPolyPolygon
.getB2DPolygon(a
));
1472 const sal_uInt32
nPointCount(rCandidate
.count());
1474 if(!bMakeLines
|| nPointCount
< 2)
1476 SdrPathObj
* pPath
= new SdrPathObj((SdrObjKind
)pSrcPath
->GetObjIdentifier(), basegfx::B2DPolyPolygon(rCandidate
));
1477 ImpCopyAttributes(pSrcPath
, pPath
);
1479 SdrInsertReason
aReason(SDRREASON_VIEWCALL
, pSrcPath
);
1480 rOL
.InsertObject(pPath
, rPos
, &aReason
);
1482 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath
, sal_True
));
1483 MarkObj(pPath
, pPV
, sal_False
, sal_True
);
1488 const sal_uInt32
nLoopCount(rCandidate
.isClosed() ? nPointCount
: nPointCount
- 1);
1490 for(sal_uInt32
b(0); b
< nLoopCount
; b
++)
1492 SdrObjKind
eKind(OBJ_PLIN
);
1493 basegfx::B2DPolygon aNewPolygon
;
1494 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
1496 aNewPolygon
.append(rCandidate
.getB2DPoint(b
));
1498 if(rCandidate
.areControlPointsUsed())
1500 aNewPolygon
.appendBezierSegment(
1501 rCandidate
.getNextControlPoint(b
),
1502 rCandidate
.getPrevControlPoint(nNextIndex
),
1503 rCandidate
.getB2DPoint(nNextIndex
));
1504 eKind
= OBJ_PATHLINE
;
1508 aNewPolygon
.append(rCandidate
.getB2DPoint(nNextIndex
));
1511 SdrPathObj
* pPath
= new SdrPathObj(eKind
, basegfx::B2DPolyPolygon(aNewPolygon
));
1512 ImpCopyAttributes(pSrcPath
, pPath
);
1514 SdrInsertReason
aReason(SDRREASON_VIEWCALL
, pSrcPath
);
1515 rOL
.InsertObject(pPath
, rPos
, &aReason
);
1517 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath
, sal_True
));
1518 MarkObj(pPath
, pPV
, sal_False
, sal_True
);
1524 if(pLast
&& pSrcPath
->GetOutlinerParaObject())
1526 pLast
->SetOutlinerParaObject(new OutlinerParaObject(*pSrcPath
->GetOutlinerParaObject()));
1529 else if(pCustomShape
)
1533 // break up custom shape
1534 const SdrObject
* pReplacement
= pCustomShape
->GetSdrObjectFromCustomShape();
1538 SdrObject
* pCandidate
= pReplacement
->Clone();
1539 DBG_ASSERT(pCandidate
, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1540 pCandidate
->SetModel(pCustomShape
->GetModel());
1542 if(((SdrShadowItem
&)pCustomShape
->GetMergedItem(SDRATTR_SHADOW
)).GetValue())
1544 if(pReplacement
->ISA(SdrObjGroup
))
1546 pCandidate
->SetMergedItem(SdrShadowItem(sal_True
));
1550 SdrInsertReason
aReason(SDRREASON_VIEWCALL
, pCustomShape
);
1551 rOL
.InsertObject(pCandidate
, rPos
, &aReason
);
1553 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate
, true));
1554 MarkObj(pCandidate
, pPV
, sal_False
, sal_True
);
1556 if(pCustomShape
->HasText() && !pCustomShape
->IsTextPath())
1558 // #i37011# also create a text object and add at rPos + 1
1559 SdrTextObj
* pTextObj
= (SdrTextObj
*)SdrObjFactory::MakeNewObject(
1560 pCustomShape
->GetObjInventor(), OBJ_TEXT
, 0L, pCustomShape
->GetModel());
1562 // Copy text content
1563 OutlinerParaObject
* pParaObj
= pCustomShape
->GetOutlinerParaObject();
1566 pTextObj
->NbcSetOutlinerParaObject(new OutlinerParaObject(*pParaObj
));
1569 // copy all attributes
1570 SfxItemSet
aTargetItemSet(pCustomShape
->GetMergedItemSet());
1572 // clear fill and line style
1573 aTargetItemSet
.Put(XLineStyleItem(XLINE_NONE
));
1574 aTargetItemSet
.Put(XFillStyleItem(XFILL_NONE
));
1576 // get the text bounds and set at text object
1577 Rectangle aTextBounds
= pCustomShape
->GetSnapRect();
1578 if(pCustomShape
->GetTextBounds(aTextBounds
))
1580 pTextObj
->SetSnapRect(aTextBounds
);
1583 // if rotated, copy GeoStat, too.
1584 const GeoStat
& rSourceGeo
= pCustomShape
->GetGeoStat();
1585 if(rSourceGeo
.nDrehWink
)
1587 pTextObj
->NbcRotate(
1588 pCustomShape
->GetSnapRect().Center(), rSourceGeo
.nDrehWink
,
1589 rSourceGeo
.nSin
, rSourceGeo
.nCos
);
1592 // set modified ItemSet at text object
1593 pTextObj
->SetMergedItemSet(aTargetItemSet
);
1596 rOL
.InsertObject(pTextObj
, rPos
+ 1, &aReason
);
1598 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj
, true));
1599 MarkObj(pTextObj
, pPV
, sal_False
, sal_True
);
1606 void SdrEditView::DismantleMarkedObjects(sal_Bool bMakeLines
)
1608 // temporary MarkList
1609 SdrMarkList aRemoveMerker
;
1611 SortMarkedObjects();
1613 const bool bUndo
= IsUndoEnabled();
1617 // comment is constructed later
1618 BegUndo(String(), String(),
1619 bMakeLines
? SDRREPFUNC_OBJ_DISMANTLE_LINES
: SDRREPFUNC_OBJ_DISMANTLE_POLYS
);
1623 sal_uIntPtr nAnz
=GetMarkedObjectCount();
1624 SdrObjList
* pOL0
=NULL
;
1625 for (nm
=nAnz
; nm
>0;) {
1627 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1628 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1629 SdrPageView
* pPV
=pM
->GetPageView();
1630 SdrObjList
* pOL
=pObj
->GetObjList();
1631 if (pOL
!=pOL0
) { pOL0
=pOL
; pObj
->GetOrdNum(); } // make sure OrdNums are correct!
1632 if (ImpCanDismantle(pObj
,bMakeLines
)) {
1633 aRemoveMerker
.InsertEntry(SdrMark(pObj
,pM
->GetPageView()));
1634 sal_uIntPtr nPos0
=pObj
->GetOrdNumDirect();
1635 sal_uIntPtr nPos
=nPos0
+1;
1636 SdrObjList
* pSubList
=pObj
->GetSubList();
1637 if (pSubList
!=NULL
&& !pObj
->Is3DObj()) {
1638 SdrObjListIter
aIter(*pSubList
,IM_DEEPNOGROUPS
);
1639 while (aIter
.IsMore()) {
1640 const SdrObject
* pObj1
=aIter
.Next();
1641 ImpDismantleOneObject(pObj1
,*pOL
,nPos
,pPV
,bMakeLines
);
1644 ImpDismantleOneObject(pObj
,*pOL
,nPos
,pPV
,bMakeLines
);
1647 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
,sal_True
));
1648 pOL
->RemoveObject(nPos0
);
1651 SdrObject::Free(pObj
);
1657 // construct UndoComment from objects actually used
1658 SetUndoComment(ImpGetResStr(bMakeLines
?STR_EditDismantle_Lines
:STR_EditDismantle_Polys
),aRemoveMerker
.GetMarkDescription());
1659 // remove objects actually used from the list
1664 ////////////////////////////////////////////////////////////////////////////////////////////////////
1666 ////////////////////////////////////////////////////////////////////////////////////////////////////
1668 void SdrEditView::GroupMarked(const SdrObject
* pUserGrp
)
1670 if (AreObjectsMarked())
1672 SortMarkedObjects();
1674 const bool bUndo
= IsUndoEnabled();
1677 BegUndo(ImpGetResStr(STR_EditGroup
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_GROUP
);
1679 const sal_uIntPtr nAnz
= GetMarkedObjectCount();
1680 for(sal_uIntPtr nm
= nAnz
; nm
>0; )
1682 // add UndoActions for all affected objects
1684 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1685 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1686 std::vector
< SdrUndoAction
* > vConnectorUndoActions( CreateConnectorUndo( *pObj
) );
1687 AddUndoActions( vConnectorUndoActions
);
1688 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj
));
1692 SdrMarkList aNewMark
;
1693 SdrPageView
* pPV
= GetSdrPageView();
1697 SdrObjList
* pAktLst
=pPV
->GetObjList();
1698 SdrObjList
* pSrcLst
=pAktLst
;
1699 SdrObjList
* pSrcLst0
=pSrcLst
;
1700 SdrPage
* pPage
=pPV
->GetPage();
1701 // make sure OrdNums are correct
1702 if (pSrcLst
->IsObjOrdNumsDirty())
1703 pSrcLst
->RecalcObjOrdNums();
1704 SdrObject
* pGrp
=NULL
;
1705 SdrObject
* pRefObj
=NULL
; // reference for InsertReason (-> anchors in Writer)
1706 SdrObject
* pRefObj1
=NULL
; // reference for InsertReason (-> anchors in Writer)
1707 SdrObjList
* pDstLst
=NULL
;
1708 // if all selected objects come from foreign object lists.
1709 // the group object is the last one in the list.
1710 sal_uIntPtr nInsPos
=pSrcLst
->GetObjCount();
1711 bool bNeedInsPos
=true;
1712 for (sal_uIntPtr nm
=GetMarkedObjectCount(); nm
>0;)
1715 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1716 if (pM
->GetPageView()==pPV
)
1721 pGrp
=pUserGrp
->Clone();
1723 pGrp
=new SdrObjGroup
;
1724 pDstLst
=pGrp
->GetSubList();
1725 DBG_ASSERT(pDstLst
!=NULL
,"Alleged group object doesn't return object list.");
1727 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1728 pSrcLst
=pObj
->GetObjList();
1729 if (pSrcLst
!=pSrcLst0
)
1731 if (pSrcLst
->IsObjOrdNumsDirty())
1732 pSrcLst
->RecalcObjOrdNums();
1734 bool bForeignList
=pSrcLst
!=pAktLst
;
1735 bool bGrouped
=pSrcLst
!=pPage
;
1736 if (!bForeignList
&& bNeedInsPos
)
1738 nInsPos
=pObj
->GetOrdNum(); // this way, all ObjOrdNum of the page are set
1742 pSrcLst
->RemoveObject(pObj
->GetOrdNumDirect());
1744 nInsPos
--; // correct InsertPos
1745 SdrInsertReason
aReason(SDRREASON_VIEWCALL
);
1746 pDstLst
->InsertObject(pObj
,0,&aReason
);
1747 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1749 pRefObj1
=pObj
; // the topmost visible object
1753 pRefObj
=pObj
; // the topmost visible non-group object
1762 aNewMark
.InsertEntry(SdrMark(pGrp
,pPV
));
1763 sal_uIntPtr nAnz
=pDstLst
->GetObjCount();
1764 SdrInsertReason
aReason(SDRREASON_VIEWCALL
,pRefObj
);
1765 pAktLst
->InsertObject(pGrp
,nInsPos
,&aReason
);
1768 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp
,true)); // no recalculation!
1769 for (sal_uIntPtr no
=0; no
<nAnz
; no
++)
1771 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst
->GetObj(no
)));
1776 GetMarkedObjectListWriteAccess().Merge(aNewMark
);
1777 MarkListHasChanged();
1784 ////////////////////////////////////////////////////////////////////////////////////////////////////
1786 ////////////////////////////////////////////////////////////////////////////////////////////////////
1788 void SdrEditView::UnGroupMarked()
1790 SdrMarkList aNewMark
;
1792 const bool bUndo
= IsUndoEnabled();
1794 BegUndo(String(), String(), SDRREPFUNC_OBJ_UNGROUP
);
1796 sal_uIntPtr nCount
=0;
1800 for (sal_uIntPtr nm
=GetMarkedObjectCount(); nm
>0;) {
1802 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1803 SdrObject
* pGrp
=pM
->GetMarkedSdrObj();
1804 SdrObjList
* pSrcLst
=pGrp
->GetSubList();
1805 if (pSrcLst
!=NULL
) {
1808 pGrp
->TakeObjNameSingul(aName
); // retrieve name of group
1809 pGrp
->TakeObjNamePlural(aName1
); // retrieve name of group
1812 if (nCount
==2) aName
=aName1
; // set plural name
1815 pGrp
->TakeObjNamePlural(aStr
); // retrieve name of group
1817 if(!aStr
.Equals(aName
))
1821 sal_uIntPtr nDstCnt
=pGrp
->GetOrdNum();
1822 SdrObjList
* pDstLst
=pM
->GetPageView()->GetObjList();
1824 // FIRST move contained objects to parent of group, so that
1825 // the contained objects are NOT migrated to the UNDO-ItemPool
1826 // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1827 sal_uIntPtr nAnz
=pSrcLst
->GetObjCount();
1832 for (no
=nAnz
; no
>0;)
1835 SdrObject
* pObj
=pSrcLst
->GetObj(no
);
1836 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj
));
1839 for (no
=0; no
<nAnz
; no
++)
1841 SdrObject
* pObj
=pSrcLst
->RemoveObject(0);
1842 SdrInsertReason
aReason(SDRREASON_VIEWCALL
,pGrp
);
1843 pDstLst
->InsertObject(pObj
,nDstCnt
,&aReason
);
1845 AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj
,true));
1847 // No SortCheck when inserting into MarkList, because that would
1848 // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
1849 aNewMark
.InsertEntry(SdrMark(pObj
,pM
->GetPageView()),sal_False
);
1854 // Now it is safe to add the delete-UNDO which triggers the
1855 // MigrateItemPool now only for itself, not for the sub-objects.
1856 // nDstCnt is right, because previous inserts move group
1857 // object deeper and increase nDstCnt.
1858 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp
));
1860 pDstLst
->RemoveObject(nDstCnt
);
1863 SdrObject::Free(pGrp
);
1865 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1871 aName
=ImpGetResStr(STR_ObjNamePluralGRUP
); // Use the term "Group Objects," if different objects are grouped.
1872 SetUndoComment(ImpGetResStr(STR_EditUngroup
),aName
);
1880 GetMarkedObjectListWriteAccess().Merge(aNewMark
,sal_True
); // Because of the sorting above, aNewMark is reversed
1881 MarkListHasChanged();
1885 ////////////////////////////////////////////////////////////////////////////////////////////////////
1887 ////////////////////////////////////////////////////////////////////////////////////////////////////
1889 SdrObject
* SdrEditView::ImpConvertOneObj(SdrObject
* pObj
, sal_Bool bPath
, sal_Bool bLineToArea
)
1891 SdrObject
* pNewObj
= pObj
->ConvertToPolyObj(bPath
, bLineToArea
);
1894 SdrObjList
* pOL
=pObj
->GetObjList();
1895 DBG_ASSERT(pOL
!=NULL
,"ConvertTo: Object doesn't return object list");
1898 const bool bUndo
= IsUndoEnabled();
1900 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj
,*pNewObj
));
1902 pOL
->ReplaceObject(pNewObj
,pObj
->GetOrdNum());
1905 SdrObject::Free(pObj
);
1911 void SdrEditView::ImpConvertTo(sal_Bool bPath
, sal_Bool bLineToArea
)
1914 if (AreObjectsMarked()) {
1915 sal_uIntPtr nMarkAnz
=GetMarkedObjectCount();
1916 sal_uInt16 nDscrID
=0;
1920 nDscrID
= STR_EditConvToContour
;
1922 nDscrID
= STR_EditConvToContours
;
1924 BegUndo(ImpGetResStr(nDscrID
), GetDescriptionOfMarkedObjects());
1929 if (nMarkAnz
==1) nDscrID
=STR_EditConvToCurve
;
1930 else nDscrID
=STR_EditConvToCurves
;
1931 BegUndo(ImpGetResStr(nDscrID
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPATH
);
1933 if (nMarkAnz
==1) nDscrID
=STR_EditConvToPoly
;
1934 else nDscrID
=STR_EditConvToPolys
;
1935 BegUndo(ImpGetResStr(nDscrID
),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPOLY
);
1938 for (sal_uIntPtr nm
=nMarkAnz
; nm
>0;) {
1940 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1941 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1942 SdrPageView
* pPV
=pM
->GetPageView();
1943 if (pObj
->IsGroupObject() && !pObj
->Is3DObj()) {
1944 SdrObject
* pGrp
=pObj
;
1945 SdrObjListIter
aIter(*pGrp
,IM_DEEPNOGROUPS
);
1946 while (aIter
.IsMore()) {
1948 ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
1951 SdrObject
* pNewObj
=ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
1952 if (pNewObj
!=NULL
) {
1954 GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj
,pPV
),nm
);
1959 if (bMrkChg
) AdjustMarkHdl();
1960 if (bMrkChg
) MarkListHasChanged();
1964 void SdrEditView::ConvertMarkedToPathObj(sal_Bool bLineToArea
)
1966 ImpConvertTo(sal_True
, bLineToArea
);
1969 void SdrEditView::ConvertMarkedToPolyObj(sal_Bool bLineToArea
)
1971 ImpConvertTo(sal_False
, bLineToArea
);
1974 ////////////////////////////////////////////////////////////////////////////////////////////////////
1976 ////////////////////////////////////////////////////////////////////////////////////////////////////
1978 void SdrEditView::DoImportMarkedMtf(SvdProgressInfo
*pProgrInfo
)
1980 const bool bUndo
= IsUndoEnabled();
1983 BegUndo(String(), String(), SDRREPFUNC_OBJ_IMPORTMTF
);
1985 SortMarkedObjects();
1986 SdrMarkList aForTheDescription
;
1987 SdrMarkList aNewMarked
;
1988 sal_uIntPtr nAnz
=GetMarkedObjectCount();
1990 for (sal_uIntPtr nm
=nAnz
; nm
>0;)
1991 { // create Undo objects for all new objects
1992 // check for cancellation between the metafiles
1993 if( pProgrInfo
!= NULL
)
1995 pProgrInfo
->SetNextObject();
1996 if(!pProgrInfo
->ReportActions(0))
2001 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2002 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2003 SdrPageView
* pPV
=pM
->GetPageView();
2004 SdrObjList
* pOL
=pObj
->GetObjList();
2005 sal_uIntPtr nInsPos
=pObj
->GetOrdNum()+1;
2006 SdrGrafObj
* pGraf
=PTR_CAST(SdrGrafObj
,pObj
);
2007 SdrOle2Obj
* pOle2
=PTR_CAST(SdrOle2Obj
,pObj
);
2008 sal_uIntPtr nInsAnz
=0;
2009 Rectangle aLogicRect
;
2011 if(pGraf
&& (pGraf
->HasGDIMetaFile() || pGraf
->isEmbeddedSvg()))
2013 GDIMetaFile aMetaFile
;
2015 if(pGraf
->HasGDIMetaFile())
2017 aMetaFile
= pGraf
->GetTransformedGraphic(SDRGRAFOBJ_TRANSFORMATTR_COLOR
|SDRGRAFOBJ_TRANSFORMATTR_MIRROR
).GetGDIMetaFile();
2019 else if(pGraf
->isEmbeddedSvg())
2021 aMetaFile
= pGraf
->getMetafileFromEmbeddedSvg();
2024 if(aMetaFile
.GetActionSize())
2026 aLogicRect
= pGraf
->GetLogicRect();
2027 ImpSdrGDIMetaFileImport
aFilter(*pMod
, pObj
->GetLayer(), aLogicRect
);
2028 nInsAnz
= aFilter
.DoImport(aMetaFile
, *pOL
, nInsPos
, pProgrInfo
);
2031 if ( pOle2
!=NULL
&& pOle2
->GetGraphic() )
2033 aLogicRect
= pOle2
->GetLogicRect();
2034 ImpSdrGDIMetaFileImport
aFilter(*pMod
, pObj
->GetLayer(), aLogicRect
);
2035 nInsAnz
= aFilter
.DoImport(pOle2
->GetGraphic()->GetGDIMetaFile(), *pOL
, nInsPos
, pProgrInfo
);
2040 GeoStat
aGeoStat(pGraf
? pGraf
->GetGeoStat() : pOle2
->GetGeoStat());
2041 sal_uIntPtr nObj
=nInsPos
;
2043 if(aGeoStat
.nShearWink
)
2045 aGeoStat
.RecalcTan();
2048 if(aGeoStat
.nDrehWink
)
2050 aGeoStat
.RecalcSinCos();
2053 for (sal_uIntPtr i
=0; i
<nInsAnz
; i
++)
2056 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL
->GetObj(nObj
)));
2058 // update new MarkList
2059 SdrObject
* pCandidate
= pOL
->GetObj(nObj
);
2061 // apply original transformation
2062 if(aGeoStat
.nShearWink
)
2064 pCandidate
->NbcShear(aLogicRect
.TopLeft(), aGeoStat
.nShearWink
, aGeoStat
.nTan
, false);
2067 if(aGeoStat
.nDrehWink
)
2069 pCandidate
->NbcRotate(aLogicRect
.TopLeft(), aGeoStat
.nDrehWink
, aGeoStat
.nSin
, aGeoStat
.nCos
);
2072 SdrMark
aNewMark(pCandidate
, pPV
);
2073 aNewMarked
.InsertEntry(aNewMark
);
2077 aForTheDescription
.InsertEntry(*pM
);
2080 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
));
2082 // remove object from selection and delete
2083 GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj
));
2084 pOL
->RemoveObject(nInsPos
-1);
2087 SdrObject::Free(pObj
);
2091 if(aNewMarked
.GetMarkCount())
2093 // create new selection
2094 for(sal_uIntPtr
a(0); a
< aNewMarked
.GetMarkCount(); a
++)
2096 GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked
.GetMark(a
));
2099 SortMarkedObjects();
2104 SetUndoComment(ImpGetResStr(STR_EditImportMtf
),aForTheDescription
.GetMarkDescription());
2109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */