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
21 #include <svx/svdmrkv.hxx>
22 #include <svx/svdetc.hxx>
23 #include <svx/svdoedge.hxx>
24 #include <svx/svdview.hxx>
25 #include <svx/svdpagv.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svdotable.hxx>
28 #include "svddrgm1.hxx"
29
30 #ifdef DBG_UTIL
31 #include <svdibrow.hxx>
32 #endif
33
34 #include <osl/thread.h>
35 #include <svx/svdoole2.hxx>
36 #include <svx/xgrad.hxx>
37 #include <svx/xfillit0.hxx>
38 #include <svx/xflgrit.hxx>
39 #include <svx/xlineit0.hxx>
40 #include "gradtrns.hxx"
41 #include <svx/xflftrit.hxx>
42 #include <svx/dialmgr.hxx>
43 #include <svx/strings.hrc>
44 #include <svx/svdundo.hxx>
45 #include <svx/svdopath.hxx>
46 #include <svx/scene3d.hxx>
47 #include <svx/svdovirt.hxx>
48 #include <sdr/overlay/overlayrollingrectangle.hxx>
49 #include <svx/sdr/overlay/overlaymanager.hxx>
50 #include <svx/sdr/table/tablecontroller.hxx>
51 #include <svx/sdr/contact/viewcontact.hxx>
52 #include <svx/sdrpaintwindow.hxx>
53 #include <svx/sdrpagewindow.hxx>
54 #include <svx/sdrhittesthelper.hxx>
55 #include <svx/svdocapt.hxx>
56 #include <svx/svdograf.hxx>
57 #include <vcl/uitest/logger.hxx>
58 #include <vcl/uitest/eventdescription.hxx>
59
60 #include <editeng/editdata.hxx>
61 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
62 #include <comphelper/lok.hxx>
63 #include <sfx2/lokhelper.hxx>
64 #include <sfx2/lokcharthelper.hxx>
65 #include <sfx2/viewsh.hxx>
66
67 #include <array>
68
69 #include <com/sun/star/view/XSelectionSupplier.hpp>
70
71 #include <boost/property_tree/json_parser.hpp>
72
73 using namespace com::sun::star;
74
75 // Migrate Marking of Objects, Points and GluePoints
76
77 class ImplMarkingOverlay
78 {
79 // The OverlayObjects
80 sdr::overlay::OverlayObjectList maObjects;
81
82 // The remembered second position in logical coordinates
83 basegfx::B2DPoint maSecondPosition;
84
85 // A flag to remember if the action is for unmarking.
86 bool const mbUnmarking : 1;
87
88 public:
89 ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking);
90
91 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
92 // That destructor calls clear() at the list which removes all objects from the
93 // OverlayManager and deletes them.
94
95 void SetSecondPosition(const basegfx::B2DPoint& rNewPosition);
IsUnmarking() const96 bool IsUnmarking() const { return mbUnmarking; }
97 };
98
ImplMarkingOverlay(const SdrPaintView & rView,const basegfx::B2DPoint & rStartPos,bool bUnmarking)99 ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking)
100 : maSecondPosition(rStartPos),
101 mbUnmarking(bUnmarking)
102 {
103 for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
104 {
105 SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
106 const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
107
108 if (xTargetOverlay.is())
109 {
110 std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(new sdr::overlay::OverlayRollingRectangleStriped(
111 rStartPos, rStartPos, false));
112 xTargetOverlay->add(*pNew);
113 maObjects.append(std::move(pNew));
114 }
115 }
116 }
117
SetSecondPosition(const basegfx::B2DPoint & rNewPosition)118 void ImplMarkingOverlay::SetSecondPosition(const basegfx::B2DPoint& rNewPosition)
119 {
120 if(rNewPosition != maSecondPosition)
121 {
122 // apply to OverlayObjects
123 for(sal_uInt32 a(0); a < maObjects.count(); a++)
124 {
125 sdr::overlay::OverlayRollingRectangleStriped& rCandidate = static_cast< sdr::overlay::OverlayRollingRectangleStriped&>(maObjects.getOverlayObject(a));
126 rCandidate.setSecondPosition(rNewPosition);
127 }
128
129 // remember new position
130 maSecondPosition = rNewPosition;
131 }
132 }
133
134
135 // MarkView
136
137
ImpClearVars()138 void SdrMarkView::ImpClearVars()
139 {
140 meDragMode=SdrDragMode::Move;
141 meEditMode=SdrViewEditMode::Edit;
142 meEditMode0=SdrViewEditMode::Edit;
143 mbDesignMode=false;
144 mpMarkedObj=nullptr;
145 mpMarkedPV=nullptr;
146 mbForceFrameHandles=false;
147 mbPlusHdlAlways=false;
148 mnFrameHandlesLimit=50;
149 mbInsPolyPoint=false;
150 mbMarkedObjRectDirty=false;
151 mbMarkedPointsRectsDirty=false;
152 mbMarkHandlesHidden = false;
153 mbMrkPntDirty=false;
154
155 // Migrate selections
156 BrkMarkObj();
157 BrkMarkPoints();
158 BrkMarkGluePoints();
159 }
160
SdrMarkView(SdrModel & rSdrModel,OutputDevice * pOut)161 SdrMarkView::SdrMarkView(
162 SdrModel& rSdrModel,
163 OutputDevice* pOut)
164 : SdrSnapView(rSdrModel, pOut),
165 mpMarkObjOverlay(nullptr),
166 mpMarkPointsOverlay(nullptr),
167 mpMarkGluePointsOverlay(nullptr),
168 maHdlList(this)
169 {
170 ImpClearVars();
171 StartListening(rSdrModel);
172 }
173
~SdrMarkView()174 SdrMarkView::~SdrMarkView()
175 {
176 // Migrate selections
177 BrkMarkObj();
178 BrkMarkPoints();
179 BrkMarkGluePoints();
180 }
181
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)182 void SdrMarkView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
183 {
184 if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
185 {
186 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
187 SdrHintKind eKind=pSdrHint->GetKind();
188 if (eKind==SdrHintKind::ObjectChange || eKind==SdrHintKind::ObjectInserted || eKind==SdrHintKind::ObjectRemoved)
189 {
190 mbMarkedObjRectDirty=true;
191 mbMarkedPointsRectsDirty=true;
192 }
193 }
194 SdrSnapView::Notify(rBC,rHint);
195 }
196
ModelHasChanged()197 void SdrMarkView::ModelHasChanged()
198 {
199 SdrPaintView::ModelHasChanged();
200 GetMarkedObjectListWriteAccess().SetNameDirty();
201 mbMarkedObjRectDirty=true;
202 mbMarkedPointsRectsDirty=true;
203 // Example: Obj is selected and maMarkedObjectList is sorted.
204 // In another View 2, the ObjOrder is changed (e. g. MovToTop())
205 // Then we need to re-sort MarkList.
206 GetMarkedObjectListWriteAccess().SetUnsorted();
207 SortMarkedObjects();
208 mbMrkPntDirty=true;
209 UndirtyMrkPnt();
210 SdrView* pV=static_cast<SdrView*>(this);
211 if (pV!=nullptr && !pV->IsDragObj() && !pV->IsInsObjPoint()) {
212 AdjustMarkHdl();
213 }
214
215 if (comphelper::LibreOfficeKit::isActive() && GetMarkedObjectCount() > 0)
216 {
217 //TODO: Is MarkedObjRect valid at this point?
218 tools::Rectangle aSelection(GetMarkedObjRect());
219 OString sSelection;
220 if (aSelection.IsEmpty())
221 sSelection = "EMPTY";
222 else
223 {
224 sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
225 if (nTotalPaintWindows == 1)
226 {
227 const vcl::Window* pWin = dynamic_cast<const vcl::Window*>(this->GetFirstOutputDevice());
228 if (pWin && pWin->IsChart())
229 {
230 const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
231 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
232 {
233 Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
234 Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
235 aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
236 }
237 }
238 }
239
240 // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
241 if (mpMarkedPV)
242 {
243 if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
244 {
245 if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
246 aSelection = OutputDevice::LogicToLogic(aSelection, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
247 }
248 }
249
250 sSelection = aSelection.toString();
251 }
252
253 if(SfxViewShell* pViewShell = GetSfxViewShell())
254 SfxLokHelper::notifyInvalidation(pViewShell, sSelection);
255 }
256 }
257
258
IsAction() const259 bool SdrMarkView::IsAction() const
260 {
261 return SdrSnapView::IsAction() || IsMarkObj() || IsMarkPoints() || IsMarkGluePoints();
262 }
263
MovAction(const Point & rPnt)264 void SdrMarkView::MovAction(const Point& rPnt)
265 {
266 SdrSnapView::MovAction(rPnt);
267
268 if(IsMarkObj())
269 {
270 MovMarkObj(rPnt);
271 }
272 else if(IsMarkPoints())
273 {
274 MovMarkPoints(rPnt);
275 }
276 else if(IsMarkGluePoints())
277 {
278 MovMarkGluePoints(rPnt);
279 }
280 }
281
EndAction()282 void SdrMarkView::EndAction()
283 {
284 if(IsMarkObj())
285 {
286 EndMarkObj();
287 }
288 else if(IsMarkPoints())
289 {
290 EndMarkPoints();
291 }
292 else if(IsMarkGluePoints())
293 {
294 EndMarkGluePoints();
295 }
296
297 SdrSnapView::EndAction();
298 }
299
BckAction()300 void SdrMarkView::BckAction()
301 {
302 SdrSnapView::BckAction();
303 BrkMarkObj();
304 BrkMarkPoints();
305 BrkMarkGluePoints();
306 }
307
BrkAction()308 void SdrMarkView::BrkAction()
309 {
310 SdrSnapView::BrkAction();
311 BrkMarkObj();
312 BrkMarkPoints();
313 BrkMarkGluePoints();
314 }
315
TakeActionRect(tools::Rectangle & rRect) const316 void SdrMarkView::TakeActionRect(tools::Rectangle& rRect) const
317 {
318 if(IsMarkObj() || IsMarkPoints() || IsMarkGluePoints())
319 {
320 rRect = tools::Rectangle(maDragStat.GetStart(), maDragStat.GetNow());
321 }
322 else
323 {
324 SdrSnapView::TakeActionRect(rRect);
325 }
326 }
327
328
ClearPageView()329 void SdrMarkView::ClearPageView()
330 {
331 UnmarkAllObj();
332 SdrSnapView::ClearPageView();
333 }
334
HideSdrPage()335 void SdrMarkView::HideSdrPage()
336 {
337 bool bMrkChg(false);
338
339 SdrPageView* pPageView = GetSdrPageView();
340 if (pPageView)
341 {
342 // break all creation actions when hiding page (#75081#)
343 BrkAction();
344
345 // Discard all selections on this page
346 bMrkChg = GetMarkedObjectListWriteAccess().DeletePageView(*pPageView);
347 }
348
349 SdrSnapView::HideSdrPage();
350
351 if(bMrkChg)
352 {
353 MarkListHasChanged();
354 AdjustMarkHdl();
355 }
356 }
357
358
BegMarkObj(const Point & rPnt,bool bUnmark)359 void SdrMarkView::BegMarkObj(const Point& rPnt, bool bUnmark)
360 {
361 BrkAction();
362
363 DBG_ASSERT(nullptr == mpMarkObjOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkObjOverlay (!)");
364 basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
365 mpMarkObjOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);
366
367 maDragStat.Reset(rPnt);
368 maDragStat.NextPoint();
369 maDragStat.SetMinMove(mnMinMovLog);
370 }
371
MovMarkObj(const Point & rPnt)372 void SdrMarkView::MovMarkObj(const Point& rPnt)
373 {
374 if(IsMarkObj() && maDragStat.CheckMinMoved(rPnt))
375 {
376 maDragStat.NextMove(rPnt);
377 DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
378 basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
379 mpMarkObjOverlay->SetSecondPosition(aNewPos);
380 }
381 }
382
EndMarkObj()383 bool SdrMarkView::EndMarkObj()
384 {
385 bool bRetval(false);
386
387 if(IsMarkObj())
388 {
389 if(maDragStat.IsMinMoved())
390 {
391 tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
392 aRect.Justify();
393 MarkObj(aRect, mpMarkObjOverlay->IsUnmarking());
394 bRetval = true;
395 }
396
397 // cleanup
398 BrkMarkObj();
399 }
400
401 return bRetval;
402 }
403
BrkMarkObj()404 void SdrMarkView::BrkMarkObj()
405 {
406 if(IsMarkObj())
407 {
408 DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
409 delete mpMarkObjOverlay;
410 mpMarkObjOverlay = nullptr;
411 }
412 }
413
414
BegMarkPoints(const Point & rPnt,bool bUnmark)415 bool SdrMarkView::BegMarkPoints(const Point& rPnt, bool bUnmark)
416 {
417 if(HasMarkablePoints())
418 {
419 BrkAction();
420
421 DBG_ASSERT(nullptr == mpMarkPointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkPointsOverlay (!)");
422 basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
423 mpMarkPointsOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);
424
425 maDragStat.Reset(rPnt);
426 maDragStat.NextPoint();
427 maDragStat.SetMinMove(mnMinMovLog);
428
429 return true;
430 }
431
432 return false;
433 }
434
MovMarkPoints(const Point & rPnt)435 void SdrMarkView::MovMarkPoints(const Point& rPnt)
436 {
437 if(IsMarkPoints() && maDragStat.CheckMinMoved(rPnt))
438 {
439 maDragStat.NextMove(rPnt);
440
441 DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
442 basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
443 mpMarkPointsOverlay->SetSecondPosition(aNewPos);
444 }
445 }
446
EndMarkPoints()447 bool SdrMarkView::EndMarkPoints()
448 {
449 bool bRetval(false);
450
451 if(IsMarkPoints())
452 {
453 if(maDragStat.IsMinMoved())
454 {
455 tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
456 aRect.Justify();
457 MarkPoints(&aRect, mpMarkPointsOverlay->IsUnmarking());
458
459 bRetval = true;
460 }
461
462 // cleanup
463 BrkMarkPoints();
464 }
465
466 return bRetval;
467 }
468
BrkMarkPoints()469 void SdrMarkView::BrkMarkPoints()
470 {
471 if(IsMarkPoints())
472 {
473 DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
474 delete mpMarkPointsOverlay;
475 mpMarkPointsOverlay = nullptr;
476 }
477 }
478
479
BegMarkGluePoints(const Point & rPnt,bool bUnmark)480 bool SdrMarkView::BegMarkGluePoints(const Point& rPnt, bool bUnmark)
481 {
482 if(HasMarkableGluePoints())
483 {
484 BrkAction();
485
486 DBG_ASSERT(nullptr == mpMarkGluePointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkGluePointsOverlay (!)");
487
488 basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
489 mpMarkGluePointsOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);
490 maDragStat.Reset(rPnt);
491 maDragStat.NextPoint();
492 maDragStat.SetMinMove(mnMinMovLog);
493
494 return true;
495 }
496
497 return false;
498 }
499
MovMarkGluePoints(const Point & rPnt)500 void SdrMarkView::MovMarkGluePoints(const Point& rPnt)
501 {
502 if(IsMarkGluePoints() && maDragStat.CheckMinMoved(rPnt))
503 {
504 maDragStat.NextMove(rPnt);
505
506 DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
507 basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
508 mpMarkGluePointsOverlay->SetSecondPosition(aNewPos);
509 }
510 }
511
EndMarkGluePoints()512 void SdrMarkView::EndMarkGluePoints()
513 {
514 if(IsMarkGluePoints())
515 {
516 if(maDragStat.IsMinMoved())
517 {
518 tools::Rectangle aRect(maDragStat.GetStart(),maDragStat.GetNow());
519 aRect.Justify();
520 MarkGluePoints(&aRect, mpMarkGluePointsOverlay->IsUnmarking());
521 }
522
523 // cleanup
524 BrkMarkGluePoints();
525 }
526 }
527
BrkMarkGluePoints()528 void SdrMarkView::BrkMarkGluePoints()
529 {
530 if(IsMarkGluePoints())
531 {
532 DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
533 delete mpMarkGluePointsOverlay;
534 mpMarkGluePointsOverlay = nullptr;
535 }
536 }
537
MarkableObjectsExceed(int n) const538 bool SdrMarkView::MarkableObjectsExceed( int n ) const
539 {
540 SdrPageView* pPV = GetSdrPageView();
541 if (!pPV)
542 return false;
543
544 SdrObjList* pOL=pPV->GetObjList();
545 const size_t nObjCount = pOL->GetObjCount();
546 for (size_t nObjNum=0; nObjNum<nObjCount; ++nObjNum) {
547 SdrObject* pObj=pOL->GetObj(nObjNum);
548 if (IsObjMarkable(pObj,pPV) && --n<0)
549 return true;
550 }
551
552 return false;
553 }
554
hideMarkHandles()555 void SdrMarkView::hideMarkHandles()
556 {
557 if(!mbMarkHandlesHidden)
558 {
559 mbMarkHandlesHidden = true;
560 AdjustMarkHdl();
561 }
562 }
563
showMarkHandles()564 void SdrMarkView::showMarkHandles()
565 {
566 if(mbMarkHandlesHidden)
567 {
568 mbMarkHandlesHidden = false;
569 AdjustMarkHdl();
570 }
571 }
572
ImpIsFrameHandles() const573 bool SdrMarkView::ImpIsFrameHandles() const
574 {
575 const size_t nMarkCount=GetMarkedObjectCount();
576 bool bFrmHdl=nMarkCount>static_cast<size_t>(mnFrameHandlesLimit) || mbForceFrameHandles;
577 bool bStdDrag=meDragMode==SdrDragMode::Move;
578 if (nMarkCount==1 && bStdDrag && bFrmHdl)
579 {
580 const SdrObject* pObj=GetMarkedObjectByIndex(0);
581 if (pObj->GetObjInventor()==SdrInventor::Default)
582 {
583 sal_uInt16 nIdent=pObj->GetObjIdentifier();
584 if (nIdent==OBJ_LINE || nIdent==OBJ_EDGE || nIdent==OBJ_CAPTION || nIdent==OBJ_MEASURE || nIdent==OBJ_CUSTOMSHAPE || nIdent==OBJ_TABLE )
585 {
586 bFrmHdl=false;
587 }
588 }
589 }
590 if (!bStdDrag && !bFrmHdl) {
591 // all other drag modes only with FrameHandles
592 bFrmHdl=true;
593 if (meDragMode==SdrDragMode::Rotate) {
594 // when rotating, use ObjOwn drag, if there's at least 1 PolyObj
595 for (size_t nMarkNum=0; nMarkNum<nMarkCount && bFrmHdl; ++nMarkNum) {
596 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
597 const SdrObject* pObj=pM->GetMarkedSdrObj();
598 bFrmHdl=!pObj->IsPolyObj();
599 }
600 }
601 }
602 if (!bFrmHdl) {
603 // FrameHandles, if at least 1 Obj can't do SpecialDrag
604 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bFrmHdl; ++nMarkNum) {
605 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
606 const SdrObject* pObj=pM->GetMarkedSdrObj();
607 bFrmHdl=!pObj->hasSpecialDrag();
608 }
609 }
610
611 // no FrameHdl for crop
612 if(bFrmHdl && SdrDragMode::Crop == meDragMode)
613 {
614 bFrmHdl = false;
615 }
616
617 return bFrmHdl;
618 }
619
620 namespace
621 {
lcl_getDragMethodServiceName(const OUString & rCID)622 OUString lcl_getDragMethodServiceName( const OUString& rCID )
623 {
624 OUString aRet;
625
626 sal_Int32 nIndexStart = rCID.indexOf( "DragMethod=" );
627 if( nIndexStart != -1 )
628 {
629 nIndexStart = rCID.indexOf( '=', nIndexStart );
630 if( nIndexStart != -1 )
631 {
632 nIndexStart++;
633 sal_Int32 nNextSlash = rCID.indexOf( '/', nIndexStart );
634 if( nNextSlash != -1 )
635 {
636 sal_Int32 nIndexEnd = nNextSlash;
637 sal_Int32 nNextColon = rCID.indexOf( ':', nIndexStart );
638 if( nNextColon < nNextSlash )
639 nIndexEnd = nNextColon;
640 aRet = rCID.copy(nIndexStart,nIndexEnd-nIndexStart);
641 }
642 }
643 }
644 return aRet;
645 }
646
lcl_getDragParameterString(const OUString & rCID)647 OUString lcl_getDragParameterString( const OUString& rCID )
648 {
649 OUString aRet;
650
651 sal_Int32 nIndexStart = rCID.indexOf( "DragParameter=" );
652 if( nIndexStart != -1 )
653 {
654 nIndexStart = rCID.indexOf( '=', nIndexStart );
655 if( nIndexStart != -1 )
656 {
657 nIndexStart++;
658 sal_Int32 nNextSlash = rCID.indexOf( '/', nIndexStart );
659 if( nNextSlash != -1 )
660 {
661 sal_Int32 nIndexEnd = nNextSlash;
662 sal_Int32 nNextColon = rCID.indexOf( ':', nIndexStart );
663 if( nNextColon < nNextSlash )
664 nIndexEnd = nNextColon;
665 aRet = rCID.copy(nIndexStart,nIndexEnd-nIndexStart);
666 }
667 }
668 }
669 return aRet;
670 }
671 } // anonymous namespace
672
SetMarkHandles(SfxViewShell * pOtherShell)673 void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
674 {
675 // remember old focus handle values to search for it again
676 const SdrHdl* pSaveOldFocusHdl = maHdlList.GetFocusHdl();
677 bool bSaveOldFocus(false);
678 sal_uInt32 nSavePolyNum(0), nSavePointNum(0);
679 SdrHdlKind eSaveKind(SdrHdlKind::Move);
680 SdrObject* pSaveObj = nullptr;
681
682 if(pSaveOldFocusHdl
683 && pSaveOldFocusHdl->GetObj()
684 && dynamic_cast<const SdrPathObj*>(pSaveOldFocusHdl->GetObj()) != nullptr
685 && (pSaveOldFocusHdl->GetKind() == SdrHdlKind::Poly || pSaveOldFocusHdl->GetKind() == SdrHdlKind::BezierWeight))
686 {
687 bSaveOldFocus = true;
688 nSavePolyNum = pSaveOldFocusHdl->GetPolyNum();
689 nSavePointNum = pSaveOldFocusHdl->GetPointNum();
690 pSaveObj = pSaveOldFocusHdl->GetObj();
691 eSaveKind = pSaveOldFocusHdl->GetKind();
692 }
693
694 // delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
695 maHdlList.Clear();
696 maHdlList.SetRotateShear(meDragMode==SdrDragMode::Rotate);
697 maHdlList.SetDistortShear(meDragMode==SdrDragMode::Shear);
698 mpMarkedObj=nullptr;
699 mpMarkedPV=nullptr;
700
701 // are handles enabled at all? Create only then
702 if(areMarkHandlesHidden())
703 return;
704
705 // There can be multiple mark views, but we're only interested in the one that has a window associated.
706 const bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW;
707
708 const size_t nMarkCount=GetMarkedObjectCount();
709 bool bStdDrag=meDragMode==SdrDragMode::Move;
710 bool bSingleTextObjMark=false;
711 bool bLimitedRotation(false);
712
713 if (nMarkCount==1)
714 {
715 mpMarkedObj=GetMarkedObjectByIndex(0);
716
717 if(nullptr != mpMarkedObj)
718 {
719 bSingleTextObjMark =
720 dynamic_cast<const SdrTextObj*>( mpMarkedObj) != nullptr &&
721 static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame();
722
723 // RotGrfFlyFrame: we may have limited rotation
724 bLimitedRotation = SdrDragMode::Rotate == meDragMode && mpMarkedObj->HasLimitedRotation();
725 }
726 }
727
728 bool bFrmHdl=ImpIsFrameHandles();
729
730 if (nMarkCount>0)
731 {
732 mpMarkedPV=GetSdrPageViewOfMarkedByIndex(0);
733
734 for (size_t nMarkNum=0; nMarkNum<nMarkCount && (mpMarkedPV!=nullptr || !bFrmHdl); ++nMarkNum)
735 {
736 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
737
738 if (mpMarkedPV!=pM->GetPageView())
739 {
740 mpMarkedPV=nullptr;
741 }
742 }
743 }
744
745 SfxViewShell* pViewShell = GetSfxViewShell();
746
747 // check if text edit or ole is active and handles need to be suppressed. This may be the case
748 // when a single object is selected
749 // Using a strict return statement is okay here; no handles means *no* handles.
750 if(mpMarkedObj)
751 {
752 // formerly #i33755#: If TextEdit is active the EditEngine will directly paint
753 // to the window, so suppress Overlay and handles completely; a text frame for
754 // the active text edit will be painted by the repaint mechanism in
755 // SdrObjEditView::ImpPaintOutlinerView in this case. This needs to be reworked
756 // in the future
757 // Also formerly #122142#: Pretty much the same for SdrCaptionObj's in calc.
758 if(static_cast<SdrView*>(this)->IsTextEdit())
759 {
760 const SdrTextObj* pSdrTextObj = dynamic_cast< const SdrTextObj* >(mpMarkedObj);
761
762 if (pSdrTextObj && pSdrTextObj->IsInEditMode())
763 {
764 if (!bTiledRendering)
765 return;
766 }
767 }
768
769 // formerly #i118524#: if inplace activated OLE is selected, suppress handles
770 const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(mpMarkedObj);
771
772 if(pSdrOle2Obj && (pSdrOle2Obj->isInplaceActive() || pSdrOle2Obj->isUiActive()))
773 {
774 if(pViewShell)
775 {
776 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, "INPLACE");
777 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "INPLACE");
778 return;
779 }
780 }
781 }
782
783 tools::Rectangle aRect(GetMarkedObjRect());
784
785 if (bTiledRendering && pViewShell)
786 {
787 tools::Rectangle aSelection(aRect);
788 bool bIsChart = false;
789
790 if (!aRect.IsEmpty())
791 {
792 sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
793 if (nTotalPaintWindows == 1)
794 {
795 const vcl::Window* pWin = dynamic_cast<const vcl::Window*>(this->GetFirstOutputDevice());
796 if (pWin && pWin->IsChart())
797 {
798 bIsChart = true;
799 const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
800 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
801 {
802 Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
803 Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
804 aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
805 }
806 }
807 }
808 }
809
810 if (!aSelection.IsEmpty())
811 {
812 // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
813 if (mpMarkedPV)
814 {
815 if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
816 {
817 if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
818 aSelection = OutputDevice::LogicToLogic(aSelection, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
819 }
820 }
821
822 // hide the text selection too
823 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
824 }
825
826 {
827 OString sSelectionText;
828 boost::property_tree::ptree aTableJsonTree;
829 bool bTableSelection = false;
830
831 if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == OBJ_TABLE)
832 {
833 auto& rTableObject = dynamic_cast<sdr::table::SdrTableObj&>(*mpMarkedObj);
834 bTableSelection = rTableObject.createTableEdgesJson(aTableJsonTree);
835 }
836 if (GetMarkedObjectCount())
837 {
838 SdrMark* pM = GetSdrMarkByIndex(0);
839 SdrObject* pO = pM->GetMarkedSdrObj();
840 long nRotAngle = pO->GetRotateAngle();
841 // true if we are dealing with a RotGrfFlyFrame
842 // (SwVirtFlyDrawObj with a SwGrfNode)
843 bool bWriterGraphic = pO->HasLimitedRotation();
844
845 if (bWriterGraphic)
846 {
847 nRotAngle *= 10;
848 }
849
850 OStringBuffer aExtraInfo;
851 if (bWriterGraphic)
852 {
853 aExtraInfo.append("{ \"isWriterGraphic\": true }");
854 }
855 else if (bIsChart)
856 {
857 LokChartHelper aChartHelper(pViewShell);
858 css::uno::Reference<css::frame::XController>& xChartController = aChartHelper.GetXController();
859 css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier( xChartController, uno::UNO_QUERY);
860 if (xSelectionSupplier.is())
861 {
862 uno::Any aSel = xSelectionSupplier->getSelection();
863 OUString aValue;
864 if (aSel >>= aValue)
865 {
866 OString aObjectCID(aValue.getStr(), aValue.getLength(), osl_getThreadTextEncoding());
867 aExtraInfo.append("{ ");
868 const std::vector<OString> aProps{"Draggable", "Resizable", "Rotatable"};
869 for (const auto& rProp: aProps)
870 {
871 sal_Int32 nPos = aObjectCID.indexOf(rProp);
872 if (nPos == -1) continue;
873 nPos += rProp.getLength() + 1; // '='
874 if (aExtraInfo.getLength() > 2) // != "{ "
875 aExtraInfo.append(", ");
876 aExtraInfo.append("\"is");
877 aExtraInfo.append(rProp);
878 aExtraInfo.append("\": ");
879 aExtraInfo.append(OString::boolean(aObjectCID[nPos] == '1'));
880 }
881
882 OUString sDragMethod = lcl_getDragMethodServiceName(aValue);
883 if (sDragMethod == "PieSegmentDragging")
884 {
885 // old initial offset inside the CID returned by xSelectionSupplier->getSelection()
886 // after a pie segment dragging; using SdrObject::GetName for getting a CID with the updated offset
887 aValue = pO->GetName();
888 OUString sDragParameters = lcl_getDragParameterString(aValue);
889 if (!sDragParameters.isEmpty())
890 {
891 aExtraInfo.append(", \"dragInfo\": { ");
892 aExtraInfo.append("\"dragMethod\": \"");
893 aExtraInfo.append(sDragMethod.toUtf8());
894 aExtraInfo.append("\"");
895
896 OUString sParam;
897 sal_Int32 nStartIndex = 0;
898 std::array<int, 5> aDragParameters;
899 for (auto& rParam : aDragParameters)
900 {
901 sParam = sDragParameters.getToken(0, ',', nStartIndex);
902 if (sParam.isEmpty())
903 break;
904 rParam = sParam.toInt32();
905 }
906
907 // initial offset in %
908 if (aDragParameters[0] < 0)
909 aDragParameters[0] = 0;
910 else if (aDragParameters[0] > 100)
911 aDragParameters[0] = 100;
912
913 aExtraInfo.append(", \"initialOffset\": ");
914 aExtraInfo.append(OString::number(aDragParameters[0]));
915
916 // drag direction constraint
917 Point aMinPos(aDragParameters[1], aDragParameters[2]);
918 Point aMaxPos(aDragParameters[3], aDragParameters[4]);
919 Point aDragDirection = aMaxPos - aMinPos;
920 aDragDirection = OutputDevice::LogicToLogic(aDragDirection, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
921
922 aExtraInfo.append(", \"dragDirection\": [");
923 aExtraInfo.append(aDragDirection.toString());
924 aExtraInfo.append("]");
925
926 // polygon approximating the pie segment or donut segment
927 if (pO->GetObjIdentifier() == OBJ_PATHFILL)
928 {
929 const basegfx::B2DPolyPolygon aPolyPolygon(pO->TakeXorPoly());
930 if (aPolyPolygon.count() == 1)
931 {
932 const basegfx::B2DPolygon aPolygon = aPolyPolygon.getB2DPolygon(0);
933 if (sal_uInt32 nPolySize = aPolygon.count())
934 {
935 const vcl::Window* pWin = dynamic_cast<const vcl::Window*>(this->GetFirstOutputDevice());
936 const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj();
937 if (pWin && pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
938 {
939 // in the following code escaping sequences used inside raw literal strings
940 // are for making them understandable by the JSON parser
941
942 Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
943 Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
944 OString sPolygonElem("<polygon points=\\\"");
945 for (sal_uInt32 nIndex = 0; nIndex < nPolySize; ++nIndex)
946 {
947 const basegfx::B2DPoint aB2Point = aPolygon.getB2DPoint(nIndex);
948 Point aPoint(aB2Point.getX(), aB2Point.getY());
949 aPoint.Move(aLogicOffset.getX(), aLogicOffset.getY());
950 if (nIndex > 0)
951 sPolygonElem += " ";
952 sPolygonElem += aPoint.toString();
953 }
954 sPolygonElem += R"elem(\" style=\"stroke: none; fill: rgb(114,159,207); fill-opacity: 0.8\"/>)elem";
955
956 aSelection = OutputDevice::LogicToLogic(aSelection, MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM));
957
958 OString sSVGElem = R"elem(<svg version=\"1.2\" width=\")elem" +
959 OString::number(aSelection.GetWidth() / 100.0) +
960 R"elem(mm\" height=\")elem" +
961 OString::number(aSelection.GetHeight() / 100.0) +
962 R"elem(mm\" viewBox=\")elem" +
963 aSelection.toString() +
964 R"elem(\" preserveAspectRatio=\"xMidYMid\" xmlns=\"http://www.w3.org/2000/svg\">)elem";
965
966 aExtraInfo.append(", \"svg\": \"");
967 aExtraInfo.append(sSVGElem);
968 aExtraInfo.append("\\n ");
969 aExtraInfo.append(sPolygonElem);
970 aExtraInfo.append("\\n</svg>");
971 aExtraInfo.append("\""); // svg
972 }
973 }
974 }
975 }
976 aExtraInfo.append("}"); // dragInfo
977 }
978 }
979 aExtraInfo.append(" }");
980 }
981 }
982 }
983 sSelectionText = aSelection.toString() +
984 ", " + OString::number(nRotAngle);
985 if (!aExtraInfo.isEmpty())
986 {
987 sSelectionText += ", " + aExtraInfo.makeStringAndClear();
988 }
989 }
990
991 if (sSelectionText.isEmpty())
992 sSelectionText = "EMPTY";
993
994 if (bTableSelection)
995 {
996 boost::property_tree::ptree aTableRectangle;
997 aTableRectangle.put("x", aSelection.Left());
998 aTableRectangle.put("y", aSelection.Top());
999 aTableRectangle.put("width", aSelection.GetWidth());
1000 aTableRectangle.put("height", aSelection.GetHeight());
1001 aTableJsonTree.push_back(std::make_pair("rectangle", aTableRectangle));
1002
1003 std::stringstream aStream;
1004 boost::property_tree::write_json(aStream, aTableJsonTree);
1005 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, aStream.str().c_str());
1006 }
1007 else
1008 {
1009 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, "{}");
1010 }
1011
1012 if (pOtherShell)
1013 {
1014 // Another shell wants to know about our existing
1015 // selection.
1016 if (pViewShell != pOtherShell)
1017 SfxLokHelper::notifyOtherView(pViewShell, pOtherShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionText);
1018 }
1019 else
1020 {
1021 // We have a new selection, so both pViewShell and the
1022 // other views want to know about it.
1023 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, sSelectionText.getStr());
1024 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionText);
1025 }
1026 }
1027 }
1028
1029 if (bFrmHdl)
1030 {
1031 if(!aRect.IsEmpty())
1032 {
1033 // otherwise nothing is found
1034 const size_t nSiz0(maHdlList.GetHdlCount());
1035
1036 if( bSingleTextObjMark )
1037 {
1038 mpMarkedObj->AddToHdlList(maHdlList);
1039 }
1040 else
1041 {
1042 const bool bWdt0(aRect.Left() == aRect.Right());
1043 const bool bHgt0(aRect.Top() == aRect.Bottom());
1044
1045 if (bWdt0 && bHgt0)
1046 {
1047 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1048 }
1049 else if (!bStdDrag && (bWdt0 || bHgt0))
1050 {
1051 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1052 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
1053 }
1054 else
1055 {
1056 if (!bWdt0 && !bHgt0)
1057 {
1058 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1059 }
1060
1061 if (!bLimitedRotation && !bHgt0)
1062 {
1063 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopCenter(), SdrHdlKind::Upper));
1064 }
1065
1066 if (!bWdt0 && !bHgt0)
1067 {
1068 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopRight(), SdrHdlKind::UpperRight));
1069 }
1070
1071 if (!bLimitedRotation && !bWdt0)
1072 {
1073 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.LeftCenter(), SdrHdlKind::Left ));
1074 }
1075
1076 if (!bLimitedRotation && !bWdt0)
1077 {
1078 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.RightCenter(), SdrHdlKind::Right));
1079 }
1080
1081 if (!bWdt0 && !bHgt0)
1082 {
1083 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomLeft(), SdrHdlKind::LowerLeft));
1084 }
1085
1086 if (!bLimitedRotation && !bHgt0)
1087 {
1088 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomCenter(), SdrHdlKind::Lower));
1089 }
1090
1091 if (!bWdt0 && !bHgt0)
1092 {
1093 maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
1094 }
1095 }
1096 }
1097
1098 const size_t nSiz1(maHdlList.GetHdlCount());
1099
1100 // moved setting the missing parameters at SdrHdl here from the
1101 // single loop above (bSingleTextObjMark), this was missing all
1102 // the time. Setting SdrObject is now required to correctly get
1103 // the View-Dependent evtl. GridOffset adapted
1104 for (size_t i=nSiz0; i<nSiz1; ++i)
1105 {
1106 SdrHdl* pHdl=maHdlList.GetHdl(i);
1107 pHdl->SetObj(mpMarkedObj);
1108 pHdl->SetPageView(mpMarkedPV);
1109 pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1110 }
1111 }
1112 }
1113 else
1114 {
1115 bool bDone(false);
1116
1117 // moved crop handling to non-frame part and the handle creation to SdrGrafObj
1118 if(1 == nMarkCount && mpMarkedObj && SdrDragMode::Crop == meDragMode)
1119 {
1120 // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous
1121 // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj
1122 // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx)
1123 const size_t nSiz0(maHdlList.GetHdlCount());
1124 mpMarkedObj->addCropHandles(maHdlList);
1125 const size_t nSiz1(maHdlList.GetHdlCount());
1126
1127 // Was missing: Set infos at SdrCropHdl
1128 for (size_t i=nSiz0; i<nSiz1; ++i)
1129 {
1130 SdrHdl* pHdl=maHdlList.GetHdl(i);
1131 pHdl->SetObj(mpMarkedObj);
1132 pHdl->SetPageView(mpMarkedPV);
1133 pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1134 }
1135
1136 bDone = true;
1137 }
1138
1139 if(!bDone)
1140 {
1141 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1142 {
1143 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
1144 SdrObject* pObj=pM->GetMarkedSdrObj();
1145 SdrPageView* pPV=pM->GetPageView();
1146 const size_t nSiz0=maHdlList.GetHdlCount();
1147 pObj->AddToHdlList(maHdlList);
1148 const size_t nSiz1=maHdlList.GetHdlCount();
1149 bool bPoly=pObj->IsPolyObj();
1150 const SdrUShortCont& rMrkPnts = pM->GetMarkedPoints();
1151 for (size_t i=nSiz0; i<nSiz1; ++i)
1152 {
1153 SdrHdl* pHdl=maHdlList.GetHdl(i);
1154 pHdl->SetObj(pObj);
1155 pHdl->SetPageView(pPV);
1156 pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1157
1158 if (bPoly)
1159 {
1160 bool bSelected= rMrkPnts.find( sal_uInt16(i-nSiz0) ) != rMrkPnts.end();
1161 pHdl->SetSelected(bSelected);
1162 if (mbPlusHdlAlways || bSelected)
1163 {
1164 SdrHdlList plusList(nullptr);
1165 pObj->AddToPlusHdlList(plusList, *pHdl);
1166 sal_uInt32 nPlusHdlCnt=plusList.GetHdlCount();
1167 for (sal_uInt32 nPlusNum=0; nPlusNum<nPlusHdlCnt; nPlusNum++)
1168 {
1169 SdrHdl* pPlusHdl=plusList.GetHdl(nPlusNum);
1170 pPlusHdl->SetObj(pObj);
1171 pPlusHdl->SetPageView(pPV);
1172 pPlusHdl->SetPlusHdl(true);
1173 }
1174 plusList.MoveTo(maHdlList);
1175 }
1176 }
1177 }
1178 }
1179 }
1180 }
1181
1182 // GluePoint handles
1183 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1184 {
1185 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
1186 SdrObject* pObj=pM->GetMarkedSdrObj();
1187 const SdrGluePointList* pGPL=pObj->GetGluePointList();
1188 if (!pGPL)
1189 continue;
1190
1191 SdrPageView* pPV=pM->GetPageView();
1192 const SdrUShortCont& rMrkGlue=pM->GetMarkedGluePoints();
1193 for (sal_uInt16 nId : rMrkGlue)
1194 {
1195 //nNum changed to nNumGP because already used in for loop
1196 sal_uInt16 nNumGP=pGPL->FindGluePoint(nId);
1197 if (nNumGP!=SDRGLUEPOINT_NOTFOUND)
1198 {
1199 const SdrGluePoint& rGP=(*pGPL)[nNumGP];
1200 Point aPos(rGP.GetAbsolutePos(*pObj));
1201 std::unique_ptr<SdrHdl> pGlueHdl(new SdrHdl(aPos,SdrHdlKind::Glue));
1202 pGlueHdl->SetObj(pObj);
1203 pGlueHdl->SetPageView(pPV);
1204 pGlueHdl->SetObjHdlNum(nId);
1205 maHdlList.AddHdl(std::move(pGlueHdl));
1206 }
1207 }
1208 }
1209
1210 // rotation point/axis of reflection
1211 if(!bLimitedRotation)
1212 {
1213 AddDragModeHdl(meDragMode);
1214 }
1215
1216 // sort handles
1217 maHdlList.Sort();
1218
1219 // add custom handles (used by other apps, e.g. AnchorPos)
1220 AddCustomHdl();
1221
1222 // try to restore focus handle index from remembered values
1223 if(bSaveOldFocus)
1224 {
1225 for(size_t a = 0; a < maHdlList.GetHdlCount(); ++a)
1226 {
1227 SdrHdl* pCandidate = maHdlList.GetHdl(a);
1228
1229 if(pCandidate->GetObj()
1230 && pCandidate->GetObj() == pSaveObj
1231 && pCandidate->GetKind() == eSaveKind
1232 && pCandidate->GetPolyNum() == nSavePolyNum
1233 && pCandidate->GetPointNum() == nSavePointNum)
1234 {
1235 maHdlList.SetFocusHdl(pCandidate);
1236 break;
1237 }
1238 }
1239 }
1240 }
1241
AddCustomHdl()1242 void SdrMarkView::AddCustomHdl()
1243 {
1244 // add custom handles (used by other apps, e.g. AnchorPos)
1245 }
1246
SetDragMode(SdrDragMode eMode)1247 void SdrMarkView::SetDragMode(SdrDragMode eMode)
1248 {
1249 SdrDragMode eMode0=meDragMode;
1250 meDragMode=eMode;
1251 if (meDragMode==SdrDragMode::Resize) meDragMode=SdrDragMode::Move;
1252 if (meDragMode!=eMode0) {
1253 ForceRefToMarked();
1254 SetMarkHandles(nullptr);
1255 {
1256 if (AreObjectsMarked()) MarkListHasChanged();
1257 }
1258 }
1259 }
1260
AddDragModeHdl(SdrDragMode eMode)1261 void SdrMarkView::AddDragModeHdl(SdrDragMode eMode)
1262 {
1263 switch(eMode)
1264 {
1265 case SdrDragMode::Rotate:
1266 {
1267 // add rotation center
1268 maHdlList.AddHdl(std::make_unique<SdrHdl>(maRef1, SdrHdlKind::Ref1));
1269 break;
1270 }
1271 case SdrDragMode::Mirror:
1272 {
1273 // add axis of reflection
1274 std::unique_ptr<SdrHdl> pHdl3(new SdrHdl(maRef2, SdrHdlKind::Ref2));
1275 std::unique_ptr<SdrHdl> pHdl2(new SdrHdl(maRef1, SdrHdlKind::Ref1));
1276 std::unique_ptr<SdrHdl> pHdl1(new SdrHdlLine(*pHdl2, *pHdl3, SdrHdlKind::MirrorAxis));
1277
1278 pHdl1->SetObjHdlNum(1); // for sorting
1279 pHdl2->SetObjHdlNum(2); // for sorting
1280 pHdl3->SetObjHdlNum(3); // for sorting
1281
1282 maHdlList.AddHdl(std::move(pHdl1)); // line comes first, so it is the last in HitTest
1283 maHdlList.AddHdl(std::move(pHdl2));
1284 maHdlList.AddHdl(std::move(pHdl3));
1285
1286 break;
1287 }
1288 case SdrDragMode::Transparence:
1289 {
1290 // add interactive transparency handle
1291 const size_t nMarkCount = GetMarkedObjectCount();
1292 if(nMarkCount == 1)
1293 {
1294 SdrObject* pObj = GetMarkedObjectByIndex(0);
1295 SdrModel* pModel = GetModel();
1296 const SfxItemSet& rSet = pObj->GetMergedItemSet();
1297
1298 if(SfxItemState::SET != rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE, false))
1299 {
1300 // add this item, it's not yet there
1301 XFillFloatTransparenceItem aNewItem(rSet.Get(XATTR_FILLFLOATTRANSPARENCE));
1302 XGradient aGrad = aNewItem.GetGradientValue();
1303
1304 aNewItem.SetEnabled(true);
1305 aGrad.SetStartIntens(100);
1306 aGrad.SetEndIntens(100);
1307 aNewItem.SetGradientValue(aGrad);
1308
1309 // add undo to allow user to take back this step
1310 if( pModel->IsUndoEnabled() )
1311 {
1312 pModel->BegUndo(SvxResId(SIP_XA_FILLTRANSPARENCE));
1313 pModel->AddUndo(pModel->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
1314 pModel->EndUndo();
1315 }
1316
1317 SfxItemSet aNewSet(pModel->GetItemPool());
1318 aNewSet.Put(aNewItem);
1319 pObj->SetMergedItemSetAndBroadcast(aNewSet);
1320 }
1321
1322 // set values and transform to vector set
1323 GradTransVector aGradTransVector;
1324 GradTransGradient aGradTransGradient;
1325
1326 aGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1327 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
1328
1329 // build handles
1330 const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
1331 const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
1332 std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
1333 std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
1334 std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, false));
1335 DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
1336
1337 // link them
1338 pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
1339 pGradHdl->SetObj(pObj);
1340 pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1341 pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1342
1343 // insert them
1344 maHdlList.AddHdl(std::move(pColHdl1));
1345 maHdlList.AddHdl(std::move(pColHdl2));
1346 maHdlList.AddHdl(std::move(pGradHdl));
1347 }
1348 break;
1349 }
1350 case SdrDragMode::Gradient:
1351 {
1352 // add interactive gradient handle
1353 const size_t nMarkCount = GetMarkedObjectCount();
1354 if(nMarkCount == 1)
1355 {
1356 SdrObject* pObj = GetMarkedObjectByIndex(0);
1357 const SfxItemSet& rSet = pObj->GetMergedItemSet();
1358 drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
1359
1360 if(eFillStyle == drawing::FillStyle_GRADIENT)
1361 {
1362 // set values and transform to vector set
1363 GradTransVector aGradTransVector;
1364 GradTransGradient aGradTransGradient;
1365 Size aHdlSize(15, 15);
1366
1367 aGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1368 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
1369
1370 // build handles
1371 const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
1372 const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
1373 std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, aHdlSize, false));
1374 std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, aHdlSize, false));
1375 std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, true));
1376 DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
1377
1378 // link them
1379 pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
1380 pGradHdl->SetObj(pObj);
1381 pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1382 pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1383
1384 // insert them
1385 maHdlList.AddHdl(std::move(pColHdl1));
1386 maHdlList.AddHdl(std::move(pColHdl2));
1387 maHdlList.AddHdl(std::move(pGradHdl));
1388 }
1389 }
1390 break;
1391 }
1392 case SdrDragMode::Crop:
1393 {
1394 // TODO
1395 break;
1396 }
1397 default: break;
1398 }
1399 }
1400
1401 /** handle mouse over effects for handles */
MouseMove(const MouseEvent & rMEvt,OutputDevice * pWin)1402 bool SdrMarkView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
1403 {
1404 if(maHdlList.GetHdlCount())
1405 {
1406 SdrHdl* pMouseOverHdl = nullptr;
1407 if( !rMEvt.IsLeaveWindow() && pWin )
1408 {
1409 Point aMDPos( pWin->PixelToLogic( rMEvt.GetPosPixel() ) );
1410 pMouseOverHdl = PickHandle(aMDPos);
1411 }
1412
1413 // notify last mouse over handle that he lost the mouse
1414 const size_t nHdlCount = maHdlList.GetHdlCount();
1415
1416 for(size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
1417 {
1418 SdrHdl* pCurrentHdl = GetHdl(nHdl);
1419 if( pCurrentHdl->mbMouseOver )
1420 {
1421 if( pCurrentHdl != pMouseOverHdl )
1422 {
1423 pCurrentHdl->mbMouseOver = false;
1424 pCurrentHdl->onMouseLeave();
1425 }
1426 break;
1427 }
1428 }
1429
1430 // notify current mouse over handle
1431 if( pMouseOverHdl )
1432 {
1433 pMouseOverHdl->mbMouseOver = true;
1434 pMouseOverHdl->onMouseEnter(rMEvt);
1435 }
1436 }
1437 return SdrSnapView::MouseMove(rMEvt, pWin);
1438 }
1439
RequestHelp(const HelpEvent & rHEvt)1440 bool SdrMarkView::RequestHelp(const HelpEvent& rHEvt)
1441 {
1442 if (maHdlList.GetHdlCount())
1443 {
1444 const size_t nHdlCount = maHdlList.GetHdlCount();
1445
1446 for (size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
1447 {
1448 SdrHdl* pCurrentHdl = GetHdl(nHdl);
1449 if (pCurrentHdl->mbMouseOver)
1450 {
1451 pCurrentHdl->onHelpRequest();
1452 return true;
1453 }
1454 }
1455 }
1456 return SdrSnapView::RequestHelp(rHEvt);
1457 }
1458
ForceRefToMarked()1459 void SdrMarkView::ForceRefToMarked()
1460 {
1461 switch(meDragMode)
1462 {
1463 case SdrDragMode::Rotate:
1464 {
1465 tools::Rectangle aR(GetMarkedObjRect());
1466 maRef1 = aR.Center();
1467
1468 break;
1469 }
1470
1471 case SdrDragMode::Mirror:
1472 {
1473 // first calculate the length of the axis of reflection
1474 long nOutMin=0;
1475 long nOutMax=0;
1476 long nMinLen=0;
1477 long nObjDst=0;
1478 long nOutHgt=0;
1479 OutputDevice* pOut=GetFirstOutputDevice();
1480 if (pOut!=nullptr) {
1481 // minimum length: 50 pixels
1482 nMinLen=pOut->PixelToLogic(Size(0,50)).Height();
1483 // 20 pixels distance to the Obj for the reference point
1484 nObjDst=pOut->PixelToLogic(Size(0,20)).Height();
1485 // MinY/MaxY
1486 // margin = minimum length = 10 pixels
1487 long nDst=pOut->PixelToLogic(Size(0,10)).Height();
1488 nOutMin=-pOut->GetMapMode().GetOrigin().Y();
1489 nOutMax=pOut->GetOutputSize().Height()-1+nOutMin;
1490 nOutMin+=nDst;
1491 nOutMax-=nDst;
1492 // absolute minimum length, however, is 10 pixels
1493 if (nOutMax-nOutMin<nDst) {
1494 nOutMin+=nOutMax+1;
1495 nOutMin/=2;
1496 nOutMin-=(nDst+1)/2;
1497 nOutMax=nOutMin+nDst;
1498 }
1499 nOutHgt=nOutMax-nOutMin;
1500 // otherwise minimum length = 1/4 OutHgt
1501 long nTemp=nOutHgt/4;
1502 if (nTemp>nMinLen) nMinLen=nTemp;
1503 }
1504
1505 tools::Rectangle aR(GetMarkedObjBoundRect());
1506 Point aCenter(aR.Center());
1507 long nMarkHgt=aR.GetHeight()-1;
1508 long nHgt=nMarkHgt+nObjDst*2; // 20 pixels overlapping above and below
1509 if (nHgt<nMinLen) nHgt=nMinLen; // minimum length 50 pixels or 1/4 OutHgt, respectively
1510
1511 long nY1=aCenter.Y()-(nHgt+1)/2;
1512 long nY2=nY1+nHgt;
1513
1514 if (pOut!=nullptr && nMinLen>nOutHgt) nMinLen=nOutHgt; // TODO: maybe shorten this a little
1515
1516 if (pOut!=nullptr) { // now move completely into the visible area
1517 if (nY1<nOutMin) {
1518 nY1=nOutMin;
1519 if (nY2<nY1+nMinLen) nY2=nY1+nMinLen;
1520 }
1521 if (nY2>nOutMax) {
1522 nY2=nOutMax;
1523 if (nY1>nY2-nMinLen) nY1=nY2-nMinLen;
1524 }
1525 }
1526
1527 maRef1.setX(aCenter.X() );
1528 maRef1.setY(nY1 );
1529 maRef2.setX(aCenter.X() );
1530 maRef2.setY(nY2 );
1531
1532 break;
1533 }
1534
1535 case SdrDragMode::Transparence:
1536 case SdrDragMode::Gradient:
1537 case SdrDragMode::Crop:
1538 {
1539 tools::Rectangle aRect(GetMarkedObjBoundRect());
1540 maRef1 = aRect.TopLeft();
1541 maRef2 = aRect.BottomRight();
1542 break;
1543 }
1544 default: break;
1545 }
1546 }
1547
SetRef1(const Point & rPt)1548 void SdrMarkView::SetRef1(const Point& rPt)
1549 {
1550 if(meDragMode == SdrDragMode::Rotate || meDragMode == SdrDragMode::Mirror)
1551 {
1552 maRef1 = rPt;
1553 SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref1);
1554 if(pH)
1555 pH->SetPos(rPt);
1556 }
1557 }
1558
SetRef2(const Point & rPt)1559 void SdrMarkView::SetRef2(const Point& rPt)
1560 {
1561 if(meDragMode == SdrDragMode::Mirror)
1562 {
1563 maRef2 = rPt;
1564 SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref2);
1565 if(pH)
1566 pH->SetPos(rPt);
1567 }
1568 }
1569
GetSfxViewShell() const1570 SfxViewShell* SdrMarkView::GetSfxViewShell() const
1571 {
1572 return SfxViewShell::Current();
1573 }
1574
CheckMarked()1575 void SdrMarkView::CheckMarked()
1576 {
1577 for (size_t nm=GetMarkedObjectCount(); nm>0;) {
1578 --nm;
1579 SdrMark* pM = GetSdrMarkByIndex(nm);
1580 SdrObject* pObj = pM->GetMarkedSdrObj();
1581 SdrPageView* pPV = pM->GetPageView();
1582 bool bRaus = !pObj || !pPV->IsObjMarkable(pObj);
1583 if (bRaus)
1584 {
1585 GetMarkedObjectListWriteAccess().DeleteMark(nm);
1586 }
1587 else
1588 {
1589 if (!IsGluePointEditMode()) { // selected glue points only in GlueEditMode
1590 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
1591 rPts.clear();
1592 }
1593 }
1594 }
1595
1596 // at least reset the remembered BoundRect to prevent handle
1597 // generation if bForceFrameHandles is TRUE.
1598 mbMarkedObjRectDirty = true;
1599 }
1600
SetMarkRects()1601 void SdrMarkView::SetMarkRects()
1602 {
1603 SdrPageView* pPV = GetSdrPageView();
1604
1605 if(pPV)
1606 {
1607 pPV->SetHasMarkedObj(GetMarkedObjectList().TakeSnapRect(pPV, pPV->MarkSnap()));
1608 GetMarkedObjectList().TakeBoundRect(pPV, pPV->MarkBound());
1609 }
1610 }
1611
SetFrameHandles(bool bOn)1612 void SdrMarkView::SetFrameHandles(bool bOn)
1613 {
1614 if (bOn!=mbForceFrameHandles) {
1615 bool bOld=ImpIsFrameHandles();
1616 mbForceFrameHandles=bOn;
1617 bool bNew=ImpIsFrameHandles();
1618 if (bNew!=bOld) {
1619 AdjustMarkHdl();
1620 MarkListHasChanged();
1621 }
1622 }
1623 }
1624
SetEditMode(SdrViewEditMode eMode)1625 void SdrMarkView::SetEditMode(SdrViewEditMode eMode)
1626 {
1627 if (eMode!=meEditMode) {
1628 bool bGlue0=meEditMode==SdrViewEditMode::GluePointEdit;
1629 bool bEdge0=static_cast<SdrCreateView*>(this)->IsEdgeTool();
1630 meEditMode0=meEditMode;
1631 meEditMode=eMode;
1632 bool bGlue1=meEditMode==SdrViewEditMode::GluePointEdit;
1633 bool bEdge1=static_cast<SdrCreateView*>(this)->IsEdgeTool();
1634 // avoid flickering when switching between GlueEdit and EdgeTool
1635 if (bGlue1 && !bGlue0) ImpSetGlueVisible2(bGlue1);
1636 if (bEdge1!=bEdge0) ImpSetGlueVisible3(bEdge1);
1637 if (!bGlue1 && bGlue0) ImpSetGlueVisible2(bGlue1);
1638 if (bGlue0 && !bGlue1) UnmarkAllGluePoints();
1639 }
1640 }
1641
1642
IsObjMarkable(SdrObject const * pObj,SdrPageView const * pPV) const1643 bool SdrMarkView::IsObjMarkable(SdrObject const * pObj, SdrPageView const * pPV) const
1644 {
1645 if (pObj)
1646 {
1647 if (pObj->IsMarkProtect() ||
1648 (!mbDesignMode && pObj->IsUnoObj()))
1649 {
1650 // object not selectable or
1651 // SdrUnoObj not in DesignMode
1652 return false;
1653 }
1654 }
1655 return pPV==nullptr || pPV->IsObjMarkable(pObj);
1656 }
1657
IsMarkedObjHit(const Point & rPnt,short nTol) const1658 bool SdrMarkView::IsMarkedObjHit(const Point& rPnt, short nTol) const
1659 {
1660 bool bRet=false;
1661 nTol=ImpGetHitTolLogic(nTol,nullptr);
1662 for (size_t nm=0; nm<GetMarkedObjectCount() && !bRet; ++nm) {
1663 SdrMark* pM=GetSdrMarkByIndex(nm);
1664 bRet = nullptr != CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr);
1665 }
1666 return bRet;
1667 }
1668
PickHandle(const Point & rPnt) const1669 SdrHdl* SdrMarkView::PickHandle(const Point& rPnt) const
1670 {
1671 if (mbSomeObjChgdFlag) { // recalculate handles, if necessary
1672 FlushComeBackTimer();
1673 }
1674 return maHdlList.IsHdlListHit(rPnt);
1675 }
1676
MarkObj(const Point & rPnt,short nTol,bool bToggle,bool bDeep)1677 bool SdrMarkView::MarkObj(const Point& rPnt, short nTol, bool bToggle, bool bDeep)
1678 {
1679 SdrPageView* pPV;
1680 nTol=ImpGetHitTolLogic(nTol,nullptr);
1681 SdrSearchOptions nOptions=SdrSearchOptions::PICKMARKABLE;
1682 if (bDeep) nOptions=nOptions|SdrSearchOptions::DEEP;
1683 SdrObject* pObj = PickObj(rPnt, static_cast<sal_uInt16>(nTol), pPV, nOptions);
1684 if (pObj) {
1685 bool bUnmark=bToggle && IsObjMarked(pObj);
1686 MarkObj(pObj,pPV,bUnmark);
1687 }
1688 return pObj != nullptr;
1689 }
1690
MarkNextObj(bool bPrev)1691 bool SdrMarkView::MarkNextObj(bool bPrev)
1692 {
1693 SdrPageView* pPageView = GetSdrPageView();
1694
1695 if(!pPageView)
1696 {
1697 return false;
1698 }
1699
1700 SortMarkedObjects();
1701 const size_t nMarkCount=GetMarkedObjectCount();
1702 size_t nChgMarkNum = SAL_MAX_SIZE; // number of the MarkEntry we want to replace
1703 size_t nSearchObjNum = bPrev ? 0 : SAL_MAX_SIZE;
1704 if (nMarkCount!=0) {
1705 nChgMarkNum=bPrev ? 0 : nMarkCount-1;
1706 SdrMark* pM=GetSdrMarkByIndex(nChgMarkNum);
1707 OSL_ASSERT(pM!=nullptr);
1708 if (pM->GetMarkedSdrObj() != nullptr)
1709 nSearchObjNum = pM->GetMarkedSdrObj()->GetNavigationPosition();
1710 }
1711
1712 SdrObject* pMarkObj=nullptr;
1713 SdrObjList* pSearchObjList=pPageView->GetObjList();
1714 const size_t nObjCount = pSearchObjList->GetObjCount();
1715 if (nObjCount!=0) {
1716 if (nSearchObjNum>nObjCount) nSearchObjNum=nObjCount;
1717 while (pMarkObj==nullptr && ((!bPrev && nSearchObjNum>0) || (bPrev && nSearchObjNum<nObjCount)))
1718 {
1719 if (!bPrev)
1720 nSearchObjNum--;
1721 SdrObject* pSearchObj = pSearchObjList->GetObjectForNavigationPosition(nSearchObjNum);
1722 if (IsObjMarkable(pSearchObj,pPageView))
1723 {
1724 if (TryToFindMarkedObject(pSearchObj)==SAL_MAX_SIZE)
1725 {
1726 pMarkObj=pSearchObj;
1727 }
1728 }
1729 if (bPrev) nSearchObjNum++;
1730 }
1731 }
1732
1733 if(!pMarkObj)
1734 {
1735 return false;
1736 }
1737
1738 if (nChgMarkNum!=SAL_MAX_SIZE)
1739 {
1740 GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum);
1741 }
1742 MarkObj(pMarkObj,pPageView); // also calls MarkListHasChanged(), AdjustMarkHdl()
1743 return true;
1744 }
1745
MarkNextObj(const Point & rPnt,short nTol,bool bPrev)1746 bool SdrMarkView::MarkNextObj(const Point& rPnt, short nTol, bool bPrev)
1747 {
1748 SortMarkedObjects();
1749 nTol=ImpGetHitTolLogic(nTol,nullptr);
1750 SdrMark* pTopMarkHit=nullptr;
1751 SdrMark* pBtmMarkHit=nullptr;
1752 size_t nTopMarkHit=0;
1753 size_t nBtmMarkHit=0;
1754 // find topmost of the selected objects that is hit by rPnt
1755 const size_t nMarkCount=GetMarkedObjectCount();
1756 for (size_t nm=nMarkCount; nm>0 && pTopMarkHit==nullptr;) {
1757 --nm;
1758 SdrMark* pM=GetSdrMarkByIndex(nm);
1759 if(CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr))
1760 {
1761 pTopMarkHit=pM;
1762 nTopMarkHit=nm;
1763 }
1764 }
1765 // nothing found, in this case, just select an object
1766 if (pTopMarkHit==nullptr) return MarkObj(rPnt,sal_uInt16(nTol));
1767
1768 SdrObject* pTopObjHit=pTopMarkHit->GetMarkedSdrObj();
1769 SdrObjList* pObjList=pTopObjHit->getParentSdrObjListFromSdrObject();
1770 SdrPageView* pPV=pTopMarkHit->GetPageView();
1771 // find lowermost of the selected objects that is hit by rPnt
1772 // and is placed on the same PageView as pTopMarkHit
1773 for (size_t nm=0; nm<nMarkCount && pBtmMarkHit==nullptr; ++nm) {
1774 SdrMark* pM=GetSdrMarkByIndex(nm);
1775 SdrPageView* pPV2=pM->GetPageView();
1776 if (pPV2==pPV && CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pPV2,SdrSearchOptions::NONE,nullptr))
1777 {
1778 pBtmMarkHit=pM;
1779 nBtmMarkHit=nm;
1780 }
1781 }
1782 if (pBtmMarkHit==nullptr) { pBtmMarkHit=pTopMarkHit; nBtmMarkHit=nTopMarkHit; }
1783 SdrObject* pBtmObjHit=pBtmMarkHit->GetMarkedSdrObj();
1784 const size_t nObjCount = pObjList->GetObjCount();
1785
1786 size_t nSearchBeg(0);
1787 E3dScene* pScene(nullptr);
1788 SdrObject* pObjHit(bPrev ? pBtmObjHit : pTopObjHit);
1789 bool bRemap =
1790 nullptr != dynamic_cast< const E3dCompoundObject* >(pObjHit);
1791 if (bRemap)
1792 {
1793 pScene = dynamic_cast< E3dScene* >(pObjHit->getParentSdrObjectFromSdrObject());
1794 bRemap = nullptr != pScene;
1795 }
1796
1797 if(bPrev)
1798 {
1799 sal_uInt32 nOrdNumBtm(pBtmObjHit->GetOrdNum());
1800
1801 if(bRemap)
1802 {
1803 nOrdNumBtm = pScene->RemapOrdNum(nOrdNumBtm);
1804 }
1805
1806 nSearchBeg = nOrdNumBtm + 1;
1807 }
1808 else
1809 {
1810 sal_uInt32 nOrdNumTop(pTopObjHit->GetOrdNum());
1811
1812 if(bRemap)
1813 {
1814 nOrdNumTop = pScene->RemapOrdNum(nOrdNumTop);
1815 }
1816
1817 nSearchBeg = nOrdNumTop;
1818 }
1819
1820 size_t no=nSearchBeg;
1821 SdrObject* pFndObj=nullptr;
1822 while (pFndObj==nullptr && ((!bPrev && no>0) || (bPrev && no<nObjCount))) {
1823 if (!bPrev) no--;
1824 SdrObject* pObj;
1825
1826 if(bRemap)
1827 {
1828 pObj = pObjList->GetObj(pScene->RemapOrdNum(no));
1829 }
1830 else
1831 {
1832 pObj = pObjList->GetObj(no);
1833 }
1834
1835 if (CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr))
1836 {
1837 if (TryToFindMarkedObject(pObj)==SAL_MAX_SIZE) {
1838 pFndObj=pObj;
1839 } else {
1840 // TODO: for performance reasons set on to Top or Btm, if necessary
1841 }
1842 }
1843 if (bPrev) no++;
1844 }
1845 if (pFndObj!=nullptr)
1846 {
1847 GetMarkedObjectListWriteAccess().DeleteMark(bPrev?nBtmMarkHit:nTopMarkHit);
1848 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj,pPV));
1849 MarkListHasChanged();
1850 AdjustMarkHdl();
1851 }
1852 return pFndObj!=nullptr;
1853 }
1854
MarkObj(const tools::Rectangle & rRect,bool bUnmark)1855 void SdrMarkView::MarkObj(const tools::Rectangle& rRect, bool bUnmark)
1856 {
1857 bool bFnd=false;
1858 tools::Rectangle aR(rRect);
1859 SdrObjList* pObjList;
1860 BrkAction();
1861 SdrPageView* pPV = GetSdrPageView();
1862
1863 if(pPV)
1864 {
1865 pObjList=pPV->GetObjList();
1866 tools::Rectangle aFrm1(aR);
1867 const size_t nObjCount = pObjList->GetObjCount();
1868 for (size_t nO=0; nO<nObjCount; ++nO) {
1869 SdrObject* pObj=pObjList->GetObj(nO);
1870 tools::Rectangle aRect(pObj->GetCurrentBoundRect());
1871 if (aFrm1.IsInside(aRect)) {
1872 if (!bUnmark) {
1873 if (IsObjMarkable(pObj,pPV))
1874 {
1875 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
1876 bFnd=true;
1877 }
1878 } else {
1879 const size_t nPos=TryToFindMarkedObject(pObj);
1880 if (nPos!=SAL_MAX_SIZE)
1881 {
1882 GetMarkedObjectListWriteAccess().DeleteMark(nPos);
1883 bFnd=true;
1884 }
1885 }
1886 }
1887 }
1888 }
1889 if (bFnd) {
1890 SortMarkedObjects();
1891 MarkListHasChanged();
1892 AdjustMarkHdl();
1893 }
1894 }
1895
1896 namespace {
1897
collectUIInformation(const SdrObject * pObj)1898 void collectUIInformation(const SdrObject* pObj)
1899 {
1900 EventDescription aDescription;
1901 aDescription.aAction = "SELECT";
1902 aDescription.aParent = "MainWindow";
1903 aDescription.aKeyWord = "CurrentApp";
1904
1905 if (!pObj->GetName().isEmpty())
1906 aDescription.aParameters = {{"OBJECT", pObj->GetName()}};
1907 else
1908 aDescription.aParameters = {{"OBJECT", "Unnamed_Obj_" + OUString::number(pObj->GetOrdNum())}};
1909
1910 UITestLogger::getInstance().logEvent(aDescription);
1911 }
1912
1913 }
1914
MarkObj(SdrObject * pObj,SdrPageView * pPV,bool bUnmark,bool bImpNoSetMarkHdl)1915 void SdrMarkView::MarkObj(SdrObject* pObj, SdrPageView* pPV, bool bUnmark, bool bImpNoSetMarkHdl)
1916 {
1917 if (pObj!=nullptr && pPV!=nullptr && IsObjMarkable(pObj, pPV)) {
1918 BrkAction();
1919 if (!bUnmark)
1920 {
1921 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
1922 collectUIInformation(pObj);
1923 }
1924 else
1925 {
1926 const size_t nPos=TryToFindMarkedObject(pObj);
1927 if (nPos!=SAL_MAX_SIZE)
1928 {
1929 GetMarkedObjectListWriteAccess().DeleteMark(nPos);
1930 }
1931 }
1932 if (!bImpNoSetMarkHdl) {
1933 MarkListHasChanged();
1934 AdjustMarkHdl();
1935 }
1936 }
1937 }
1938
IsObjMarked(SdrObject const * pObj) const1939 bool SdrMarkView::IsObjMarked(SdrObject const * pObj) const
1940 {
1941 return TryToFindMarkedObject(pObj)!=SAL_MAX_SIZE;
1942 }
1943
GetMarkHdlSizePixel() const1944 sal_uInt16 SdrMarkView::GetMarkHdlSizePixel() const
1945 {
1946 return maHdlList.GetHdlSize()*2+1;
1947 }
1948
SetMarkHdlSizePixel(sal_uInt16 nSiz)1949 void SdrMarkView::SetMarkHdlSizePixel(sal_uInt16 nSiz)
1950 {
1951 if (nSiz<3) nSiz=3;
1952 nSiz/=2;
1953 if (nSiz!=maHdlList.GetHdlSize()) {
1954 maHdlList.SetHdlSize(nSiz);
1955 }
1956 }
1957
getPossibleGridOffsetForSdrObject(basegfx::B2DVector & rOffset,const SdrObject * pObj,const SdrPageView * pPV) const1958 bool SdrMarkView::getPossibleGridOffsetForSdrObject(
1959 basegfx::B2DVector& rOffset,
1960 const SdrObject* pObj,
1961 const SdrPageView* pPV) const
1962 {
1963 if(nullptr == pObj || nullptr == pPV)
1964 {
1965 return false;
1966 }
1967
1968 const OutputDevice* pOutputDevice(GetFirstOutputDevice());
1969
1970 if(nullptr == pOutputDevice)
1971 {
1972 return false;
1973 }
1974
1975 const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
1976
1977 if(nullptr == pSdrPageWindow)
1978 {
1979 return false;
1980 }
1981
1982 const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
1983
1984 if(!rObjectContact.supportsGridOffsets())
1985 {
1986 return false;
1987 }
1988
1989 const sdr::contact::ViewObjectContact& rVOC(pObj->GetViewContact().GetViewObjectContact(
1990 const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
1991
1992 rObjectContact.calculateGridOffsetForViewOjectContact(rOffset, rVOC);
1993
1994 return !rOffset.equalZero();
1995 }
1996
getPossibleGridOffsetForPosition(basegfx::B2DVector & rOffset,const basegfx::B2DPoint & rPoint,const SdrPageView * pPV) const1997 bool SdrMarkView::getPossibleGridOffsetForPosition(
1998 basegfx::B2DVector& rOffset,
1999 const basegfx::B2DPoint& rPoint,
2000 const SdrPageView* pPV) const
2001 {
2002 if(nullptr == pPV)
2003 {
2004 return false;
2005 }
2006
2007 const OutputDevice* pOutputDevice(GetFirstOutputDevice());
2008
2009 if(nullptr == pOutputDevice)
2010 {
2011 return false;
2012 }
2013
2014 const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
2015
2016 if(nullptr == pSdrPageWindow)
2017 {
2018 return false;
2019 }
2020
2021 const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
2022
2023 if(!rObjectContact.supportsGridOffsets())
2024 {
2025 return false;
2026 }
2027
2028 rObjectContact.calculateGridOffsetForB2DRange(rOffset, basegfx::B2DRange(rPoint));
2029
2030 return !rOffset.equalZero();
2031 }
2032
CheckSingleSdrObjectHit(const Point & rPnt,sal_uInt16 nTol,SdrObject * pObj,SdrPageView * pPV,SdrSearchOptions nOptions,const SdrLayerIDSet * pMVisLay) const2033 SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
2034 {
2035 if(((nOptions & SdrSearchOptions::IMPISMASTER) && pObj->IsNotVisibleAsMaster()) || (!pObj->IsVisible()))
2036 {
2037 return nullptr;
2038 }
2039
2040 const bool bCheckIfMarkable(nOptions & SdrSearchOptions::TESTMARKABLE);
2041 const bool bDeep(nOptions & SdrSearchOptions::DEEP);
2042 const bool bOLE(dynamic_cast< const SdrOle2Obj* >(pObj) != nullptr);
2043 const bool bTXT(dynamic_cast<const SdrTextObj*>( pObj) != nullptr && static_cast<SdrTextObj*>(pObj)->IsTextFrame());
2044 SdrObject* pRet=nullptr;
2045 tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2046
2047 // add possible GridOffset to up-to-now view-independent BoundRect data
2048 basegfx::B2DVector aGridOffset(0.0, 0.0);
2049 if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pPV))
2050 {
2051 aRect += Point(
2052 basegfx::fround(aGridOffset.getX()),
2053 basegfx::fround(aGridOffset.getY()));
2054 }
2055
2056 sal_uInt16 nTol2(nTol);
2057
2058 // double tolerance for OLE, text frames and objects in
2059 // active text edit
2060 if(bOLE || bTXT || pObj==static_cast<const SdrObjEditView*>(this)->GetTextEditObject())
2061 {
2062 nTol2*=2;
2063 }
2064
2065 aRect.AdjustLeft( -nTol2 ); // add 1 tolerance for all objects
2066 aRect.AdjustTop( -nTol2 );
2067 aRect.AdjustRight(nTol2 );
2068 aRect.AdjustBottom(nTol2 );
2069
2070 if (aRect.IsInside(rPnt))
2071 {
2072 if (!bCheckIfMarkable || IsObjMarkable(pObj,pPV))
2073 {
2074 SdrObjList* pOL=pObj->GetSubList();
2075
2076 if (pOL!=nullptr && pOL->GetObjCount()!=0)
2077 {
2078 SdrObject* pTmpObj;
2079 // adjustment hit point for virtual objects
2080 Point aPnt( rPnt );
2081
2082 if ( dynamic_cast<const SdrVirtObj*>( pObj) != nullptr )
2083 {
2084 Point aOffset = static_cast<SdrVirtObj*>(pObj)->GetOffset();
2085 aPnt.Move( -aOffset.X(), -aOffset.Y() );
2086 }
2087
2088 pRet=CheckSingleSdrObjectHit(aPnt,nTol,pOL,pPV,nOptions,pMVisLay,pTmpObj);
2089 }
2090 else
2091 {
2092 if(!pMVisLay || pMVisLay->IsSet(pObj->GetLayer()))
2093 {
2094 pRet = SdrObjectPrimitiveHit(*pObj, rPnt, nTol2, *pPV, &pPV->GetVisibleLayers(), false);
2095 }
2096 }
2097 }
2098 }
2099
2100 if (!bDeep && pRet!=nullptr)
2101 {
2102 pRet=pObj;
2103 }
2104
2105 return pRet;
2106 }
2107
CheckSingleSdrObjectHit(const Point & rPnt,sal_uInt16 nTol,SdrObjList const * pOL,SdrPageView * pPV,SdrSearchOptions nOptions,const SdrLayerIDSet * pMVisLay,SdrObject * & rpRootObj) const2108 SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj) const
2109 {
2110 return (*this).CheckSingleSdrObjectHit(rPnt,nTol,pOL,pPV,nOptions,pMVisLay,rpRootObj,nullptr);
2111 }
CheckSingleSdrObjectHit(const Point & rPnt,sal_uInt16 nTol,SdrObjList const * pOL,SdrPageView * pPV,SdrSearchOptions nOptions,const SdrLayerIDSet * pMVisLay,SdrObject * & rpRootObj,const SdrMarkList * pMarkList) const2112 SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj,const SdrMarkList * pMarkList) const
2113 {
2114 SdrObject* pRet=nullptr;
2115 rpRootObj=nullptr;
2116 if (pOL!=nullptr)
2117 {
2118 const bool bRemap(
2119 nullptr != pOL->getSdrObjectFromSdrObjList()
2120 && nullptr != dynamic_cast< const E3dScene* >(pOL->getSdrObjectFromSdrObjList()));
2121 const E3dScene* pRemapScene(bRemap ? static_cast< E3dScene* >(pOL->getSdrObjectFromSdrObjList()) : nullptr);
2122 const size_t nObjCount(pOL->GetObjCount());
2123 size_t nObjNum(nObjCount);
2124
2125 while (pRet==nullptr && nObjNum>0)
2126 {
2127 nObjNum--;
2128 SdrObject* pObj;
2129
2130 if(bRemap)
2131 {
2132 pObj = pOL->GetObj(pRemapScene->RemapOrdNum(nObjNum));
2133 }
2134 else
2135 {
2136 pObj = pOL->GetObj(nObjNum);
2137 }
2138 if (nOptions & SdrSearchOptions::BEFOREMARK)
2139 {
2140 if (pMarkList!=nullptr)
2141 {
2142 if ((*pMarkList).FindObject(pObj)!=SAL_MAX_SIZE)
2143 {
2144 return nullptr;
2145 }
2146 }
2147 }
2148 pRet=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,pMVisLay);
2149 if (pRet!=nullptr) rpRootObj=pObj;
2150 }
2151 }
2152 return pRet;
2153 }
2154
PickObj(const Point & rPnt,short nTol,SdrPageView * & rpPV,SdrSearchOptions nOptions) const2155 SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
2156 {
2157 return PickObj(rPnt, nTol, rpPV, nOptions, nullptr);
2158 }
2159
PickObj(const Point & rPnt,short nTol,SdrPageView * & rpPV,SdrSearchOptions nOptions,SdrObject ** ppRootObj,bool * pbHitPassDirect) const2160 SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions, SdrObject** ppRootObj, bool* pbHitPassDirect) const
2161 { // TODO: lacks a Pass2,Pass3
2162 SortMarkedObjects();
2163 if (ppRootObj!=nullptr) *ppRootObj=nullptr;
2164 if (pbHitPassDirect!=nullptr) *pbHitPassDirect=true;
2165 SdrObject* pRet = nullptr;
2166 rpPV=nullptr;
2167 bool bMarked(nOptions & SdrSearchOptions::MARKED);
2168 bool bMasters=!bMarked && bool(nOptions & SdrSearchOptions::ALSOONMASTER);
2169 // nOptions & SdrSearchOptions::NEXT: n.i.
2170 // nOptions & SdrSearchOptions::PASS2BOUND: n.i.
2171 // nOptions & SdrSearchOptions::PASS3NEAREST// n.i.
2172 if (nTol<0) nTol=ImpGetHitTolLogic(nTol,nullptr);
2173 SdrObject* pObj=nullptr;
2174 SdrObject* pHitObj=nullptr;
2175 SdrPageView* pPV=nullptr;
2176 if (static_cast<const SdrObjEditView*>(this)->IsTextEditFrameHit(rPnt)) {
2177 pObj=static_cast<const SdrObjEditView*>(this)->GetTextEditObject();
2178 pHitObj=pObj;
2179 pPV=static_cast<const SdrObjEditView*>(this)->GetTextEditPageView();
2180 }
2181 if (bMarked) {
2182 const size_t nMrkCnt=GetMarkedObjectCount();
2183 size_t nMrkNum=nMrkCnt;
2184 while (pHitObj==nullptr && nMrkNum>0) {
2185 nMrkNum--;
2186 SdrMark* pM=GetSdrMarkByIndex(nMrkNum);
2187 pObj=pM->GetMarkedSdrObj();
2188 pPV=pM->GetPageView();
2189 pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,nullptr);
2190 }
2191 }
2192 else
2193 {
2194 pPV = GetSdrPageView();
2195
2196 if(pPV)
2197 {
2198 SdrPage* pPage=pPV->GetPage();
2199 sal_uInt16 nPgCount=1;
2200
2201 if(bMasters && pPage->TRG_HasMasterPage())
2202 {
2203 nPgCount++;
2204 }
2205 bool bWholePage(nOptions & SdrSearchOptions::WHOLEPAGE);
2206 bool bExtraPassForWholePage=bWholePage && pPage!=pPV->GetObjList();
2207 if (bExtraPassForWholePage) nPgCount++; // First search in AktObjList, then on the entire page
2208 sal_uInt16 nPgNum=nPgCount;
2209 while (pHitObj==nullptr && nPgNum>0) {
2210 SdrSearchOptions nTmpOptions=nOptions;
2211 nPgNum--;
2212 const SdrLayerIDSet* pMVisLay=nullptr;
2213 SdrObjList* pObjList=nullptr;
2214 if (pbHitPassDirect!=nullptr) *pbHitPassDirect = true;
2215 if (nPgNum>=nPgCount-1 || (bExtraPassForWholePage && nPgNum>=nPgCount-2))
2216 {
2217 pObjList=pPV->GetObjList();
2218 if (bExtraPassForWholePage && nPgNum==nPgCount-2) {
2219 pObjList=pPage;
2220 if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
2221 }
2222 }
2223 else
2224 {
2225 // otherwise MasterPage
2226 SdrPage& rMasterPage = pPage->TRG_GetMasterPage();
2227 pMVisLay = &pPage->TRG_GetMasterPageVisibleLayers();
2228 pObjList = &rMasterPage;
2229
2230 if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
2231 nTmpOptions=nTmpOptions | SdrSearchOptions::IMPISMASTER;
2232 }
2233 pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObjList,pPV,nTmpOptions,pMVisLay,pObj,&(GetMarkedObjectList()));
2234 }
2235 }
2236 }
2237 if (pHitObj!=nullptr) {
2238 if (ppRootObj!=nullptr) *ppRootObj=pObj;
2239 if (nOptions & SdrSearchOptions::DEEP) pObj=pHitObj;
2240 if (nOptions & SdrSearchOptions::TESTTEXTEDIT) {
2241 if (!pObj->HasTextEdit() || pPV->GetLockedLayers().IsSet(pObj->GetLayer())) {
2242 pObj=nullptr;
2243 }
2244 }
2245 if (pObj!=nullptr && (nOptions & SdrSearchOptions::TESTMACRO)) {
2246 SdrObjMacroHitRec aHitRec;
2247 aHitRec.aPos=rPnt;
2248 aHitRec.nTol=nTol;
2249 aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
2250 aHitRec.pPageView=pPV;
2251 if (!pObj->HasMacro() || !pObj->IsMacroHit(aHitRec)) pObj=nullptr;
2252 }
2253 if (pObj!=nullptr) {
2254 pRet=pObj;
2255 rpPV=pPV;
2256 }
2257 }
2258 return pRet;
2259 }
2260
PickMarkedObj(const Point & rPnt,SdrObject * & rpObj,SdrPageView * & rpPV,SdrSearchOptions nOptions) const2261 bool SdrMarkView::PickMarkedObj(const Point& rPnt, SdrObject*& rpObj, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
2262 {
2263 SortMarkedObjects();
2264 const bool bBoundCheckOn2ndPass(nOptions & SdrSearchOptions::PASS2BOUND);
2265 rpObj=nullptr;
2266 rpPV=nullptr;
2267 const size_t nMarkCount=GetMarkedObjectCount();
2268 for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
2269 --nMarkNum;
2270 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
2271 SdrPageView* pPV=pM->GetPageView();
2272 SdrObject* pObj=pM->GetMarkedSdrObj();
2273 if (CheckSingleSdrObjectHit(rPnt,mnHitTolLog,pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr)) {
2274 rpObj=pObj;
2275 rpPV=pPV;
2276 return true;
2277 }
2278 }
2279 if (bBoundCheckOn2ndPass) {
2280 for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
2281 --nMarkNum;
2282 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
2283 SdrPageView* pPV=pM->GetPageView();
2284 SdrObject* pObj=pM->GetMarkedSdrObj();
2285 tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2286 aRect.AdjustLeft( -mnHitTolLog );
2287 aRect.AdjustTop( -mnHitTolLog );
2288 aRect.AdjustRight(mnHitTolLog );
2289 aRect.AdjustBottom(mnHitTolLog );
2290 if (aRect.IsInside(rPnt)) {
2291 rpObj=pObj;
2292 rpPV=pPV;
2293 return true;
2294 }
2295 }
2296 }
2297 return false;
2298 }
2299
2300
UnmarkAllObj(SdrPageView const * pPV)2301 void SdrMarkView::UnmarkAllObj(SdrPageView const * pPV)
2302 {
2303 if (GetMarkedObjectCount()!=0) {
2304 BrkAction();
2305 if (pPV!=nullptr)
2306 {
2307 GetMarkedObjectListWriteAccess().DeletePageView(*pPV);
2308 }
2309 else
2310 {
2311 GetMarkedObjectListWriteAccess().Clear();
2312 }
2313 mpMarkedObj=nullptr;
2314 mpMarkedPV=nullptr;
2315 MarkListHasChanged();
2316 AdjustMarkHdl();
2317 }
2318 }
2319
MarkAllObj(SdrPageView * pPV)2320 void SdrMarkView::MarkAllObj(SdrPageView* pPV)
2321 {
2322 BrkAction();
2323
2324 if(!pPV)
2325 {
2326 pPV = GetSdrPageView();
2327 }
2328
2329 // #i69171# pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting
2330 // other files
2331 if(pPV)
2332 {
2333 const bool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*pPV));
2334
2335 if(bMarkChg)
2336 {
2337 MarkListHasChanged();
2338 }
2339 }
2340
2341 if(GetMarkedObjectCount())
2342 {
2343 AdjustMarkHdl();
2344 }
2345 }
2346
AdjustMarkHdl(SfxViewShell * pOtherShell)2347 void SdrMarkView::AdjustMarkHdl(SfxViewShell* pOtherShell)
2348 {
2349 CheckMarked();
2350 SetMarkRects();
2351 SetMarkHandles(pOtherShell);
2352 }
2353
2354 // BoundRect in model coordinates, no GridOffset added
GetMarkedObjBoundRect() const2355 tools::Rectangle SdrMarkView::GetMarkedObjBoundRect() const
2356 {
2357 tools::Rectangle aRect;
2358 for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
2359 SdrMark* pM=GetSdrMarkByIndex(nm);
2360 SdrObject* pO=pM->GetMarkedSdrObj();
2361 tools::Rectangle aR1(pO->GetCurrentBoundRect());
2362 if (aRect.IsEmpty()) aRect=aR1;
2363 else aRect.Union(aR1);
2364 }
2365 return aRect;
2366 }
2367
2368 // ObjRect in model coordinates, no GridOffset added
GetMarkedObjRect() const2369 const tools::Rectangle& SdrMarkView::GetMarkedObjRect() const
2370 {
2371 if (mbMarkedObjRectDirty) {
2372 const_cast<SdrMarkView*>(this)->mbMarkedObjRectDirty=false;
2373 tools::Rectangle aRect;
2374 for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
2375 SdrMark* pM=GetSdrMarkByIndex(nm);
2376 SdrObject* pO = pM->GetMarkedSdrObj();
2377 if (!pO)
2378 continue;
2379 tools::Rectangle aR1(pO->GetSnapRect());
2380 if (aRect.IsEmpty()) aRect=aR1;
2381 else aRect.Union(aR1);
2382 }
2383 const_cast<SdrMarkView*>(this)->maMarkedObjRect=aRect;
2384 }
2385 return maMarkedObjRect;
2386 }
2387
2388
ImpGetDescriptionString(const char * pStrCacheID,ImpGetDescriptionOptions nOpt) const2389 OUString SdrMarkView::ImpGetDescriptionString(const char* pStrCacheID, ImpGetDescriptionOptions nOpt) const
2390 {
2391 OUString sStr = SvxResId(pStrCacheID);
2392 const sal_Int32 nPos = sStr.indexOf("%1");
2393
2394 if(nPos != -1)
2395 {
2396 if(nOpt == ImpGetDescriptionOptions::POINTS)
2397 {
2398 sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedPoints());
2399 }
2400 else if(nOpt == ImpGetDescriptionOptions::GLUEPOINTS)
2401 {
2402 sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedGluePoints());
2403 }
2404 else
2405 {
2406 sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedObjects());
2407 }
2408 }
2409
2410 return sStr.replaceFirst("%2", "0");
2411 }
2412
2413
EnterMarkedGroup()2414 void SdrMarkView::EnterMarkedGroup()
2415 {
2416 // We enter only the first group found (in only one PageView), because
2417 // PageView::EnterGroup calls an AdjustMarkHdl.
2418 // TODO: I'll have to prevent that via a flag.
2419 SdrPageView* pPV = GetSdrPageView();
2420
2421 if(pPV)
2422 {
2423 bool bEnter=false;
2424 for (size_t nm = GetMarkedObjectCount(); nm > 0 && !bEnter;)
2425 {
2426 --nm;
2427 SdrMark* pM=GetSdrMarkByIndex(nm);
2428 if (pM->GetPageView()==pPV) {
2429 SdrObject* pObj=pM->GetMarkedSdrObj();
2430 if (pObj->IsGroupObject()) {
2431 if (pPV->EnterGroup(pObj)) {
2432 bEnter=true;
2433 }
2434 }
2435 }
2436 }
2437 }
2438 }
2439
2440
MarkListHasChanged()2441 void SdrMarkView::MarkListHasChanged()
2442 {
2443 GetMarkedObjectListWriteAccess().SetNameDirty();
2444 maSdrViewSelection.SetEdgesOfMarkedNodesDirty();
2445
2446 mbMarkedObjRectDirty=true;
2447 mbMarkedPointsRectsDirty=true;
2448 #ifdef DBG_UTIL
2449 if (mpItemBrowser!=nullptr) mpItemBrowser->SetDirty();
2450 #endif
2451 bool bOneEdgeMarked=false;
2452 if (GetMarkedObjectCount()==1) {
2453 const SdrObject* pObj=GetMarkedObjectByIndex(0);
2454 if (pObj->GetObjInventor()==SdrInventor::Default) {
2455 sal_uInt16 nIdent=pObj->GetObjIdentifier();
2456 bOneEdgeMarked=nIdent==OBJ_EDGE;
2457 }
2458 }
2459 ImpSetGlueVisible4(bOneEdgeMarked);
2460 }
2461
2462
SetMoveOutside(bool bOn)2463 void SdrMarkView::SetMoveOutside(bool bOn)
2464 {
2465 maHdlList.SetMoveOutside(bOn);
2466 }
2467
SetDesignMode(bool bOn)2468 void SdrMarkView::SetDesignMode( bool bOn )
2469 {
2470 if ( mbDesignMode != bOn )
2471 {
2472 mbDesignMode = bOn;
2473 SdrPageView* pPageView = GetSdrPageView();
2474 if ( pPageView )
2475 pPageView->SetDesignMode( bOn );
2476 }
2477 }
2478
2479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2480