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