1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <svx/svdedtv.hxx>
21 #include <svx/svdundo.hxx>
22 #include <svx/svdograf.hxx>
23 #include <svx/svdoole2.hxx>
24 #include <svx/svdoedge.hxx>
25 #include <svx/svdlayer.hxx>
26 #include <svx/svdpagv.hxx>
27 #include <svx/svdpage.hxx>
28 #include <svx/svdpoev.hxx>
29 #include <svx/strings.hrc>
30 #include <svx/dialmgr.hxx>
31 #include <svx/e3dsceneupdater.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <svx/svdview.hxx>
34 #include <clonelist.hxx>
35 #include <svx/svdogrp.hxx>
36 #include <svx/scene3d.hxx>
37 #include <svx/xfillit0.hxx>
38 #include <osl/diagnose.h>
39 
40 #include <com/sun/star/lang/XServiceInfo.hpp>
41 
42 using namespace com::sun::star;
43 
ImpResetPossibilityFlags()44 void SdrEditView::ImpResetPossibilityFlags()
45 {
46     m_bReadOnly               =false;
47 
48     m_bGroupPossible          =false;
49     m_bUnGroupPossible        =false;
50     m_bGrpEnterPossible       =false;
51     m_bToTopPossible          =false;
52     m_bToBtmPossible          =false;
53     m_bReverseOrderPossible   =false;
54 
55     m_bImportMtfPossible      =false;
56     m_bCombinePossible        =false;
57     m_bDismantlePossible      =false;
58     m_bCombineNoPolyPolyPossible =false;
59     m_bDismantleMakeLinesPossible=false;
60     m_bOrthoDesiredOnMarked   =false;
61 
62     m_bOneOrMoreMovable       =false;
63     m_bMoreThanOneNoMovRot    =false;
64     m_bContortionPossible     =false;
65     m_bMoveAllowed            =false;
66     m_bResizeFreeAllowed      =false;
67     m_bResizePropAllowed      =false;
68     m_bRotateFreeAllowed      =false;
69     m_bRotate90Allowed        =false;
70     m_bMirrorFreeAllowed      =false;
71     m_bMirror45Allowed        =false;
72     m_bMirror90Allowed        =false;
73     m_bTransparenceAllowed    =false;
74     m_bCropAllowed            =false;
75     m_bGradientAllowed        =false;
76     m_bShearAllowed           =false;
77     m_bEdgeRadiusAllowed      =false;
78     m_bCanConvToPath          =false;
79     m_bCanConvToPoly          =false;
80     m_bCanConvToContour       =false;
81     m_bMoveProtect            =false;
82     m_bResizeProtect          =false;
83 }
84 
SdrEditView(SdrModel & rSdrModel,OutputDevice * pOut)85 SdrEditView::SdrEditView(SdrModel& rSdrModel, OutputDevice* pOut)
86     : SdrMarkView(rSdrModel, pOut)
87     , m_bPossibilitiesDirty(true)
88     , m_bReadOnly(false)
89     , m_bGroupPossible(false)
90     , m_bUnGroupPossible(false)
91     , m_bGrpEnterPossible(false)
92     , m_bToTopPossible(false)
93     , m_bToBtmPossible(false)
94     , m_bReverseOrderPossible(false)
95     , m_bImportMtfPossible(false)
96     , m_bCombinePossible(false)
97     , m_bDismantlePossible(false)
98     , m_bCombineNoPolyPolyPossible(false)
99     , m_bDismantleMakeLinesPossible(false)
100     , m_bOrthoDesiredOnMarked(false)
101     , m_bOneOrMoreMovable(false)
102     , m_bMoreThanOneNoMovRot(false)
103     , m_bContortionPossible(false)
104     , m_bMoveAllowed(false)
105     , m_bResizeFreeAllowed(false)
106     , m_bResizePropAllowed(false)
107     , m_bRotateFreeAllowed(false)
108     , m_bRotate90Allowed(false)
109     , m_bMirrorFreeAllowed(false)
110     , m_bMirror45Allowed(false)
111     , m_bMirror90Allowed(false)
112     , m_bShearAllowed(false)
113     , m_bEdgeRadiusAllowed(false)
114     , m_bTransparenceAllowed(false)
115     , m_bCropAllowed(false)
116     , m_bGradientAllowed(false)
117     , m_bCanConvToPath(false)
118     , m_bCanConvToPoly(false)
119     , m_bCanConvToContour(false)
120     , m_bMoveProtect(false)
121     , m_bResizeProtect(false)
122 {
123 }
124 
~SdrEditView()125 SdrEditView::~SdrEditView()
126 {
127 }
128 
InsertNewLayer(const OUString & rName,sal_uInt16 nPos)129 void SdrEditView::InsertNewLayer(const OUString& rName, sal_uInt16 nPos)
130 {
131     SdrLayerAdmin& rLA=mpModel->GetLayerAdmin();
132     sal_uInt16 nMax=rLA.GetLayerCount();
133     if (nPos>nMax) nPos=nMax;
134     rLA.NewLayer(rName,nPos);
135 
136     if( GetModel()->IsUndoEnabled() )
137         AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewLayer(nPos,rLA,*mpModel));
138 
139     mpModel->SetChanged();
140 }
141 
ImpDelLayerCheck(SdrObjList const * pOL,SdrLayerID nDelID) const142 bool SdrEditView::ImpDelLayerCheck(SdrObjList const * pOL, SdrLayerID nDelID) const
143 {
144     bool bDelAll(true);
145 
146     for(size_t nObjNum = pOL->GetObjCount(); nObjNum > 0 && bDelAll;)
147     {
148         nObjNum--;
149         SdrObject* pObj = pOL->GetObj(nObjNum);
150         SdrObjList* pSubOL = pObj->GetSubList();
151 
152         // explicitly test for group objects and 3d scenes
153         if(pSubOL && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr || dynamic_cast< const E3dScene* >(pObj) !=  nullptr))
154         {
155             if(!ImpDelLayerCheck(pSubOL, nDelID))
156             {
157                 bDelAll = false;
158             }
159         }
160         else
161         {
162             if(pObj->GetLayer() != nDelID)
163             {
164                 bDelAll = false;
165             }
166         }
167     }
168 
169     return bDelAll;
170 }
171 
ImpDelLayerDelObjs(SdrObjList * pOL,SdrLayerID nDelID)172 void SdrEditView::ImpDelLayerDelObjs(SdrObjList* pOL, SdrLayerID nDelID)
173 {
174     const size_t nObjCount(pOL->GetObjCount());
175     // make sure OrdNums are correct
176     pOL->GetObj(0)->GetOrdNum();
177 
178     const bool bUndo = GetModel()->IsUndoEnabled();
179 
180     for(size_t nObjNum = nObjCount; nObjNum > 0;)
181     {
182         nObjNum--;
183         SdrObject* pObj = pOL->GetObj(nObjNum);
184         SdrObjList* pSubOL = pObj->GetSubList();
185 
186 
187         // explicitly test for group objects and 3d scenes
188         if(pSubOL && (dynamic_cast<const SdrObjGroup*>( pObj) != nullptr || dynamic_cast<const E3dScene* >(pObj) !=  nullptr))
189         {
190             if(ImpDelLayerCheck(pSubOL, nDelID))
191             {
192                 if( bUndo )
193                     AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
194                 pOL->RemoveObject(nObjNum);
195 
196                 if( !bUndo )
197                     SdrObject::Free( pObj );
198             }
199             else
200             {
201                 ImpDelLayerDelObjs(pSubOL, nDelID);
202             }
203         }
204         else
205         {
206             if(pObj->GetLayer() == nDelID)
207             {
208                 if( bUndo )
209                     AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
210                 pOL->RemoveObject(nObjNum);
211                 if( !bUndo )
212                     SdrObject::Free( pObj );
213             }
214         }
215     }
216 }
217 
DeleteLayer(const OUString & rName)218 void SdrEditView::DeleteLayer(const OUString& rName)
219 {
220     SdrLayerAdmin& rLA = mpModel->GetLayerAdmin();
221     SdrLayer* pLayer = rLA.GetLayer(rName);
222 
223     if(!pLayer)
224         return;
225 
226     sal_uInt16 nLayerNum(rLA.GetLayerPos(pLayer));
227     SdrLayerID nDelID = pLayer->GetID();
228 
229     const bool bUndo = IsUndoEnabled();
230     if( bUndo )
231         BegUndo(SvxResId(STR_UndoDelLayer));
232 
233     bool bMaPg(true);
234 
235     for(sal_uInt16 nPageKind(0); nPageKind < 2; nPageKind++)
236     {
237         // MasterPages and DrawPages
238         sal_uInt16 nPgCount(bMaPg ? mpModel->GetMasterPageCount() : mpModel->GetPageCount());
239 
240         for(sal_uInt16 nPgNum(0); nPgNum < nPgCount; nPgNum++)
241         {
242             // over all pages
243             SdrPage* pPage = bMaPg ? mpModel->GetMasterPage(nPgNum) : mpModel->GetPage(nPgNum);
244             const size_t nObjCount(pPage->GetObjCount());
245 
246             // make sure OrdNums are correct
247             if(nObjCount)
248                 pPage->GetObj(0)->GetOrdNum();
249 
250             for(size_t nObjNum(nObjCount); nObjNum > 0;)
251             {
252                 nObjNum--;
253                 SdrObject* pObj = pPage->GetObj(nObjNum);
254                 SdrObjList* pSubOL = pObj->GetSubList();
255 
256                 // explicitly test for group objects and 3d scenes
257                 if(pSubOL && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr || dynamic_cast<const E3dScene* >(pObj) !=  nullptr))
258                 {
259                     if(ImpDelLayerCheck(pSubOL, nDelID))
260                     {
261                         if( bUndo )
262                             AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
263                         pPage->RemoveObject(nObjNum);
264                         if( !bUndo )
265                             SdrObject::Free(pObj);
266                     }
267                     else
268                     {
269                         ImpDelLayerDelObjs(pSubOL, nDelID);
270                     }
271                 }
272                 else
273                 {
274                     if(pObj->GetLayer() == nDelID)
275                     {
276                         if( bUndo )
277                             AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
278                         pPage->RemoveObject(nObjNum);
279                         if( !bUndo )
280                             SdrObject::Free(pObj);
281                     }
282                 }
283             }
284         }
285         bMaPg = false;
286     }
287 
288     if( bUndo )
289     {
290         AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteLayer(nLayerNum, rLA, *mpModel));
291         rLA.RemoveLayer(nLayerNum).release();
292         EndUndo();
293     }
294     else
295     {
296         rLA.RemoveLayer(nLayerNum);
297     }
298 
299     mpModel->SetChanged();
300 }
301 
302 
EndUndo()303 void SdrEditView::EndUndo()
304 {
305     // #i13033#
306     // Comparison changed to 1L since EndUndo() is called later now
307     // and EndUndo WILL change count to count-1
308     if(1 == mpModel->GetUndoBracketLevel())
309     {
310         ImpBroadcastEdgesOfMarkedNodes();
311     }
312 
313     // #i13033#
314     // moved to bottom to still have access to UNDOs inside of
315     // ImpBroadcastEdgesOfMarkedNodes()
316     mpModel->EndUndo();
317 }
318 
ImpBroadcastEdgesOfMarkedNodes()319 void SdrEditView::ImpBroadcastEdgesOfMarkedNodes()
320 {
321     std::vector<SdrObject*>::const_iterator iterPos;
322     const std::vector<SdrObject*>& rAllMarkedObjects = GetTransitiveHullOfMarkedObjects();
323 
324     // #i13033#
325     // New mechanism to search for necessary disconnections for
326     // changed connectors inside the transitive hull of all at
327     // the beginning of UNDO selected objects
328     for(size_t a(0); a < rAllMarkedObjects.size(); a++)
329     {
330         SdrEdgeObj* pEdge = dynamic_cast<SdrEdgeObj*>( rAllMarkedObjects[a] );
331 
332         if(pEdge)
333         {
334             SdrObject* pObj1 = pEdge->GetConnectedNode(false);
335             SdrObject* pObj2 = pEdge->GetConnectedNode(true);
336 
337             if(pObj1 && !pEdge->CheckNodeConnection(false))
338             {
339                 iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj1);
340 
341                 if (iterPos == rAllMarkedObjects.end())
342                 {
343                     if( IsUndoEnabled() )
344                         AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pEdge));
345                     pEdge->DisconnectFromNode(false);
346                 }
347             }
348 
349             if(pObj2 && !pEdge->CheckNodeConnection(true))
350             {
351                 iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj2);
352 
353                 if (iterPos == rAllMarkedObjects.end())
354                 {
355                     if( IsUndoEnabled() )
356                         AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pEdge));
357                     pEdge->DisconnectFromNode(true);
358                 }
359             }
360         }
361     }
362 
363     const size_t nMarkedEdgeCnt = GetMarkedEdgesOfMarkedNodes().GetMarkCount();
364 
365     for (size_t i=0; i<nMarkedEdgeCnt; ++i) {
366         SdrMark* pEM = GetMarkedEdgesOfMarkedNodes().GetMark(i);
367         SdrObject* pEdgeTmp=pEM->GetMarkedSdrObj();
368         SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pEdgeTmp );
369         if (pEdge!=nullptr) {
370             pEdge->SetEdgeTrackDirty();
371         }
372     }
373 }
374 
375 
376 // Possibilities
377 
378 
MarkListHasChanged()379 void SdrEditView::MarkListHasChanged()
380 {
381     SdrMarkView::MarkListHasChanged();
382     m_bPossibilitiesDirty=true;
383 }
384 
ModelHasChanged()385 void SdrEditView::ModelHasChanged()
386 {
387     SdrMarkView::ModelHasChanged();
388     m_bPossibilitiesDirty=true;
389 }
390 
IsResizeAllowed(bool bProp) const391 bool SdrEditView::IsResizeAllowed(bool bProp) const
392 {
393     ForcePossibilities();
394     if (m_bResizeProtect) return false;
395     if (bProp) return m_bResizePropAllowed;
396     return m_bResizeFreeAllowed;
397 }
398 
IsRotateAllowed(bool b90Deg) const399 bool SdrEditView::IsRotateAllowed(bool b90Deg) const
400 {
401     ForcePossibilities();
402     if (m_bMoveProtect) return false;
403     if (b90Deg) return m_bRotate90Allowed;
404     return m_bRotateFreeAllowed;
405 }
406 
IsMirrorAllowed(bool b45Deg,bool b90Deg) const407 bool SdrEditView::IsMirrorAllowed(bool b45Deg, bool b90Deg) const
408 {
409     ForcePossibilities();
410     if (m_bMoveProtect) return false;
411     if (b90Deg) return m_bMirror90Allowed;
412     if (b45Deg) return m_bMirror45Allowed;
413     return m_bMirrorFreeAllowed;
414 }
415 
IsTransparenceAllowed() const416 bool SdrEditView::IsTransparenceAllowed() const
417 {
418     ForcePossibilities();
419     return m_bTransparenceAllowed;
420 }
421 
IsCropAllowed() const422 bool SdrEditView::IsCropAllowed() const
423 {
424     ForcePossibilities();
425     return m_bCropAllowed;
426 }
427 
IsGradientAllowed() const428 bool SdrEditView::IsGradientAllowed() const
429 {
430     ForcePossibilities();
431     return m_bGradientAllowed;
432 }
433 
IsShearAllowed() const434 bool SdrEditView::IsShearAllowed() const
435 {
436     ForcePossibilities();
437     if (m_bResizeProtect) return false;
438     return m_bShearAllowed;
439 }
440 
IsEdgeRadiusAllowed() const441 bool SdrEditView::IsEdgeRadiusAllowed() const
442 {
443     ForcePossibilities();
444     return m_bEdgeRadiusAllowed;
445 }
446 
IsCrookAllowed(bool bNoContortion) const447 bool SdrEditView::IsCrookAllowed(bool bNoContortion) const
448 {
449     // CrookMode missing here (no rotations allowed when shearing ...)
450     ForcePossibilities();
451     if (bNoContortion) {
452         if (!m_bRotateFreeAllowed) return false;
453         return !m_bMoveProtect && m_bMoveAllowed;
454     } else {
455         return !m_bResizeProtect && m_bContortionPossible;
456     }
457 }
458 
IsDistortAllowed(bool bNoContortion) const459 bool SdrEditView::IsDistortAllowed(bool bNoContortion) const
460 {
461     ForcePossibilities();
462     if (bNoContortion) {
463         return false;
464     } else {
465         return !m_bResizeProtect && m_bContortionPossible;
466     }
467 }
468 
IsCombinePossible(bool bNoPolyPoly) const469 bool SdrEditView::IsCombinePossible(bool bNoPolyPoly) const
470 {
471     ForcePossibilities();
472     if (bNoPolyPoly) return m_bCombineNoPolyPolyPossible;
473     else return m_bCombinePossible;
474 }
475 
IsDismantlePossible(bool bMakeLines) const476 bool SdrEditView::IsDismantlePossible(bool bMakeLines) const
477 {
478     ForcePossibilities();
479     if (bMakeLines) return m_bDismantleMakeLinesPossible;
480     else return m_bDismantlePossible;
481 }
482 
CheckPossibilities()483 void SdrEditView::CheckPossibilities()
484 {
485     if (mbSomeObjChgdFlag)
486     {
487         m_bPossibilitiesDirty = true;
488 
489         // This call IS necessary to correct the MarkList, in which
490         // no longer to the model belonging objects still can reside.
491         // These ones need to be removed.
492         CheckMarked();
493     }
494 
495     if (!m_bPossibilitiesDirty)
496         return;
497 
498     ImpResetPossibilityFlags();
499     SortMarkedObjects();
500     const size_t nMarkCount = GetMarkedObjectCount();
501     if (nMarkCount != 0)
502     {
503         m_bReverseOrderPossible = (nMarkCount >= 2);
504 
505         size_t nMovableCount=0;
506         m_bGroupPossible=nMarkCount>=2;
507         m_bCombinePossible=nMarkCount>=2;
508         if (nMarkCount==1)
509         {
510             // check bCombinePossible more thoroughly
511             // still missing ...
512             const SdrObject* pObj=GetMarkedObjectByIndex(0);
513             //const SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
514             bool bGroup=pObj->GetSubList()!=nullptr;
515             bool bHasText=pObj->GetOutlinerParaObject()!=nullptr;
516             if (bGroup || bHasText) {
517                 m_bCombinePossible=true;
518             }
519         }
520         m_bCombineNoPolyPolyPossible=m_bCombinePossible;
521         // accept transformations for now
522         m_bMoveAllowed      =true;
523         m_bResizeFreeAllowed=true;
524         m_bResizePropAllowed=true;
525         m_bRotateFreeAllowed=true;
526         m_bRotate90Allowed  =true;
527         m_bMirrorFreeAllowed=true;
528         m_bMirror45Allowed  =true;
529         m_bMirror90Allowed  =true;
530         m_bShearAllowed     =true;
531         m_bEdgeRadiusAllowed=false;
532         m_bContortionPossible=true;
533         m_bCanConvToContour = true;
534 
535         // these ones are only allowed when single object is selected
536         m_bTransparenceAllowed = (nMarkCount == 1);
537         m_bGradientAllowed = (nMarkCount == 1);
538         m_bCropAllowed = (nMarkCount == 1);
539         if(m_bGradientAllowed)
540         {
541             // gradient depends on fill style
542             const SdrMark* pM = GetSdrMarkByIndex(0);
543             const SdrObject* pObj = pM->GetMarkedSdrObj();
544 
545             // may be group object, so get merged ItemSet
546             const SfxItemSet& rSet = pObj->GetMergedItemSet();
547             SfxItemState eState = rSet.GetItemState(XATTR_FILLSTYLE, false);
548 
549             if(SfxItemState::DONTCARE != eState)
550             {
551                 // If state is not DONTCARE, test the item
552                 drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
553 
554                 if(eFillStyle != drawing::FillStyle_GRADIENT)
555                 {
556                     m_bGradientAllowed = false;
557                 }
558             }
559         }
560 
561         bool bNoMovRotFound=false;
562         const SdrPageView* pPV0=nullptr;
563 
564         for (size_t nm=0; nm<nMarkCount; ++nm) {
565             const SdrMark* pM=GetSdrMarkByIndex(nm);
566             const SdrObject* pObj=pM->GetMarkedSdrObj();
567             const SdrPageView* pPV=pM->GetPageView();
568             if (pPV!=pPV0) {
569                 if (pPV->IsReadOnly()) m_bReadOnly=true;
570                 pPV0=pPV;
571             }
572 
573             SdrObjTransformInfoRec aInfo;
574             pObj->TakeObjInfo(aInfo);
575             bool bMovPrt=pObj->IsMoveProtect();
576             bool bSizPrt=pObj->IsResizeProtect();
577             if (!bMovPrt && aInfo.bMoveAllowed) nMovableCount++; // count MovableObjs
578             if (bMovPrt) m_bMoveProtect=true;
579             if (bSizPrt) m_bResizeProtect=true;
580 
581             // not allowed when not allowed at one object
582             if(!aInfo.bTransparenceAllowed)
583                 m_bTransparenceAllowed = false;
584 
585             // If one of these can't do something, none can
586             if (!aInfo.bMoveAllowed      ) m_bMoveAllowed      =false;
587             if (!aInfo.bResizeFreeAllowed) m_bResizeFreeAllowed=false;
588             if (!aInfo.bResizePropAllowed) m_bResizePropAllowed=false;
589             if (!aInfo.bRotateFreeAllowed) m_bRotateFreeAllowed=false;
590             if (!aInfo.bRotate90Allowed  ) m_bRotate90Allowed  =false;
591             if (!aInfo.bMirrorFreeAllowed) m_bMirrorFreeAllowed=false;
592             if (!aInfo.bMirror45Allowed  ) m_bMirror45Allowed  =false;
593             if (!aInfo.bMirror90Allowed  ) m_bMirror90Allowed  =false;
594             if (!aInfo.bShearAllowed     ) m_bShearAllowed     =false;
595             if (aInfo.bEdgeRadiusAllowed) m_bEdgeRadiusAllowed=true;
596             if (aInfo.bNoContortion      ) m_bContortionPossible=false;
597             // For Crook with Contortion: all objects have to be
598             // Movable and Rotatable, except for a maximum of 1 of them
599             if (!m_bMoreThanOneNoMovRot) {
600                 if (!aInfo.bMoveAllowed || !aInfo.bResizeFreeAllowed) {
601                     m_bMoreThanOneNoMovRot=bNoMovRotFound;
602                     bNoMovRotFound=true;
603                 }
604             }
605 
606             // Must be resizable to allow cropping
607             if (!aInfo.bResizeFreeAllowed && !aInfo.bResizePropAllowed)
608                 m_bCropAllowed = false;
609 
610             // if one member cannot be converted, no conversion is possible
611             if(!aInfo.bCanConvToContour)
612                 m_bCanConvToContour = false;
613 
614             // Ungroup
615             if (!m_bUnGroupPossible) m_bUnGroupPossible=pObj->GetSubList()!=nullptr;
616             // ConvertToCurve: If at least one can be converted, that is fine.
617             if (aInfo.bCanConvToPath          ) m_bCanConvToPath          =true;
618             if (aInfo.bCanConvToPoly          ) m_bCanConvToPoly          =true;
619 
620             // Combine/Dismantle
621             if(m_bCombinePossible)
622             {
623                 m_bCombinePossible = ImpCanConvertForCombine(pObj);
624                 m_bCombineNoPolyPolyPossible = m_bCombinePossible;
625             }
626 
627             if (!m_bDismantlePossible) m_bDismantlePossible = ImpCanDismantle(pObj, false);
628             if (!m_bDismantleMakeLinesPossible) m_bDismantleMakeLinesPossible = ImpCanDismantle(pObj, true);
629             // check OrthoDesiredOnMarked
630             if (!m_bOrthoDesiredOnMarked && !aInfo.bNoOrthoDesired) m_bOrthoDesiredOnMarked=true;
631             // check ImportMtf
632 
633             if (!m_bImportMtfPossible)
634             {
635                 const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj);
636                 if (pSdrGrafObj != nullptr)
637                 {
638                     if ((pSdrGrafObj->HasGDIMetaFile() && !pSdrGrafObj->IsEPS()) ||
639                         pSdrGrafObj->isEmbeddedVectorGraphicData())
640                     {
641                         m_bImportMtfPossible = true;
642                     }
643                 }
644 
645                 const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(pObj);
646                 if (pSdrOle2Obj)
647                 {
648                     m_bImportMtfPossible = pSdrOle2Obj->GetObjRef().is();
649                 }
650             }
651         }
652 
653         m_bOneOrMoreMovable=nMovableCount!=0;
654         m_bGrpEnterPossible=m_bUnGroupPossible;
655     }
656     ImpCheckToTopBtmPossible();
657     static_cast<SdrPolyEditView*>(this)->ImpCheckPolyPossibilities();
658     m_bPossibilitiesDirty=false;
659 
660     if (m_bReadOnly) {
661         bool bTemp=m_bGrpEnterPossible;
662         ImpResetPossibilityFlags();
663         m_bReadOnly=true;
664         m_bGrpEnterPossible=bTemp;
665     }
666     if (!m_bMoveAllowed)        return;
667 
668     // Don't allow moving glued connectors.
669     // Currently only implemented for single selection.
670     if (nMarkCount==1) {
671         SdrObject* pObj=GetMarkedObjectByIndex(0);
672         SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
673         if (pEdge!=nullptr) {
674             SdrObject* pNode1=pEdge->GetConnectedNode(true);
675             SdrObject* pNode2=pEdge->GetConnectedNode(false);
676             if (pNode1!=nullptr || pNode2!=nullptr) m_bMoveAllowed=false;
677         }
678     }
679 }
680 
681 
ForceMarkedObjToAnotherPage()682 void SdrEditView::ForceMarkedObjToAnotherPage()
683 {
684     bool bFlg=false;
685     for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
686         SdrMark* pM=GetSdrMarkByIndex(nm);
687         SdrObject* pObj=pM->GetMarkedSdrObj();
688         tools::Rectangle aObjRect(pObj->GetCurrentBoundRect());
689         tools::Rectangle aPgRect(pM->GetPageView()->GetPageRect());
690         if (!aObjRect.IsOver(aPgRect)) {
691             bool bFnd=false;
692             SdrPageView* pPV = GetSdrPageView();
693 
694             if(pPV)
695             {
696                 bFnd = aObjRect.IsOver(pPV->GetPageRect());
697             }
698 
699             if(bFnd)
700             {
701                 pM->GetPageView()->GetObjList()->RemoveObject(pObj->GetOrdNum());
702                 pPV->GetObjList()->InsertObject(pObj, SAL_MAX_SIZE);
703                 pM->SetPageView(pPV);
704                 InvalidateAllWin(aObjRect);
705                 bFlg=true;
706             }
707         }
708     }
709     if (bFlg) {
710         MarkListHasChanged();
711     }
712 }
713 
DeleteMarkedList(SdrMarkList const & rMark)714 std::vector<SdrObject*> SdrEditView::DeleteMarkedList(SdrMarkList const& rMark)
715 {
716     std::vector<SdrObject*> ret;
717     if (rMark.GetMarkCount()!=0)
718     {
719         rMark.ForceSort();
720 
721         const bool bUndo = IsUndoEnabled();
722         if( bUndo )
723             BegUndo();
724         const size_t nMarkCount(rMark.GetMarkCount());
725 
726         if(nMarkCount)
727         {
728             std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
729 
730             if( bUndo )
731             {
732                 for(size_t nm = nMarkCount; nm > 0;)
733                 {
734                     --nm;
735                     SdrMark* pM = rMark.GetMark(nm);
736                     SdrObject* pObj = pM->GetMarkedSdrObj();
737 
738                     // extra undo actions for changed connector which now may hold its laid out path (SJ)
739                     AddUndoActions(CreateConnectorUndo( *pObj ));
740 
741                     AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
742                 }
743             }
744 
745             // make sure, OrderNums are correct:
746             rMark.GetMark(0)->GetMarkedSdrObj()->GetOrdNum();
747 
748             for(size_t nm = nMarkCount; nm > 0;)
749             {
750                 --nm;
751                 SdrMark* pM = rMark.GetMark(nm);
752                 SdrObject* pObj = pM->GetMarkedSdrObj();
753                 SdrObjList*  pOL = pObj->getParentSdrObjListFromSdrObject();
754                 const size_t nOrdNum(pObj->GetOrdNumDirect());
755 
756                 bool bIs3D = dynamic_cast< E3dObject* >(pObj);
757                 // set up a scene updater if object is a 3d object
758                 if(bIs3D)
759                 {
760                     aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pObj));
761                 }
762 
763                 pOL->RemoveObject(nOrdNum);
764 
765                 if( !bUndo )
766                 {
767                     // tdf#108863 don't delete objects before EndUndo()
768                     ret.push_back(pObj);
769                 }
770             }
771 
772             // fire scene updaters
773             while(!aUpdaters.empty())
774             {
775                 delete aUpdaters.back();
776                 aUpdaters.pop_back();
777             }
778         }
779 
780         if( bUndo )
781             EndUndo();
782     }
783     return ret;
784 }
785 
lcl_LazyDelete(std::vector<SdrObject * > & rLazyDelete)786 static void lcl_LazyDelete(std::vector<SdrObject*> & rLazyDelete)
787 {
788     // now delete removed scene objects
789     while (!rLazyDelete.empty())
790     {
791         SdrObject::Free( rLazyDelete.back() );
792         rLazyDelete.pop_back();
793     }
794 }
795 
DeleteMarkedObj()796 void SdrEditView::DeleteMarkedObj()
797 {
798     // #i110981# return when nothing is to be done at all
799     if(!GetMarkedObjectCount())
800     {
801         return;
802     }
803 
804     // moved breaking action and undo start outside loop
805     BrkAction();
806     BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Delete);
807 
808     std::vector<SdrObject*> lazyDeleteObjects;
809     // remove as long as something is selected. This allows to schedule objects for
810     // removal for a next run as needed
811     while(GetMarkedObjectCount())
812     {
813         // vector to remember the parents which may be empty after object removal
814         std::vector< SdrObject* > aParents;
815 
816         {
817             const SdrMarkList& rMarkList = GetMarkedObjectList();
818             const size_t nCount(rMarkList.GetMarkCount());
819 
820             for(size_t a = 0; a < nCount; ++a)
821             {
822                 // in the first run, add all found parents, but only once
823                 SdrMark* pMark(rMarkList.GetMark(a));
824                 SdrObject* pObject(pMark->GetMarkedSdrObj());
825                 SdrObject* pParent(pObject->getParentSdrObjectFromSdrObject());
826 
827                 if(pParent)
828                 {
829                     if(!aParents.empty())
830                     {
831                         std::vector< SdrObject* >::iterator aFindResult =
832                             std::find(aParents.begin(), aParents.end(), pParent);
833 
834                         if(aFindResult == aParents.end())
835                         {
836                             aParents.push_back(pParent);
837                         }
838                     }
839                     else
840                     {
841                         aParents.push_back(pParent);
842                     }
843                 }
844             }
845 
846             if(!aParents.empty())
847             {
848                 // in a 2nd run, remove all objects which may already be scheduled for
849                 // removal. I am not sure if this can happen, but theoretically
850                 // a to-be-removed object may already be the group/3DScene itself
851                 for(size_t a = 0; a < nCount; ++a)
852                 {
853                     SdrMark* pMark = rMarkList.GetMark(a);
854                     SdrObject* pObject = pMark->GetMarkedSdrObj();
855 
856                     std::vector< SdrObject* >::iterator aFindResult =
857                         std::find(aParents.begin(), aParents.end(), pObject);
858 
859                     if(aFindResult != aParents.end())
860                     {
861                         aParents.erase(aFindResult);
862                     }
863                 }
864             }
865         }
866 
867         // original stuff: remove selected objects. Handle clear will
868         // do something only once
869         auto temp(DeleteMarkedList(GetMarkedObjectList()));
870         for (auto p : temp)
871         {
872             lazyDeleteObjects.push_back(p);
873         }
874         GetMarkedObjectListWriteAccess().Clear();
875         maHdlList.Clear();
876 
877         while(!aParents.empty() && !GetMarkedObjectCount())
878         {
879             // iterate over remembered parents
880             SdrObject* pParent = aParents.back();
881             aParents.pop_back();
882 
883             if(pParent->GetSubList() && 0 == pParent->GetSubList()->GetObjCount())
884             {
885                 // we detected an empty parent, a candidate to leave group/3DScene
886                 // if entered
887                 if(GetSdrPageView()->GetCurrentGroup()
888                     && GetSdrPageView()->GetCurrentGroup() == pParent)
889                 {
890                     GetSdrPageView()->LeaveOneGroup();
891                 }
892 
893                 // schedule empty parent for removal
894                 GetMarkedObjectListWriteAccess().InsertEntry(
895                     SdrMark(pParent, GetSdrPageView()));
896             }
897         }
898     }
899 
900     // end undo and change messaging moved at the end
901     EndUndo();
902     MarkListHasChanged();
903 
904     lcl_LazyDelete(lazyDeleteObjects);
905 }
906 
CopyMarkedObj()907 void SdrEditView::CopyMarkedObj()
908 {
909     SortMarkedObjects();
910 
911     SdrMarkList aSourceObjectsForCopy(GetMarkedObjectList());
912     // The following loop is used instead of MarkList::Merge(), to be
913     // able to flag the MarkEntries.
914     const size_t nEdgeCnt = GetEdgesOfMarkedNodes().GetMarkCount();
915     for (size_t nEdgeNum=0; nEdgeNum<nEdgeCnt; ++nEdgeNum) {
916         SdrMark aM(*GetEdgesOfMarkedNodes().GetMark(nEdgeNum));
917         aM.SetUser(1);
918         aSourceObjectsForCopy.InsertEntry(aM);
919     }
920     aSourceObjectsForCopy.ForceSort();
921 
922     // #i13033#
923     // New mechanism to re-create the connections of cloned connectors
924     CloneList aCloneList;
925 
926     const bool bUndo = IsUndoEnabled();
927 
928     GetMarkedObjectListWriteAccess().Clear();
929     size_t nCloneErrCnt=0;
930     std::unordered_set<rtl::OUString> aNameSet;
931     const size_t nMarkCount=aSourceObjectsForCopy.GetMarkCount();
932     for (size_t nm=0; nm<nMarkCount; ++nm) {
933         SdrMark* pM=aSourceObjectsForCopy.GetMark(nm);
934         SdrObject* pSource(pM->GetMarkedSdrObj());
935         SdrObject* pO(pSource->CloneSdrObject(pSource->getSdrModelFromSdrObject()));
936         if (pO!=nullptr) {
937             pM->GetPageView()->GetObjList()->InsertObjectThenMakeNameUnique(pO, aNameSet);
938 
939             if( bUndo )
940                 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoCopyObject(*pO));
941 
942             SdrMark aME(*pM);
943             aME.SetMarkedSdrObj(pO);
944             aCloneList.AddPair(pM->GetMarkedSdrObj(), pO);
945 
946             if (pM->GetUser()==0)
947             {
948                 // otherwise it is only an Edge we have to copy as well
949                 GetMarkedObjectListWriteAccess().InsertEntry(aME);
950             }
951         } else {
952             nCloneErrCnt++;
953         }
954     }
955 
956     // #i13033#
957     // New mechanism to re-create the connections of cloned connectors
958     aCloneList.CopyConnections();
959 
960     if(nCloneErrCnt)
961     {
962 #ifdef DBG_UTIL
963         OStringBuffer aStr("SdrEditView::CopyMarkedObj(): Error when cloning ");
964 
965         if(nCloneErrCnt == 1)
966         {
967             aStr.append("a drawing object.");
968         }
969         else
970         {
971             aStr.append(static_cast<sal_Int32>(nCloneErrCnt));
972             aStr.append(" drawing objects.");
973         }
974 
975         aStr.append(" This object's/These objects's connections will not be copied.");
976         OSL_FAIL(aStr.getStr());
977 #endif
978     }
979     MarkListHasChanged();
980 }
981 
982 
InsertObjectAtView(SdrObject * pObj,SdrPageView & rPV,SdrInsertFlags nOptions)983 bool SdrEditView::InsertObjectAtView(SdrObject* pObj, SdrPageView& rPV, SdrInsertFlags nOptions)
984 {
985     if (nOptions & SdrInsertFlags::SETDEFLAYER) {
986         SdrLayerID nLayer=rPV.GetPage()->GetLayerAdmin().GetLayerID(maActualLayer);
987         if (nLayer==SDRLAYER_NOTFOUND) nLayer=SdrLayerID(0);
988         if (rPV.GetLockedLayers().IsSet(nLayer) || !rPV.GetVisibleLayers().IsSet(nLayer)) {
989             SdrObject::Free( pObj ); // Layer locked or invisible
990             return false;
991         }
992         pObj->NbcSetLayer(nLayer);
993     }
994     if (nOptions & SdrInsertFlags::SETDEFATTR) {
995         if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
996         pObj->SetMergedItemSet(maDefaultAttr);
997     }
998     if (!pObj->IsInserted()) {
999         rPV.GetObjList()->InsertObject(pObj, SAL_MAX_SIZE);
1000     }
1001     if( IsUndoEnabled())
1002     {
1003         EndTextEditAllViews();
1004         AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pObj));
1005     }
1006 
1007     css::uno::Reference<lang::XServiceInfo> xServices(GetModel()->getUnoModel(),
1008                                                       css::uno::UNO_QUERY);
1009     if (xServices.is() && (xServices->supportsService("com.sun.star.sheet.SpreadsheetDocument") ||
1010                            xServices->supportsService("com.sun.star.text.TextDocument")))
1011     {
1012         const bool bUndo(IsUndoEnabled());
1013         GetModel()->EnableUndo(false);
1014         pObj->MakeNameUnique();
1015         GetModel()->EnableUndo(bUndo);
1016     }
1017 
1018     if (!(nOptions & SdrInsertFlags::DONTMARK)) {
1019         if (!(nOptions & SdrInsertFlags::ADDMARK)) UnmarkAllObj();
1020         MarkObj(pObj,&rPV);
1021     }
1022     return true;
1023 }
1024 
ReplaceObjectAtView(SdrObject * pOldObj,SdrPageView & rPV,SdrObject * pNewObj,bool bMark)1025 void SdrEditView::ReplaceObjectAtView(SdrObject* pOldObj, SdrPageView& rPV, SdrObject* pNewObj, bool bMark)
1026 {
1027     if(IsTextEdit())
1028     {
1029 #ifdef DBG_UTIL
1030         if(auto pTextObj = dynamic_cast< SdrTextObj* >(pOldObj))
1031             if (pTextObj->IsTextEditActive())
1032                 OSL_ENSURE(false, "OldObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)");
1033 
1034         if(auto pTextObj = dynamic_cast< SdrTextObj* >(pNewObj))
1035             if (pTextObj->IsTextEditActive())
1036                 OSL_ENSURE(false, "NewObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)");
1037 #endif
1038 
1039         // #i123468# emergency repair situation, needs to cast up to a class derived from
1040         // this one; (aw080 has a mechanism for that and the view hierarchy is secured to
1041         // always be a SdrView)
1042         SdrView *pSdrView = dynamic_cast<SdrView*>(this);
1043         if (pSdrView)
1044             pSdrView->SdrEndTextEdit();
1045     }
1046 
1047     SdrObjList* pOL=pOldObj->getParentSdrObjListFromSdrObject();
1048     const bool bUndo = IsUndoEnabled();
1049     if( bUndo  )
1050         AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pOldObj,*pNewObj));
1051 
1052     if( IsObjMarked( pOldObj ) )
1053         MarkObj( pOldObj, &rPV, true /*unmark!*/ );
1054 
1055     pOL->ReplaceObject(pNewObj,pOldObj->GetOrdNum());
1056 
1057     if( !bUndo )
1058         SdrObject::Free( pOldObj );
1059 
1060     if (bMark) MarkObj(pNewObj,&rPV);
1061 }
1062 
1063 
IsUndoEnabled() const1064 bool SdrEditView::IsUndoEnabled() const
1065 {
1066     return mpModel->IsUndoEnabled();
1067 }
1068 
EndTextEditAllViews() const1069 void SdrEditView::EndTextEditAllViews() const
1070 {
1071     size_t nViews = mpModel->GetListenerCount();
1072     for (size_t nView = 0; nView < nViews; ++nView)
1073     {
1074         SdrObjEditView* pView = dynamic_cast<SdrObjEditView*>(mpModel->GetListener(nView));
1075         if (!pView)
1076             continue;
1077 
1078         if (pView->IsTextEdit())
1079             pView->SdrEndTextEdit();
1080     }
1081 }
1082 
1083 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1084