/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
rMarkList.ForceSort(); for (size_t nm=0; nm<nCount; ++nm)
{ // All Ordnums have to be correct!
rMarkList.GetMark(nm)->GetMarkedSdrObj()->GetOrdNum();
}
bool bChg=false;
SdrObjList* pOL0=nullptr;
size_t nNewPos=0; for (size_t nm=0; nm<nCount; ++nm)
{
SdrMark* pM=rMarkList.GetMark(nm);
SdrObject* pObj=pM->GetMarkedSdrObj();
SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject(); if (pOL!=pOL0)
{
nNewPos=0;
pOL0=pOL;
} const size_t nNowPos = pObj->GetOrdNumDirect(); const tools::Rectangle& rBR=pObj->GetCurrentBoundRect();
size_t nCmpPos = nNowPos; if (nCmpPos>0)
--nCmpPos;
SdrObject* pMaxObj=GetMaxToBtmObj(pObj); if (pMaxObj!=nullptr)
{ const size_t nMinPos=pMaxObj->GetOrdNum()+1; if (nNewPos<nMinPos)
nNewPos=nMinPos; // neither go faster... if (nNewPos>nNowPos)
nNewPos=nNowPos; // nor go in the other direction
} bool bEnd=false; // nNewPos in this case is the "maximum" position // the object may reach without going faster than the object before // it (multiple selection). while (nCmpPos>nNewPos && !bEnd)
{
assert(pOL);
SdrObject* pCmpObj=pOL->GetObj(nCmpPos); if (pCmpObj==nullptr)
{
OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
bEnd=true;
} elseif (pCmpObj==pMaxObj)
{
nNewPos=nCmpPos;
nNewPos++;
bEnd=true;
} elseif (rBR.Overlaps(pCmpObj->GetCurrentBoundRect()))
{
nNewPos=nCmpPos;
bEnd=true;
} else
{
nCmpPos--;
}
} if (nNowPos!=nNewPos)
{
bChg=true;
pOL->SetObjectOrdNum(nNowPos,nNewPos); if( bUndo )
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos++;
}
if (pRefObj!=nullptr)
{ // Make "in front of the object" work, even if the // selected objects are already in front of the other object const size_t nRefMark=rMarkList.FindObject(pRefObj);
SdrMark aRefMark; if (nRefMark!=SAL_MAX_SIZE)
{
aRefMark=*rMarkList.GetMark(nRefMark);
GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
}
PutMarkedToBtm(); if (nRefMark!=SAL_MAX_SIZE)
{
GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
rMarkList.ForceSort();
}
} for (size_t nm=0; nm<nCount; ++nm)
{ // All Ordnums have to be correct!
rMarkList.GetMark(nm)->GetMarkedSdrObj()->GetOrdNum();
} bool bChg=false;
SdrObjList* pOL0=nullptr;
size_t nNewPos=0; for (size_t nm=nCount; nm>0;)
{
--nm;
SdrMark* pM=rMarkList.GetMark(nm);
SdrObject* pObj=pM->GetMarkedSdrObj(); if (pObj!=pRefObj)
{
SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject(); if (pOL!=pOL0)
{
nNewPos=pOL->GetObjCount()-1;
pOL0=pOL;
} const size_t nNowPos=pObj->GetOrdNumDirect();
SdrObject* pMaxObj=GetMaxToTopObj(pObj); if (pMaxObj!=nullptr)
{
size_t nMaxOrd=pMaxObj->GetOrdNum(); // sadly doesn't work any other way if (nMaxOrd>0)
nMaxOrd--; if (nNewPos>nMaxOrd)
nNewPos=nMaxOrd; // neither go faster... if (nNewPos<nNowPos)
nNewPos=nNowPos; // nor go into the other direction
} if (pRefObj!=nullptr)
{ if (pRefObj->getParentSdrObjListFromSdrObject()==pObj->getParentSdrObjListFromSdrObject())
{ const size_t nMaxOrd=pRefObj->GetOrdNum(); // sadly doesn't work any other way if (nNewPos>nMaxOrd)
nNewPos=nMaxOrd; // neither go faster... if (nNewPos<nNowPos)
nNewPos=nNowPos; // nor go into the other direction
} else
{
nNewPos=nNowPos; // different PageView, so don't change
}
} if (nNowPos!=nNewPos)
{
bChg=true;
pOL->SetObjectOrdNum(nNowPos,nNewPos); if( bUndo )
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos--;
} // if (pObj!=pRefObj)
} // for loop over all selected objects
rMarkList.ForceSort(); if (pRefObj!=nullptr)
{ // Make "behind the object" work, even if the // selected objects are already behind the other object const size_t nRefMark=rMarkList.FindObject(pRefObj);
SdrMark aRefMark; if (nRefMark!=SAL_MAX_SIZE)
{
aRefMark=*rMarkList.GetMark(nRefMark);
GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
}
PutMarkedToTop(); if (nRefMark!=SAL_MAX_SIZE)
{
GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
rMarkList.ForceSort();
}
} for (size_t nm=0; nm<nCount; ++nm) { // All Ordnums have to be correct!
rMarkList.GetMark(nm)->GetMarkedSdrObj()->GetOrdNum();
} bool bChg=false;
SdrObjList* pOL0=nullptr;
size_t nNewPos=0; for (size_t nm=0; nm<nCount; ++nm) {
SdrMark* pM=rMarkList.GetMark(nm);
SdrObject* pObj=pM->GetMarkedSdrObj(); if (pObj!=pRefObj) {
SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject(); if (pOL!=pOL0) {
nNewPos=0;
pOL0=pOL;
} const size_t nNowPos=pObj->GetOrdNumDirect();
SdrObject* pMinObj=GetMaxToBtmObj(pObj); if (pMinObj!=nullptr) { const size_t nMinOrd=pMinObj->GetOrdNum()+1; // sadly doesn't work any differently if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster... if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
} if (pRefObj!=nullptr) { if (pRefObj->getParentSdrObjListFromSdrObject()==pObj->getParentSdrObjListFromSdrObject()) { const size_t nMinOrd=pRefObj->GetOrdNum(); // sadly doesn't work any differently if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster... if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
} else {
nNewPos=nNowPos; // different PageView, so don't change
}
} if (nNowPos!=nNewPos) {
bChg=true;
pOL->SetObjectOrdNum(nNowPos,nNewPos); if( bUndo )
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
ObjOrderChanged(pObj,nNowPos,nNewPos);
}
nNewPos++;
} // if (pObj!=pRefObj)
} // for loop over all selected objects
size_t a=0; do { // take into account selection across multiple PageViews
size_t b=a+1; while (b<nMarkCount && rMarkList.GetMark(b)->GetPageView() == rMarkList.GetMark(a)->GetPageView()) ++b;
--b;
SdrObjList* pOL=rMarkList.GetMark(a)->GetPageView()->GetObjList();
size_t c=b; if (a<c) { // make sure OrdNums aren't dirty
rMarkList.GetMark(a)->GetMarkedSdrObj()->GetOrdNum();
} while (a<c) {
SdrObject* pObj1=rMarkList.GetMark(a)->GetMarkedSdrObj();
SdrObject* pObj2=rMarkList.GetMark(c)->GetMarkedSdrObj(); const size_t nOrd1=pObj1->GetOrdNumDirect(); const size_t nOrd2=pObj2->GetOrdNumDirect(); if( bUndo )
{
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1,nOrd1,nOrd2));
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2,nOrd2-1,nOrd1));
}
pOL->SetObjectOrdNum(nOrd1,nOrd2); // Obj 2 has moved forward by one position, so now nOrd2-1
pOL->SetObjectOrdNum(nOrd2-1,nOrd1); // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
++a;
--c;
bChg=true;
}
a=b+1;
} while (a<nMarkCount);
if(bUndo)
EndUndo();
if(bChg)
MarkListHasChanged();
}
void SdrEditView::ImpCheckToTopBtmPossible()
{ const SdrMarkList& rMarkList = GetMarkedObjectList(); const size_t nCount=rMarkList.GetMarkCount(); if (nCount==0) return; if (nCount==1)
{ // special-casing for single selection
SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
SAL_WARN_IF(!pOL, "svx", "Object somehow has no ObjList");
size_t nMax = pOL ? pOL->GetObjCount() : 0;
size_t nMin = 0; const size_t nObjNum=pObj->GetOrdNum();
SdrObject* pRestrict=GetMaxToTopObj(pObj); if (pRestrict!=nullptr) { const size_t nRestrict=pRestrict->GetOrdNum(); if (nRestrict<nMax) nMax=nRestrict;
}
pRestrict=GetMaxToBtmObj(pObj); if (pRestrict!=nullptr) { const size_t nRestrict=pRestrict->GetOrdNum(); if (nRestrict>nMin) nMin=nRestrict;
}
m_bToTopPossible = nObjNum+1 < nMax;
m_bToBtmPossible = nObjNum > nMin;
} else { // multiple selection
SdrObjList* pOL0=nullptr;
size_t nPos0 = 0; for (size_t nm = 0; !m_bToBtmPossible && nm<nCount; ++nm) { // check 'send to background'
SdrObject* pObj=rMarkList.GetMark(nm)->GetMarkedSdrObj();
SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject(); if (pOL!=pOL0) {
nPos0 = 0;
pOL0=pOL;
} const size_t nPos = pObj->GetOrdNum();
m_bToBtmPossible = nPos && (nPos-1 > nPos0);
nPos0 = nPos;
}
void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
{ if (pSource!=nullptr) {
SdrObjList* pOL=pSource->GetSubList(); if (pOL!=nullptr && !pSource->Is3DObj()) { // get first non-group object from group
SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
pSource=aIter.Next();
}
}
// all members of a group have to be convertible if(!ImpCanConvertForCombine1(pObj1))
{ returnfalse;
}
}
} else
{ if(!ImpCanConvertForCombine1(pObj))
{ returnfalse;
}
}
// make sure selected objects are contour objects // since now basegfx::utils::adaptiveSubdivide() is used, it is no longer // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old // mechanisms. In a next step the polygon clipper will even be able to clip curves... // ConvertMarkedToPolyObj(true);
ConvertMarkedToPathObj(true);
OSL_ENSURE(rMarkList.GetMarkCount() != 0, "no more objects selected after preparations (!)");
// #i76891# use single iteration from SJ here which works on SdrObjects and takes // groups into account by itself
SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups);
// #i76891# unfortunately ConvertMarkedToPathObj has converted all // involved polygon data to curve segments, even if not necessary. // It is better to try to reduce to more simple polygons.
aTmpPoly = basegfx::utils::simplifyCurveSegments(aTmpPoly);
// for each part polygon as preparation, remove self-intersections // correct orientations and get rid of possible neutral polygons.
aTmpPoly = basegfx::utils::prepareForPolygonOperation(aTmpPoly);
if(!bFirstObjectComplete)
{ // #i111987# Also need to collect ORed source shape when more than // a single polygon is involved if(aMergePolyPolygonA.count())
{
aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly);
} else
{
aMergePolyPolygonA = std::move(aTmpPoly);
}
} else
{ if(aMergePolyPolygonB.count())
{ // to topologically correctly collect the 2nd polygon // group it is necessary to OR the parts (each is seen as // XOR-FillRule polygon and they are drawn over each-other)
aMergePolyPolygonB = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonB, aTmpPoly);
} else
{
aMergePolyPolygonB = std::move(aTmpPoly);
}
}
}
}
// was there something added to the first polygon? if(!bFirstObjectComplete && aMergePolyPolygonA.count())
{
bFirstObjectComplete = true;
}
// move object to temporary delete list
aRemove.InsertEntry(SdrMark(pObj, pM->GetPageView()));
}
}
switch(eMode)
{ case SdrMergeMode::Merge:
{ // merge all contained parts (OR)
aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB); break;
} case SdrMergeMode::Subtract:
{ // Subtract B from A
aMergePolyPolygonA = basegfx::utils::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB); break;
} case SdrMergeMode::Intersect:
{ // AND B and A
aMergePolyPolygonA = basegfx::utils::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB); break;
}
}
// #i73441# check insert list before taking actions if(pInsOL)
{
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(pAttrObj->getSdrModelFromSdrObject(), SdrObjKind::PathFill, std::move(aMergePolyPolygonA));
ImpCopyAttributes(pAttrObj, pPath.get());
pInsOL->InsertObject(pPath.get(), nInsPos); if( bUndo )
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath));
// #i124760# To have a correct selection with only the new object it is necessary to // unmark all objects first. If not doing so, there may remain invalid pointers to objects // TTTT:Not needed for aw080 (!)
UnmarkAllObj(pInsPV);
MarkObj(pPath.get(), pInsPV, false, true);
}
aRemove.ForceSort(); switch(eMode)
{ case SdrMergeMode::Merge:
{
SetUndoComment(
SvxResId(STR_EditMergeMergePoly),
aRemove.GetMarkDescription()); break;
} case SdrMergeMode::Subtract:
{
SetUndoComment(
SvxResId(STR_EditMergeSubstractPoly),
aRemove.GetMarkDescription()); break;
} case SdrMergeMode::Intersect:
{
SetUndoComment(
SvxResId(STR_EditMergeIntersectPoly),
aRemove.GetMarkDescription()); break;
}
}
DeleteMarkedList(aRemove);
const SdrMarkList& rMarkList = GetMarkedObjectList();
SdrObjListIter aIter( rMarkList, SdrIterMode::Flat); while ( aIter.IsMore() )
{
SdrObject* pObj = aIter.Next();
SdrTextObj* pTextObj = DynCastSdrTextObj( pObj ); const OutlinerParaObject* pOPO = pTextObj ? pTextObj->GetOutlinerParaObject() : nullptr; if ( pOPO && pTextObj->IsTextFrame()
&& pTextObj->GetObjIdentifier() == SdrObjKind::Text // not callouts (OBJ_CAPTION)
&& !pTextObj->IsOutlText() // not impress presentation objects
&& pTextObj->GetMergedItem(XATTR_FORMTXTSTYLE).GetValue() == XFormTextStyle::NONE // not Fontwork
)
{ // if the last paragraph does not end in paragraph-end punctuation (ignoring whitespace), // assume this text should be added to the end of the last paragraph, instead of starting a new paragraph. const sal_Int32 nPara = rDrawOutliner.GetParagraphCount(); const OUString sLastPara = nPara ? rDrawOutliner.GetText( rDrawOutliner.GetParagraph( nPara - 1 ) ) : u""_ustr;
sal_Int32 n = sLastPara.getLength(); while ( n && unicode::isWhiteSpace( sLastPara[--n] ) )
; //TODO: find way to use Locale to identify sentence final punctuation. Copied IsSentenceAtEnd() from autofmt.cxx constbool bAppend = !n || ( sLastPara[n] != '.' && sLastPara[n] != '?' && sLastPara[n] != '!' );
rDrawOutliner.AddText( *pOPO, bAppend );
} else
{ // Unmark non-textboxes, because all marked objects are deleted at the end. AdjustMarkHdl later.
MarkObj(pObj, pPageView, /*bUnmark=*/true, /*bImpNoSetMarkHdl=*/true);
}
}
void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly)
{ // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would // create a 2nd Undo-action and Undo-Comment.
bool bUndo = IsUndoEnabled();
// Undo-String will be set later if( bUndo )
BegUndo(u""_ustr, u""_ustr, bNoPolyPoly ? SdrRepeatFunc::CombineOnePoly : SdrRepeatFunc::CombinePolyPoly);
// #105899# First, guarantee that all objects are converted to polyobjects, // especially for SdrGrafObj with bitmap filling this is necessary to not // lose the bitmap filling.
// #i12392# // ConvertMarkedToPolyObj was too strong here, it will lose quality and // information when curve objects are combined. This can be replaced by // using ConvertMarkedToPathObj without changing the previous fix.
// #i21250# // Instead of simply passing true as LineToArea, use bNoPolyPoly as info // if this command is a 'Combine' or a 'Connect' command. On Connect it's true. // To not concert line segments with a set line width to polygons in that case, // use this info. Do not convert LineToArea on Connect commands. // ConvertMarkedToPathObj(!bNoPolyPoly);
// This is used for Combine and Connect. In no case it is necessary to force // the content to curve, but it is also not good to force to polygons. Thus, // curve is the less information losing one. Remember: This place is not // used for merge. // LineToArea is never necessary, both commands are able to take over the // set line style and to display it correctly. Thus, i will use a // ConvertMarkedToPathObj with a false in any case. Only drawback is that // simple polygons will be changed to curves, but with no information loss.
ConvertMarkedToPathObj(false/* bLineToArea */);
// continue as before
basegfx::B2DPolyPolygon aPolyPolygon;
SdrObjList* pCurrentOL = nullptr;
SdrMarkList aRemoveBuffer;
if(ImpCanConvertForCombine(pObj))
{ // remember objects to be able to copy attributes
pAttrObj = pObj;
// unfortunately ConvertMarkedToPathObj has converted all // involved polygon data to curve segments, even if not necessary. // It is better to try to reduce to more simple polygons.
basegfx::B2DPolyPolygon aTmpPoly(basegfx::utils::simplifyCurveSegments(ImpGetPolyPolygon(pObj)));
aPolyPolygon.insert(0, aTmpPoly);
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(pAttrObj->getSdrModelFromSdrObject(), eKind, std::move(aPolyPolygon));
// attributes of the lowest object
ImpCopyAttributes(pAttrObj, pPath.get());
// If LineStyle of pAttrObj is drawing::LineStyle_NONE force to drawing::LineStyle_SOLID to make visible. const drawing::LineStyle eLineStyle = pAttrObj->GetMergedItem(XATTR_LINESTYLE).GetValue(); const drawing::FillStyle eFillStyle = pAttrObj->GetMergedItem(XATTR_FILLSTYLE).GetValue();
// Take fill style/closed state of pAttrObj in account when deciding to change the line style bool bIsClosedPathObj = false; if (auto pPathObj = dynamic_cast<const SdrPathObj*>(pAttrObj)) if (pPathObj->IsClosed())
bIsClosedPathObj = true;
// Here was a severe error: Without UnmarkAllObj, the new object was marked // additionally to the two ones which are deleted below. As long as those are // in the UNDO there is no problem, but as soon as they get deleted, the // MarkList will contain deleted objects -> GPF.
UnmarkAllObj(pInsPV);
MarkObj(pPath.get(), pInsPV, false, true);
}
// build an UndoComment from the objects actually used
aRemoveBuffer.ForceSort(); // important for remove (see below) if( bUndo )
SetUndoComment(SvxResId(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveBuffer.GetMarkDescription());
// remove objects actually used from the list
DeleteMarkedList(aRemoveBuffer); if( bUndo )
EndUndo();
}
if(nPolygonCount >= 2)
{ // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
bCan = true;
} elseif(bMakeLines && 1 == nPolygonCount)
{ // #i69172# ..or with at least 2 edges (curves or lines) const basegfx::B2DPolygon& aPolygon(rPpolyPolygon.getB2DPolygon(0)); const sal_uInt32 nPointCount(aPolygon.count());
if(nPointCount > 2)
{
bCan = true;
}
}
return bCan;
}
bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, bool bMakeLines)
{ bool bOtherObjs(false); // true=objects other than PathObj's existent bool bMin1PolyPoly(false); // true=at least 1 tools::PolyPolygon with more than one Polygon existent
SdrObjList* pOL = pObj->GetSubList();
if(pOL)
{ // group object -- check all members if they're PathObjs
SdrObjListIter aIter(pOL, SdrIterMode::DeepNoGroups);
if(pSrcPath)
{ // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
SdrObject* pLast = nullptr; // to be able to apply OutlinerParaObject const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly()); const sal_uInt32 nPolyCount(rPolyPolygon.count());
if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
{ // #i37011# also create a text object and add at rPos + 1
rtl::Reference<SdrObject> pTextObj = SdrObjFactory::MakeNewObject(
pCustomShape->getSdrModelFromSdrObject(),
pCustomShape->GetObjInventor(),
SdrObjKind::Text);
// copy all attributes
SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
// clear fill and line style
aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
// get the text bounds and set at text object
tools::Rectangle aTextBounds = pCustomShape->GetSnapRect(); if(pCustomShape->GetTextBounds(aTextBounds))
{
pTextObj->SetSnapRect(aTextBounds);
}
if( bUndo )
{ // construct UndoComment from objects actually used
SetUndoComment(SvxResId(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveBuffer.GetMarkDescription()); // remove objects actually used from the list
EndUndo();
}
}
if(pPV)
{
SdrObjList* pCurrentLst=pPV->GetObjList();
SdrObjList* pSrcLst=pCurrentLst;
SdrObjList* pSrcLst0=pSrcLst; // make sure OrdNums are correct if (pSrcLst->IsObjOrdNumsDirty())
pSrcLst->RecalcObjOrdNums();
rtl::Reference<SdrObject> pGrp;
SdrObjList* pDstLst=nullptr; // if all selected objects come from foreign object lists. // the group object is the last one in the list.
size_t nInsPos=pSrcLst->GetObjCount(); bool bNeedInsPos=true; for (size_t nm=rMarkList.GetMarkCount(); nm>0;)
{
--nm;
SdrMark* pM=rMarkList.GetMark(nm); if (pM->GetPageView()==pPV)
{
SdrObject* pObj=pM->GetMarkedSdrObj(); if (!pGrp)
{
pGrp = new SdrObjGroup(pObj->getSdrModelFromSdrObject());
pDstLst=pGrp->GetSubList();
assert(pDstLst && "Alleged group object doesn't return object list.");
}
pSrcLst=pObj->getParentSdrObjListFromSdrObject(); if (pSrcLst!=pSrcLst0)
{ if (pSrcLst->IsObjOrdNumsDirty())
pSrcLst->RecalcObjOrdNums();
} bool bForeignList=pSrcLst!=pCurrentLst; if (!bForeignList && bNeedInsPos)
{
nInsPos=pObj->GetOrdNum(); // this way, all ObjOrdNum of the page are set
nInsPos++;
bNeedInsPos=false;
}
pSrcLst->RemoveObject(pObj->GetOrdNumDirect()); if (!bForeignList)
nInsPos--; // correct InsertPos
pDstLst->InsertObject(pObj,0);
GetMarkedObjectListWriteAccess().DeleteMark(nm);
pSrcLst0=pSrcLst;
}
} if (pGrp!=nullptr)
{
assert(pDstLst); // keep coverity happy
aNewMark.InsertEntry(SdrMark(pGrp.get(),pPV)); const size_t nCount=pDstLst->GetObjCount();
pCurrentLst->InsertObject(pGrp.get(),nInsPos);
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.