1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdmrkv.hxx>
22 #include <svx/svdview.hxx>
23 #include <svx/svdpagv.hxx>
24 #include <svx/svdpage.hxx>
25 #include <svx/svdotable.hxx>
26 #include <svx/svdomedia.hxx>
28 #include <osl/diagnose.h>
29 #include <osl/thread.h>
30 #include <rtl/strbuf.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <svx/xfillit0.hxx>
33 #include <svx/xflgrit.hxx>
34 #include "gradtrns.hxx"
35 #include <svx/xflftrit.hxx>
36 #include <svx/dialmgr.hxx>
37 #include <svx/strings.hrc>
38 #include <svx/svdundo.hxx>
39 #include <svx/svdopath.hxx>
40 #include <svx/scene3d.hxx>
41 #include <svx/svdovirt.hxx>
42 #include <sdr/overlay/overlayrollingrectangle.hxx>
43 #include <svx/sdr/contact/displayinfo.hxx>
44 #include <svx/sdr/contact/objectcontact.hxx>
45 #include <svx/sdr/overlay/overlaymanager.hxx>
46 #include <svx/sdr/overlay/overlayselection.hxx>
47 #include <svx/sdr/contact/viewcontact.hxx>
48 #include <svx/sdr/contact/viewobjectcontact.hxx>
49 #include <svx/sdrpaintwindow.hxx>
50 #include <svx/sdrpagewindow.hxx>
51 #include <svx/sdrhittesthelper.hxx>
52 #include <vcl/uitest/logger.hxx>
53 #include <vcl/uitest/eventdescription.hxx>
54 #include <vcl/window.hxx>
55 #include <o3tl/string_view.hxx>
57 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
58 #include <comphelper/lok.hxx>
59 #include <sfx2/lokhelper.hxx>
60 #include <sfx2/lokcomponenthelpers.hxx>
61 #include <sfx2/viewsh.hxx>
62 #include <svtools/optionsdrawinglayer.hxx>
64 #include <drawinglayer/processor2d/textextractor2d.hxx>
68 #include <com/sun/star/frame/XController.hpp>
69 #include <com/sun/star/view/XSelectionSupplier.hpp>
71 #include <boost/property_tree/json_parser.hpp>
73 using namespace com::sun::star
;
75 // Migrate Marking of Objects, Points and GluePoints
77 class ImplMarkingOverlay
80 sdr::overlay::OverlayObjectList maObjects
;
82 // The remembered second position in logical coordinates
83 basegfx::B2DPoint maSecondPosition
;
85 // A flag to remember if the action is for unmarking.
89 ImplMarkingOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
, bool bUnmarking
);
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.
95 void SetSecondPosition(const basegfx::B2DPoint
& rNewPosition
);
96 bool IsUnmarking() const { return mbUnmarking
; }
99 ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
, bool bUnmarking
)
100 : maSecondPosition(rStartPos
),
101 mbUnmarking(bUnmarking
)
103 if (comphelper::LibreOfficeKit::isActive())
104 return; // We do client-side object manipulation with the Kit API
106 for(sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
108 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
109 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
111 if (xTargetOverlay
.is())
113 std::unique_ptr
<sdr::overlay::OverlayRollingRectangleStriped
> pNew(new sdr::overlay::OverlayRollingRectangleStriped(
114 rStartPos
, rStartPos
, false));
115 xTargetOverlay
->add(*pNew
);
116 maObjects
.append(std::move(pNew
));
121 void ImplMarkingOverlay::SetSecondPosition(const basegfx::B2DPoint
& rNewPosition
)
123 if(rNewPosition
!= maSecondPosition
)
125 // apply to OverlayObjects
126 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
128 sdr::overlay::OverlayRollingRectangleStriped
& rCandidate
= static_cast< sdr::overlay::OverlayRollingRectangleStriped
&>(maObjects
.getOverlayObject(a
));
129 rCandidate
.setSecondPosition(rNewPosition
);
132 // remember new position
133 maSecondPosition
= rNewPosition
;
137 class MarkingSubSelectionOverlay
139 sdr::overlay::OverlayObjectList maObjects
;
142 MarkingSubSelectionOverlay(const SdrPaintView
& rView
, std::vector
<basegfx::B2DRectangle
> const & rSelections
)
144 if (comphelper::LibreOfficeKit::isActive())
145 return; // We do client-side object manipulation with the Kit API
147 for (sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
149 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
150 const rtl::Reference
<sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
152 if (xTargetOverlay
.is())
154 const Color aHighlightColor
= SvtOptionsDrawinglayer::getHilightColor();
156 std::unique_ptr
<sdr::overlay::OverlaySelection
> pNew
=
157 std::make_unique
<sdr::overlay::OverlaySelection
>(
158 sdr::overlay::OverlayType::Transparent
,
159 aHighlightColor
, std::vector(rSelections
), false);
161 xTargetOverlay
->add(*pNew
);
162 maObjects
.append(std::move(pNew
));
168 SdrMarkView::SdrMarkView(SdrModel
& rSdrModel
, OutputDevice
* pOut
)
169 : SdrSnapView(rSdrModel
, pOut
)
170 , mpMarkedObj(nullptr)
171 , mpMarkedPV(nullptr)
173 , meDragMode(SdrDragMode::Move
)
174 , meEditMode(SdrViewEditMode::Edit
)
175 , meEditMode0(SdrViewEditMode::Edit
)
176 , mbDesignMode(false)
177 , mbForceFrameHandles(false)
178 , mbPlusHdlAlways(false)
179 , mbInsPolyPoint(false)
180 , mbMarkedObjRectDirty(false)
181 , mbMrkPntDirty(false)
182 , mbMarkedPointsRectsDirty(false)
183 , mbMarkHandlesHidden(false)
191 StartListening(rSdrModel
);
194 SdrMarkView::~SdrMarkView()
196 // Migrate selections
202 void SdrMarkView::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
204 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
206 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
207 SdrHintKind eKind
=pSdrHint
->GetKind();
208 if (eKind
==SdrHintKind::ObjectChange
|| eKind
==SdrHintKind::ObjectInserted
|| eKind
==SdrHintKind::ObjectRemoved
)
210 mbMarkedObjRectDirty
=true;
211 mbMarkedPointsRectsDirty
=true;
214 SdrSnapView::Notify(rBC
,rHint
);
217 void SdrMarkView::ModelHasChanged()
219 SdrPaintView::ModelHasChanged();
220 GetMarkedObjectListWriteAccess().SetNameDirty();
221 mbMarkedObjRectDirty
=true;
222 mbMarkedPointsRectsDirty
=true;
223 // Example: Obj is selected and maMarkedObjectList is sorted.
224 // In another View 2, the ObjOrder is changed (e. g. MovToTop())
225 // Then we need to re-sort MarkList.
226 GetMarkedObjectListWriteAccess().SetUnsorted();
230 SdrView
* pV
=static_cast<SdrView
*>(this);
231 if (pV
!=nullptr && !pV
->IsDragObj() && !pV
->IsInsObjPoint()) {
235 if (comphelper::LibreOfficeKit::isActive())
236 modelHasChangedLOKit();
239 void SdrMarkView::modelHasChangedLOKit()
241 if (GetMarkedObjectCount() <= 0)
244 //TODO: Is MarkedObjRect valid at this point?
245 tools::Rectangle
aSelection(GetMarkedObjRect());
246 tools::Rectangle
* pResultSelection
;
247 if (aSelection
.IsEmpty())
248 pResultSelection
= nullptr;
251 sal_uInt32 nTotalPaintWindows
= this->PaintWindowCount();
252 if (nTotalPaintWindows
== 1)
254 const OutputDevice
* pOut
= this->GetFirstOutputDevice();
255 const vcl::Window
* pWin
= pOut
? pOut
->GetOwnerWindow() : nullptr;
256 if (pWin
&& pWin
->IsChart())
258 const vcl::Window
* pViewShellWindow
= GetSfxViewShell()->GetEditWindowForActiveOLEObj();
259 if (pViewShellWindow
&& pViewShellWindow
->IsAncestorOf(*pWin
))
261 Point aOffsetPx
= pWin
->GetOffsetPixelFrom(*pViewShellWindow
);
262 Point aLogicOffset
= pWin
->PixelToLogic(aOffsetPx
);
263 aSelection
.Move(aLogicOffset
.getX(), aLogicOffset
.getY());
268 // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
271 if (OutputDevice
* pOutputDevice
= mpMarkedPV
->GetView().GetFirstOutputDevice())
273 if (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
)
274 aSelection
= o3tl::convert(aSelection
, o3tl::Length::mm100
, o3tl::Length::twip
);
278 pResultSelection
= &aSelection
;
282 // Convert to positive X doc-coordinates
283 tools::Long nTmp
= aSelection
.Left();
284 aSelection
.SetLeft(-aSelection
.Right());
285 aSelection
.SetRight(-nTmp
);
289 if (SfxViewShell
* pViewShell
= GetSfxViewShell())
290 SfxLokHelper::notifyInvalidation(pViewShell
, pResultSelection
);
293 bool SdrMarkView::IsAction() const
295 return SdrSnapView::IsAction() || IsMarkObj() || IsMarkPoints() || IsMarkGluePoints();
298 void SdrMarkView::MovAction(const Point
& rPnt
)
300 SdrSnapView::MovAction(rPnt
);
306 else if(IsMarkPoints())
310 else if(IsMarkGluePoints())
312 MovMarkGluePoints(rPnt
);
316 void SdrMarkView::EndAction()
322 else if(IsMarkPoints())
326 else if(IsMarkGluePoints())
331 SdrSnapView::EndAction();
334 void SdrMarkView::BckAction()
336 SdrSnapView::BckAction();
342 void SdrMarkView::BrkAction()
344 SdrSnapView::BrkAction();
350 void SdrMarkView::TakeActionRect(tools::Rectangle
& rRect
) const
352 if(IsMarkObj() || IsMarkPoints() || IsMarkGluePoints())
354 rRect
= tools::Rectangle(maDragStat
.GetStart(), maDragStat
.GetNow());
358 SdrSnapView::TakeActionRect(rRect
);
363 void SdrMarkView::ClearPageView()
366 SdrSnapView::ClearPageView();
369 void SdrMarkView::HideSdrPage()
373 SdrPageView
* pPageView
= GetSdrPageView();
376 // break all creation actions when hiding page (#75081#)
379 // Discard all selections on this page
380 bMrkChg
= GetMarkedObjectListWriteAccess().DeletePageView(*pPageView
);
383 SdrSnapView::HideSdrPage();
387 MarkListHasChanged();
393 void SdrMarkView::BegMarkObj(const Point
& rPnt
, bool bUnmark
)
397 DBG_ASSERT(!mpMarkObjOverlay
, "SdrMarkView::BegMarkObj: There exists a mpMarkObjOverlay (!)");
399 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
400 mpMarkObjOverlay
.reset(new ImplMarkingOverlay(*this, aStartPos
, bUnmark
));
402 maDragStat
.Reset(rPnt
);
403 maDragStat
.NextPoint();
404 maDragStat
.SetMinMove(mnMinMovLog
);
407 void SdrMarkView::MovMarkObj(const Point
& rPnt
)
409 if(IsMarkObj() && maDragStat
.CheckMinMoved(rPnt
))
411 maDragStat
.NextMove(rPnt
);
412 DBG_ASSERT(mpMarkObjOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
413 basegfx::B2DPoint
aNewPos(rPnt
.X(), rPnt
.Y());
414 mpMarkObjOverlay
->SetSecondPosition(aNewPos
);
418 bool SdrMarkView::EndMarkObj()
424 if(maDragStat
.IsMinMoved())
426 tools::Rectangle
aRect(maDragStat
.GetStart(), maDragStat
.GetNow());
428 MarkObj(aRect
, mpMarkObjOverlay
->IsUnmarking());
439 void SdrMarkView::BrkMarkObj()
443 DBG_ASSERT(mpMarkObjOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
444 mpMarkObjOverlay
.reset();
449 bool SdrMarkView::BegMarkPoints(const Point
& rPnt
, bool bUnmark
)
451 if(HasMarkablePoints())
455 DBG_ASSERT(!mpMarkPointsOverlay
, "SdrMarkView::BegMarkObj: There exists a mpMarkPointsOverlay (!)");
456 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
457 mpMarkPointsOverlay
.reset(new ImplMarkingOverlay(*this, aStartPos
, bUnmark
));
459 maDragStat
.Reset(rPnt
);
460 maDragStat
.NextPoint();
461 maDragStat
.SetMinMove(mnMinMovLog
);
469 void SdrMarkView::MovMarkPoints(const Point
& rPnt
)
471 if(IsMarkPoints() && maDragStat
.CheckMinMoved(rPnt
))
473 maDragStat
.NextMove(rPnt
);
475 DBG_ASSERT(mpMarkPointsOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
476 basegfx::B2DPoint
aNewPos(rPnt
.X(), rPnt
.Y());
477 mpMarkPointsOverlay
->SetSecondPosition(aNewPos
);
481 bool SdrMarkView::EndMarkPoints()
487 if(maDragStat
.IsMinMoved())
489 tools::Rectangle
aRect(maDragStat
.GetStart(), maDragStat
.GetNow());
491 MarkPoints(&aRect
, mpMarkPointsOverlay
->IsUnmarking());
503 void SdrMarkView::BrkMarkPoints()
507 DBG_ASSERT(mpMarkPointsOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
508 mpMarkPointsOverlay
.reset();
513 bool SdrMarkView::BegMarkGluePoints(const Point
& rPnt
, bool bUnmark
)
515 if(HasMarkableGluePoints())
519 DBG_ASSERT(!mpMarkGluePointsOverlay
, "SdrMarkView::BegMarkObj: There exists a mpMarkGluePointsOverlay (!)");
521 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
522 mpMarkGluePointsOverlay
.reset(new ImplMarkingOverlay(*this, aStartPos
, bUnmark
));
523 maDragStat
.Reset(rPnt
);
524 maDragStat
.NextPoint();
525 maDragStat
.SetMinMove(mnMinMovLog
);
533 void SdrMarkView::MovMarkGluePoints(const Point
& rPnt
)
535 if(IsMarkGluePoints() && maDragStat
.CheckMinMoved(rPnt
))
537 maDragStat
.NextMove(rPnt
);
539 DBG_ASSERT(mpMarkGluePointsOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
540 basegfx::B2DPoint
aNewPos(rPnt
.X(), rPnt
.Y());
541 mpMarkGluePointsOverlay
->SetSecondPosition(aNewPos
);
545 void SdrMarkView::EndMarkGluePoints()
547 if(IsMarkGluePoints())
549 if(maDragStat
.IsMinMoved())
551 tools::Rectangle
aRect(maDragStat
.GetStart(),maDragStat
.GetNow());
553 MarkGluePoints(&aRect
, mpMarkGluePointsOverlay
->IsUnmarking());
561 void SdrMarkView::BrkMarkGluePoints()
563 if(IsMarkGluePoints())
565 DBG_ASSERT(mpMarkGluePointsOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
566 mpMarkGluePointsOverlay
.reset();
570 bool SdrMarkView::MarkableObjectsExceed( int n
) const
572 SdrPageView
* pPV
= GetSdrPageView();
576 SdrObjList
* pOL
=pPV
->GetObjList();
577 for (const rtl::Reference
<SdrObject
>& pObj
: *pOL
)
578 if (IsObjMarkable(pObj
.get(),pPV
) && --n
<0)
584 void SdrMarkView::hideMarkHandles()
586 if(!mbMarkHandlesHidden
)
588 mbMarkHandlesHidden
= true;
593 void SdrMarkView::showMarkHandles()
595 if(mbMarkHandlesHidden
)
597 mbMarkHandlesHidden
= false;
602 bool SdrMarkView::ImpIsFrameHandles() const
604 const size_t nMarkCount
=GetMarkedObjectCount();
605 bool bFrmHdl
=nMarkCount
>static_cast<size_t>(mnFrameHandlesLimit
) || mbForceFrameHandles
;
606 bool bStdDrag
=meDragMode
==SdrDragMode::Move
;
607 if (nMarkCount
==1 && bStdDrag
&& bFrmHdl
)
609 const SdrObject
* pObj
=GetMarkedObjectByIndex(0);
610 if (pObj
&& pObj
->GetObjInventor()==SdrInventor::Default
)
612 SdrObjKind nIdent
=pObj
->GetObjIdentifier();
613 if (nIdent
==SdrObjKind::Line
|| nIdent
==SdrObjKind::Edge
|| nIdent
==SdrObjKind::Caption
|| nIdent
==SdrObjKind::Measure
|| nIdent
==SdrObjKind::CustomShape
|| nIdent
==SdrObjKind::Table
)
619 if (!bStdDrag
&& !bFrmHdl
) {
620 // all other drag modes only with FrameHandles
622 if (meDragMode
==SdrDragMode::Rotate
) {
623 // when rotating, use ObjOwn drag, if there's at least 1 PolyObj
624 for (size_t nMarkNum
=0; nMarkNum
<nMarkCount
&& bFrmHdl
; ++nMarkNum
) {
625 const SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
626 const SdrObject
* pObj
=pM
->GetMarkedSdrObj();
627 bFrmHdl
=!pObj
->IsPolyObj();
632 // FrameHandles, if at least 1 Obj can't do SpecialDrag
633 for (size_t nMarkNum
=0; nMarkNum
<nMarkCount
&& !bFrmHdl
; ++nMarkNum
) {
634 const SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
635 const SdrObject
* pObj
=pM
->GetMarkedSdrObj();
636 bFrmHdl
=!pObj
->hasSpecialDrag();
640 // no FrameHdl for crop
641 if(bFrmHdl
&& SdrDragMode::Crop
== meDragMode
)
651 std::u16string_view
lcl_getDragMethodServiceName( std::u16string_view rCID
)
653 std::u16string_view aRet
;
655 size_t nIndexStart
= rCID
.find( u
"DragMethod=" );
656 if( nIndexStart
!= std::u16string_view::npos
)
658 nIndexStart
= rCID
.find( '=', nIndexStart
);
659 if( nIndexStart
!= std::u16string_view::npos
)
662 size_t nNextSlash
= rCID
.find( '/', nIndexStart
);
663 if( nNextSlash
!= std::u16string_view::npos
)
665 sal_Int32 nIndexEnd
= nNextSlash
;
666 size_t nNextColon
= rCID
.find( ':', nIndexStart
);
667 if( nNextColon
== std::u16string_view::npos
|| nNextColon
< nNextSlash
)
668 nIndexEnd
= nNextColon
;
669 aRet
= rCID
.substr(nIndexStart
,nIndexEnd
-nIndexStart
);
676 std::u16string_view
lcl_getDragParameterString( std::u16string_view rCID
)
678 std::u16string_view aRet
;
680 size_t nIndexStart
= rCID
.find( u
"DragParameter=" );
681 if( nIndexStart
!= std::u16string_view::npos
)
683 nIndexStart
= rCID
.find( '=', nIndexStart
);
684 if( nIndexStart
!= std::u16string_view::npos
)
687 size_t nNextSlash
= rCID
.find( '/', nIndexStart
);
688 if( nNextSlash
!= std::u16string_view::npos
)
690 sal_Int32 nIndexEnd
= nNextSlash
;
691 size_t nNextColon
= rCID
.find( ':', nIndexStart
);
692 if( nNextColon
== std::u16string_view::npos
|| nNextColon
< nNextSlash
)
693 nIndexEnd
= nNextColon
;
694 aRet
= rCID
.substr(nIndexStart
,nIndexEnd
-nIndexStart
);
700 } // anonymous namespace
702 bool SdrMarkView::dumpGluePointsToJSON(boost::property_tree::ptree
& rTree
)
705 tools::Long nSignX
= mbNegativeX
? -1 : 1;
706 if (OutputDevice
* pOutDev
= mpMarkedPV
? mpMarkedPV
->GetView().GetFirstOutputDevice() : nullptr)
708 bool bConvertUnit
= false;
709 if (pOutDev
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
)
711 const SdrObjList
* pOL
= mpMarkedPV
->GetObjList();
714 boost::property_tree::ptree elements
;
715 for (const rtl::Reference
<SdrObject
>& pObj
: *pOL
)
719 if (pObj
== GetMarkedObjectByIndex(0))
721 const SdrGluePointList
* pGPL
= pObj
->GetGluePointList();
722 bool VertexObject
= !(pGPL
&& pGPL
->GetCount());
723 const size_t count
= !VertexObject
? pGPL
->GetCount() : 4;
724 boost::property_tree::ptree object
;
725 boost::property_tree::ptree points
;
726 for (size_t i
= 0; i
< count
; ++i
)
728 boost::property_tree::ptree node
;
729 boost::property_tree::ptree point
;
730 const SdrGluePoint
& rGP
= !VertexObject
? (*pGPL
)[i
] : pObj
->GetVertexGluePoint(i
);
731 Point rPoint
= rGP
.GetAbsolutePos(*pObj
);
734 rPoint
= o3tl::convert(rPoint
, o3tl::Length::mm100
, o3tl::Length::twip
);
736 point
.put("x", nSignX
* rPoint
.getX());
737 point
.put("y", rPoint
.getY());
738 node
.add_child("point", point
);
739 points
.push_back(std::make_pair("", node
));
741 basegfx::B2DVector
aGridOffset(0.0, 0.0);
742 Point objLogicRectTopLeft
= pObj
->GetLogicRect().TopLeft();
743 if(getPossibleGridOffsetForPosition(aGridOffset
, basegfx::B2DPoint(objLogicRectTopLeft
.X(), objLogicRectTopLeft
.Y()), GetSdrPageView()))
745 Point
p(aGridOffset
.getX(), aGridOffset
.getY());
748 p
= o3tl::convert(p
, o3tl::Length::mm100
, o3tl::Length::twip
);
750 boost::property_tree::ptree gridOffset
;
751 gridOffset
.put("x", nSignX
* p
.getX());
752 gridOffset
.put("y", p
.getY());
753 object
.add_child("gridoffset", gridOffset
);
755 object
.put("ordnum", pObj
->GetOrdNum());
756 object
.add_child("gluepoints", points
);
757 elements
.push_back(std::make_pair("", object
));
760 rTree
.add_child("shapes", elements
);
767 class TextBoundsExtractor final
: public drawinglayer::processor2d::TextExtractor2D
770 basegfx::B2DRange maTextRange
;
771 void processTextPrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
) override
773 maTextRange
.expand(rCandidate
.getB2DRange(getViewInformation2D()));
776 explicit TextBoundsExtractor(const drawinglayer::geometry::ViewInformation2D
& rViewInformation
)
777 : drawinglayer::processor2d::TextExtractor2D(rViewInformation
, true)
781 basegfx::B2DRange
getTextBounds(const sdr::contact::ViewObjectContact
&rVOC
, sdr::contact::DisplayInfo
&raDisplayInfo
)
783 this->process(rVOC
.getPrimitive2DSequence(raDisplayInfo
));
789 OString
SdrMarkView::CreateInnerTextRectString() const
794 SdrPageView
* pPageView
= GetSdrPageView();
795 const sdr::contact::ViewObjectContact
& rVOC
= mpMarkedObj
->GetViewContact().GetViewObjectContact(
796 pPageView
->GetPageWindow(0)->GetObjectContact());
798 sdr::contact::DisplayInfo aDisplayInfo
;
799 TextBoundsExtractor
aTextBoundsExtractor(rVOC
.GetObjectContact().getViewInformation2D());
800 basegfx::B2DRange aRange
= aTextBoundsExtractor
.getTextBounds(rVOC
, aDisplayInfo
);
801 if (!aRange
.isEmpty()) {
802 tools::Rectangle
rect(aRange
.getMinX(), aRange
.getMinY(), aRange
.getMaxX(), aRange
.getMaxY());
803 tools::Rectangle aRangeTWIP
= o3tl::convert(rect
, o3tl::Length::mm100
, o3tl::Length::twip
);
804 OString innerTextInfo
= "\"innerTextRect\":[" +
805 OString::number(aRangeTWIP
.getX()) + "," +
806 OString::number(aRangeTWIP
.getY()) + "," +
807 OString::number(aRangeTWIP
.GetWidth()) + "," +
808 OString::number(aRangeTWIP
.GetHeight()) + "]";
809 return innerTextInfo
;
815 void SdrMarkView::SetInnerTextAreaForLOKit() const
817 if (!comphelper::LibreOfficeKit::isActive())
819 SfxViewShell
* pViewShell
= GetSfxViewShell();
820 OString sRectString
= CreateInnerTextRectString();
821 if (pViewShell
&& !sRectString
.isEmpty())
822 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_SHAPE_INNER_TEXT
, sRectString
);
825 void SdrMarkView::SetMarkHandlesForLOKit(tools::Rectangle
const & rRect
, const SfxViewShell
* pOtherShell
)
827 SfxViewShell
* pViewShell
= GetSfxViewShell();
829 tools::Rectangle
aSelection(rRect
);
830 tools::Long nSignX
= mbNegativeX
? -1 : 1;
831 bool bIsChart
= false;
832 Point
addLogicOffset(0, 0);
833 bool convertMapMode
= false;
834 if (!rRect
.IsEmpty())
836 sal_uInt32 nTotalPaintWindows
= this->PaintWindowCount();
837 if (nTotalPaintWindows
== 1)
839 const OutputDevice
* pOut
= this->GetFirstOutputDevice();
840 const vcl::Window
* pWin
= pOut
? pOut
->GetOwnerWindow() : nullptr;
841 if (pWin
&& pWin
->IsChart())
844 const vcl::Window
* pViewShellWindow
= GetSfxViewShell()->GetEditWindowForActiveOLEObj();
845 if (pViewShellWindow
&& pViewShellWindow
->IsAncestorOf(*pWin
))
847 Point aOffsetPx
= pWin
->GetOffsetPixelFrom(*pViewShellWindow
);
848 if (mbNegativeX
&& AllSettings::GetLayoutRTL())
850 // mbNegativeX is set only for Calc in RTL mode.
851 // If global RTL flag is set, vcl-window X offset of chart window is
852 // mirrored w.r.t parent window rectangle. This needs to be reverted.
853 aOffsetPx
.setX(pViewShellWindow
->GetOutOffXPixel() + pViewShellWindow
->GetSizePixel().Width()
854 - pWin
->GetOutOffXPixel() - pWin
->GetSizePixel().Width());
856 Point aLogicOffset
= pWin
->PixelToLogic(aOffsetPx
);
857 addLogicOffset
= aLogicOffset
;
858 aSelection
.Move(aLogicOffset
.getX(), aLogicOffset
.getY());
864 if (!aSelection
.IsEmpty())
866 // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
869 if (OutputDevice
* pOutputDevice
= mpMarkedPV
->GetView().GetFirstOutputDevice())
871 if (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
)
873 aSelection
= o3tl::convert(aSelection
, o3tl::Length::mm100
, o3tl::Length::twip
);
874 convertMapMode
= true;
879 // hide the text selection too
880 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION
, ""_ostr
);
884 OStringBuffer aExtraInfo
;
885 OString sSelectionText
;
886 OString sSelectionTextView
;
887 boost::property_tree::ptree aTableJsonTree
;
888 boost::property_tree::ptree aGluePointsTree
;
889 const bool bMediaObj
= (mpMarkedObj
&& mpMarkedObj
->GetObjIdentifier() == SdrObjKind::Media
);
890 bool bTableSelection
= false;
891 bool bConnectorSelection
= false;
893 if (mpMarkedObj
&& mpMarkedObj
->GetObjIdentifier() == SdrObjKind::Table
)
895 auto& rTableObject
= dynamic_cast<sdr::table::SdrTableObj
&>(*mpMarkedObj
);
896 bTableSelection
= rTableObject
.createTableEdgesJson(aTableJsonTree
);
898 if (mpMarkedObj
&& mpMarkedObj
->GetObjIdentifier() == SdrObjKind::Edge
)
900 bConnectorSelection
= dumpGluePointsToJSON(aGluePointsTree
);
903 SdrPageView
* pPageView
= GetSdrPageView();
905 if (GetMarkedObjectCount())
907 SdrMark
* pM
= GetSdrMarkByIndex(0);
908 SdrObject
* pO
= pM
->GetMarkedSdrObj();
909 Degree100 nRotAngle
= pO
->GetRotateAngle();
910 // true if we are dealing with a RotGrfFlyFrame
911 // (SwVirtFlyDrawObj with a SwGrfNode)
912 bool bWriterGraphic
= pO
->HasLimitedRotation();
914 OString handleArrayStr
;
916 aExtraInfo
.append("{\"id\":\""
917 + OString::number(reinterpret_cast<sal_IntPtr
>(pO
))
919 + OString::number(static_cast<sal_Int32
>(pO
->GetObjIdentifier())));
921 if (mpMarkedObj
&& !pOtherShell
)
923 OString innerTextInfo
= CreateInnerTextRectString();
924 if (!innerTextInfo
.isEmpty())
925 aExtraInfo
.append("," + innerTextInfo
);
928 // In core, the gridOffset is calculated based on the LogicRect's TopLeft coordinate
929 // In online, we have the SnapRect and we calculate it based on its TopLeft coordinate
930 // SnapRect's TopLeft and LogicRect's TopLeft match unless there is rotation
931 // but the rotation is not applied to the LogicRect. Therefore,
932 // what we calculate in online does not match with the core in case of the rotation.
933 // Here we can send the correct gridOffset in the selection callback, this way
934 // whether the shape is rotated or not, we will always have the correct gridOffset
935 // Note that the gridOffset is calculated from the first selected obj
936 basegfx::B2DVector
aGridOffset(0.0, 0.0);
937 if(getPossibleGridOffsetForSdrObject(aGridOffset
, GetMarkedObjectByIndex(0), pPageView
))
939 Point
p(aGridOffset
.getX(), aGridOffset
.getY());
941 p
= o3tl::convert(p
, o3tl::Length::mm100
, o3tl::Length::twip
);
942 aExtraInfo
.append(",\"gridOffsetX\":"
943 + OString::number(nSignX
* p
.getX())
944 + ",\"gridOffsetY\":"
945 + OString::number(p
.getY()));
950 aExtraInfo
.append(", \"isWriterGraphic\": true");
954 LokChartHelper
aChartHelper(pViewShell
);
955 css::uno::Reference
<css::frame::XController
>& xChartController
= aChartHelper
.GetXController();
956 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier( xChartController
, uno::UNO_QUERY
);
957 if (xSelectionSupplier
.is())
959 uno::Any aSel
= xSelectionSupplier
->getSelection();
963 OString
aObjectCID(aValue
.getStr(), aValue
.getLength(), osl_getThreadTextEncoding());
964 const std::vector
<OString
> aProps
{"Draggable"_ostr
, "Resizable"_ostr
, "Rotatable"_ostr
};
965 for (const auto& rProp
: aProps
)
967 sal_Int32 nPos
= aObjectCID
.indexOf(rProp
);
968 if (nPos
== -1) continue;
969 nPos
+= rProp
.getLength() + 1; // '='
970 if (aExtraInfo
.getLength() > 2) // != "{ "
971 aExtraInfo
.append(", ");
972 aExtraInfo
.append("\"is" + rProp
+ "\": "
973 + OString::boolean(aObjectCID
[nPos
] == '1'));
976 std::u16string_view sDragMethod
= lcl_getDragMethodServiceName(aValue
);
977 if (sDragMethod
== u
"PieSegmentDragging")
979 // old initial offset inside the CID returned by xSelectionSupplier->getSelection()
980 // after a pie segment dragging; using SdrObject::GetName for getting a CID with the updated offset
981 aValue
= pO
->GetName();
982 std::u16string_view sDragParameters
= lcl_getDragParameterString(aValue
);
983 if (!sDragParameters
.empty())
985 aExtraInfo
.append(", \"dragInfo\": { "
987 + OUString(sDragMethod
).toUtf8()
990 sal_Int32 nStartIndex
= 0;
991 std::array
<int, 5> aDragParameters
;
992 for (auto& rParam
: aDragParameters
)
994 std::u16string_view sParam
= o3tl::getToken(sDragParameters
, 0, ',', nStartIndex
);
997 rParam
= o3tl::toInt32(sParam
);
1000 // initial offset in %
1001 if (aDragParameters
[0] < 0)
1002 aDragParameters
[0] = 0;
1003 else if (aDragParameters
[0] > 100)
1004 aDragParameters
[0] = 100;
1006 aExtraInfo
.append(", \"initialOffset\": "
1007 + OString::number(static_cast<sal_Int32
>(aDragParameters
[0])));
1009 // drag direction constraint
1010 Point
aMinPos(aDragParameters
[1], aDragParameters
[2]);
1011 Point
aMaxPos(aDragParameters
[3], aDragParameters
[4]);
1012 Point aDragDirection
= aMaxPos
- aMinPos
;
1013 aDragDirection
= o3tl::convert(aDragDirection
, o3tl::Length::mm100
, o3tl::Length::twip
);
1015 aExtraInfo
.append(", \"dragDirection\": ["
1016 + aDragDirection
.toString()
1019 // polygon approximating the pie segment or donut segment
1020 if (pO
->GetObjIdentifier() == SdrObjKind::PathFill
)
1022 const basegfx::B2DPolyPolygon
aPolyPolygon(pO
->TakeXorPoly());
1023 if (aPolyPolygon
.count() == 1)
1025 const basegfx::B2DPolygon aPolygon
= aPolyPolygon
.getB2DPolygon(0);
1026 if (sal_uInt32 nPolySize
= aPolygon
.count())
1028 const OutputDevice
* pOut
= this->GetFirstOutputDevice();
1029 const vcl::Window
* pWin
= pOut
? pOut
->GetOwnerWindow() : nullptr;
1030 const vcl::Window
* pViewShellWindow
= pViewShell
->GetEditWindowForActiveOLEObj();
1031 if (pWin
&& pViewShellWindow
&& pViewShellWindow
->IsAncestorOf(*pWin
))
1033 // in the following code escaping sequences used inside raw literal strings
1034 // are for making them understandable by the JSON parser
1036 Point aOffsetPx
= pWin
->GetOffsetPixelFrom(*pViewShellWindow
);
1037 Point aLogicOffset
= pWin
->PixelToLogic(aOffsetPx
);
1038 OString
sPolygonElem("<polygon points=\\\""_ostr
);
1039 for (sal_uInt32 nIndex
= 0; nIndex
< nPolySize
; ++nIndex
)
1041 const basegfx::B2DPoint aB2Point
= aPolygon
.getB2DPoint(nIndex
);
1042 Point
aPoint(aB2Point
.getX(), aB2Point
.getY());
1043 aPoint
.Move(aLogicOffset
.getX(), aLogicOffset
.getY());
1045 aPoint
.setX(-aPoint
.X());
1047 sPolygonElem
+= " ";
1048 sPolygonElem
+= aPoint
.toString();
1050 sPolygonElem
+= R
"elem(\" style
=\"stroke
: none
; fill
: rgb(114,159,207); fill
-opacity
: 0.8\"/>)elem
";
1052 OString sSVGElem = R"elem(<svg version
=\"1.2\" width
=\")elem
" +
1053 OString::number(aSelection.GetWidth() / 100.0) +
1054 R"elem(mm
\" height
=\")elem
" +
1055 OString::number(aSelection.GetHeight() / 100.0) +
1056 R"elem(mm
\" viewBox
=\")elem
" +
1057 aSelection.toString() +
1058 R"elem(\" preserveAspectRatio
=\"xMidYMid
\" xmlns
=\"http
://www.w3.org/2000/svg\">)elem";
1060 aExtraInfo
.append(", \"svg\": \""
1070 aExtraInfo
.append("}"); // dragInfo
1076 if (!bTableSelection
&& !pOtherShell
&& maHdlList
.GetHdlCount())
1078 boost::property_tree::ptree responseJSON
;
1079 boost::property_tree::ptree others
;
1080 boost::property_tree::ptree anchor
;
1081 boost::property_tree::ptree rectangle
;
1082 boost::property_tree::ptree poly
;
1083 boost::property_tree::ptree custom
;
1084 boost::property_tree::ptree nodes
;
1085 for (size_t i
= 0; i
< maHdlList
.GetHdlCount(); i
++)
1087 SdrHdl
*pHdl
= maHdlList
.GetHdl(i
);
1088 boost::property_tree::ptree child
;
1089 boost::property_tree::ptree point
;
1090 sal_Int32 kind
= static_cast<sal_Int32
>(pHdl
->GetKind());
1091 child
.put("id", pHdl
->GetObjHdlNum());
1092 child
.put("kind", kind
);
1093 child
.put("pointer", static_cast<sal_Int32
>(pHdl
->GetPointer()));
1094 Point pHdlPos
= pHdl
->GetPos();
1095 pHdlPos
.Move(addLogicOffset
.getX(), addLogicOffset
.getY());
1098 pHdlPos
= o3tl::convert(pHdlPos
, o3tl::Length::mm100
, o3tl::Length::twip
);
1100 point
.put("x", pHdlPos
.getX());
1101 point
.put("y", pHdlPos
.getY());
1102 child
.add_child("point", point
);
1103 const auto node
= std::make_pair("", child
);
1104 boost::property_tree::ptree
* selectedNode
= nullptr;
1105 if (kind
>= static_cast<sal_Int32
>(SdrHdlKind::UpperLeft
) && kind
<= static_cast<sal_Int32
>(SdrHdlKind::LowerRight
))
1107 selectedNode
= &rectangle
;
1109 else if (kind
== static_cast<sal_Int32
>(SdrHdlKind::Poly
))
1111 selectedNode
= &poly
;
1113 else if (kind
== static_cast<sal_Int32
>(SdrHdlKind::CustomShape1
))
1115 selectedNode
= &custom
;
1117 else if (kind
== static_cast<sal_Int32
>(SdrHdlKind::Anchor
) || kind
== static_cast<sal_Int32
>(SdrHdlKind::Anchor_TR
))
1119 if (getSdrModelFromSdrView().IsWriter())
1120 selectedNode
= &anchor
;
1122 // put it to others as we don't render them except in writer
1123 selectedNode
= &others
;
1127 selectedNode
= &others
;
1129 std::string sKind
= std::to_string(kind
);
1130 boost::optional
< boost::property_tree::ptree
& > kindNode
= selectedNode
->get_child_optional(sKind
.c_str());
1133 boost::property_tree::ptree newChild
;
1134 newChild
.push_back(node
);
1135 selectedNode
->add_child(sKind
.c_str(), newChild
);
1138 kindNode
.get().push_back(node
);
1140 nodes
.add_child("rectangle", rectangle
);
1141 nodes
.add_child("poly", poly
);
1142 nodes
.add_child("custom", custom
);
1143 nodes
.add_child("anchor", anchor
);
1144 nodes
.add_child("others", others
);
1145 responseJSON
.add_child("kinds", nodes
);
1146 std::stringstream aStream
;
1147 boost::property_tree::write_json(aStream
, responseJSON
, /*pretty=*/ false);
1148 handleArrayStr
= ", \"handles\":"_ostr
;
1149 handleArrayStr
= handleArrayStr
+ aStream
.str().c_str();
1150 if (bConnectorSelection
)
1153 boost::property_tree::write_json(aStream
, aGluePointsTree
, /*pretty=*/ false);
1154 handleArrayStr
= handleArrayStr
+ ", \"GluePoints\":";
1155 handleArrayStr
= handleArrayStr
+ aStream
.str().c_str();
1161 tools::Rectangle
aNegatedRect(aSelection
);
1162 aNegatedRect
.SetLeft(-aNegatedRect
.Left());
1163 aNegatedRect
.SetRight(-aNegatedRect
.Right());
1164 aNegatedRect
.Normalize();
1165 sSelectionText
= aNegatedRect
.toString() +
1166 ", " + OString::number(nRotAngle
.get());
1170 sSelectionText
= aSelection
.toString() +
1171 ", " + OString::number(nRotAngle
.get());
1174 if (!aExtraInfo
.isEmpty())
1176 sSelectionTextView
= sSelectionText
+ ", " + aExtraInfo
+ "}";
1178 if (bMediaObj
&& pOtherShell
== nullptr)
1180 // Add the URL only if we have a Media Object and
1181 // we are the selecting view.
1182 SdrMediaObj
* mediaObj
= dynamic_cast<SdrMediaObj
*>(mpMarkedObj
);
1184 aExtraInfo
.append(", \"url\": \"" + mediaObj
->getTempURL().toUtf8() + "\"");
1187 aExtraInfo
.append(handleArrayStr
1189 sSelectionText
+= ", " + aExtraInfo
;
1193 if (sSelectionText
.isEmpty())
1195 sSelectionText
= "EMPTY"_ostr
;
1196 sSelectionTextView
= "EMPTY"_ostr
;
1198 pViewShell
->NotifyOtherViews(LOK_CALLBACK_TEXT_VIEW_SELECTION
, "selection"_ostr
, OString());
1201 if (bTableSelection
)
1203 boost::property_tree::ptree aTableRectangle
;
1204 aTableRectangle
.put("x", aSelection
.Left());
1205 aTableRectangle
.put("y", aSelection
.Top());
1206 aTableRectangle
.put("width", aSelection
.GetWidth());
1207 aTableRectangle
.put("height", aSelection
.GetHeight());
1208 aTableJsonTree
.push_back(std::make_pair("rectangle", aTableRectangle
));
1210 std::stringstream aStream
;
1211 boost::property_tree::write_json(aStream
, aTableJsonTree
);
1212 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED
, OString(aStream
.str()));
1214 else if (!getSdrModelFromSdrView().IsWriter())
1216 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED
, "{}"_ostr
);
1221 // Another shell wants to know about our existing
1223 if (pViewShell
!= pOtherShell
)
1224 SfxLokHelper::notifyOtherView(pViewShell
, pOtherShell
, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
, "selection", sSelectionTextView
);
1228 // We have a new selection, so both pViewShell and the
1229 // other views want to know about it.
1230 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION
, sSelectionText
);
1232 SfxLokHelper::notifyOtherViews(pViewShell
, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
, "selection", sSelectionTextView
);
1237 void SdrMarkView::SetMarkHandles(SfxViewShell
* pOtherShell
)
1239 // remember old focus handle values to search for it again
1240 const SdrHdl
* pSaveOldFocusHdl
= maHdlList
.GetFocusHdl();
1241 bool bSaveOldFocus(false);
1242 sal_uInt32
nSavePolyNum(0), nSavePointNum(0);
1243 SdrHdlKind
eSaveKind(SdrHdlKind::Move
);
1244 SdrObject
* pSaveObj
= nullptr;
1246 mpMarkingSubSelectionOverlay
.reset();
1249 && pSaveOldFocusHdl
->GetObj()
1250 && dynamic_cast<const SdrPathObj
*>(pSaveOldFocusHdl
->GetObj()) != nullptr
1251 && (pSaveOldFocusHdl
->GetKind() == SdrHdlKind::Poly
|| pSaveOldFocusHdl
->GetKind() == SdrHdlKind::BezierWeight
))
1253 bSaveOldFocus
= true;
1254 nSavePolyNum
= pSaveOldFocusHdl
->GetPolyNum();
1255 nSavePointNum
= pSaveOldFocusHdl
->GetPointNum();
1256 pSaveObj
= pSaveOldFocusHdl
->GetObj();
1257 eSaveKind
= pSaveOldFocusHdl
->GetKind();
1260 // delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
1262 maHdlList
.SetRotateShear(meDragMode
==SdrDragMode::Rotate
);
1263 maHdlList
.SetDistortShear(meDragMode
==SdrDragMode::Shear
);
1264 mpMarkedObj
=nullptr;
1267 // are handles enabled at all? Create only then
1268 if(areMarkHandlesHidden())
1271 // There can be multiple mark views, but we're only interested in the one that has a window associated.
1272 const bool bTiledRendering
= comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW
;
1274 const size_t nMarkCount
=GetMarkedObjectCount();
1275 bool bStdDrag
=meDragMode
==SdrDragMode::Move
;
1276 bool bSingleTextObjMark
=false;
1277 bool bLimitedRotation(false);
1281 mpMarkedObj
=GetMarkedObjectByIndex(0);
1283 if(nullptr != mpMarkedObj
)
1285 bSingleTextObjMark
=
1286 DynCastSdrTextObj( mpMarkedObj
) != nullptr &&
1287 static_cast<SdrTextObj
*>(mpMarkedObj
)->IsTextFrame();
1289 // RotGrfFlyFrame: we may have limited rotation
1290 bLimitedRotation
= SdrDragMode::Rotate
== meDragMode
&& mpMarkedObj
->HasLimitedRotation();
1294 bool bFrmHdl
=ImpIsFrameHandles();
1298 mpMarkedPV
=GetSdrPageViewOfMarkedByIndex(0);
1300 for (size_t nMarkNum
=0; nMarkNum
<nMarkCount
&& (mpMarkedPV
!=nullptr || !bFrmHdl
); ++nMarkNum
)
1302 const SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
1304 if (mpMarkedPV
!=pM
->GetPageView())
1311 SfxViewShell
* pViewShell
= GetSfxViewShell();
1313 // check if text edit or ole is active and handles need to be suppressed. This may be the case
1314 // when a single object is selected
1315 // Using a strict return statement is okay here; no handles means *no* handles.
1318 // formerly #i33755#: If TextEdit is active the EditEngine will directly paint
1319 // to the window, so suppress Overlay and handles completely; a text frame for
1320 // the active text edit will be painted by the repaint mechanism in
1321 // SdrObjEditView::ImpPaintOutlinerView in this case. This needs to be reworked
1323 // Also formerly #122142#: Pretty much the same for SdrCaptionObj's in calc.
1324 if(static_cast<SdrView
*>(this)->IsTextEdit())
1326 const SdrTextObj
* pSdrTextObj
= DynCastSdrTextObj(mpMarkedObj
);
1328 if (pSdrTextObj
&& pSdrTextObj
->IsInEditMode())
1330 if (!bTiledRendering
)
1335 // formerly #i118524#: if inplace activated OLE is selected, suppress handles
1336 const SdrOle2Obj
* pSdrOle2Obj
= dynamic_cast< const SdrOle2Obj
* >(mpMarkedObj
);
1338 if(pSdrOle2Obj
&& (pSdrOle2Obj
->isInplaceActive() || pSdrOle2Obj
->isUiActive()))
1343 if (!maSubSelectionList
.empty())
1345 mpMarkingSubSelectionOverlay
= std::make_unique
<MarkingSubSelectionOverlay
>(*this, maSubSelectionList
);
1349 tools::Rectangle
aRect(GetMarkedObjRect());
1353 if(!aRect
.IsEmpty())
1355 // otherwise nothing is found
1356 const size_t nSiz0(maHdlList
.GetHdlCount());
1358 if( bSingleTextObjMark
)
1360 mpMarkedObj
->AddToHdlList(maHdlList
);
1364 const bool bWdt0(aRect
.Left() == aRect
.Right());
1365 const bool bHgt0(aRect
.Top() == aRect
.Bottom());
1369 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.TopLeft(), SdrHdlKind::UpperLeft
));
1371 else if (!bStdDrag
&& (bWdt0
|| bHgt0
))
1373 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.TopLeft(), SdrHdlKind::UpperLeft
));
1374 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.BottomRight(), SdrHdlKind::LowerRight
));
1378 if (!bWdt0
&& !bHgt0
)
1380 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.TopLeft(), SdrHdlKind::UpperLeft
));
1383 if (!bLimitedRotation
&& !bHgt0
)
1385 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.TopCenter(), SdrHdlKind::Upper
));
1388 if (!bWdt0
&& !bHgt0
)
1390 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.TopRight(), SdrHdlKind::UpperRight
));
1393 if (!bLimitedRotation
&& !bWdt0
)
1395 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.LeftCenter(), SdrHdlKind::Left
));
1396 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.RightCenter(), SdrHdlKind::Right
));
1399 if (!bWdt0
&& !bHgt0
)
1401 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.BottomLeft(), SdrHdlKind::LowerLeft
));
1404 if (!bLimitedRotation
&& !bHgt0
)
1406 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.BottomCenter(), SdrHdlKind::Lower
));
1409 if (!bWdt0
&& !bHgt0
)
1411 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(aRect
.BottomRight(), SdrHdlKind::LowerRight
));
1416 // Diagram selection visualization support
1417 // Caution: CppunitTest_sd_tiledrendering shows that mpMarkedObj *can* actually be nullptr (!)
1418 if(nullptr != mpMarkedObj
&& mpMarkedObj
->isDiagram())
1420 mpMarkedObj
->AddToHdlList(maHdlList
);
1423 const size_t nSiz1(maHdlList
.GetHdlCount());
1425 // moved setting the missing parameters at SdrHdl here from the
1426 // single loop above (bSingleTextObjMark), this was missing all
1427 // the time. Setting SdrObject is now required to correctly get
1428 // the View-Dependent evtl. GridOffset adapted
1429 for (size_t i
=nSiz0
; i
<nSiz1
; ++i
)
1431 SdrHdl
* pHdl
=maHdlList
.GetHdl(i
);
1432 pHdl
->SetObj(mpMarkedObj
);
1433 pHdl
->SetPageView(mpMarkedPV
);
1434 pHdl
->SetObjHdlNum(sal_uInt16(i
-nSiz0
));
1442 // moved crop handling to non-frame part and the handle creation to SdrGrafObj
1443 if(1 == nMarkCount
&& mpMarkedObj
&& SdrDragMode::Crop
== meDragMode
)
1445 // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous
1446 // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj
1447 // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx)
1448 const size_t nSiz0(maHdlList
.GetHdlCount());
1449 mpMarkedObj
->addCropHandles(maHdlList
);
1450 const size_t nSiz1(maHdlList
.GetHdlCount());
1452 // Was missing: Set infos at SdrCropHdl
1453 for (size_t i
=nSiz0
; i
<nSiz1
; ++i
)
1455 SdrHdl
* pHdl
=maHdlList
.GetHdl(i
);
1456 pHdl
->SetObj(mpMarkedObj
);
1457 pHdl
->SetPageView(mpMarkedPV
);
1458 pHdl
->SetObjHdlNum(sal_uInt16(i
-nSiz0
));
1466 for (size_t nMarkNum
=0; nMarkNum
<nMarkCount
; ++nMarkNum
)
1468 const SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
1469 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1470 SdrPageView
* pPV
=pM
->GetPageView();
1471 const size_t nSiz0
=maHdlList
.GetHdlCount();
1472 pObj
->AddToHdlList(maHdlList
);
1473 const size_t nSiz1
=maHdlList
.GetHdlCount();
1474 bool bPoly
=pObj
->IsPolyObj();
1475 const SdrUShortCont
& rMrkPnts
= pM
->GetMarkedPoints();
1476 for (size_t i
=nSiz0
; i
<nSiz1
; ++i
)
1478 SdrHdl
* pHdl
=maHdlList
.GetHdl(i
);
1480 pHdl
->SetPageView(pPV
);
1481 pHdl
->SetObjHdlNum(sal_uInt16(i
-nSiz0
));
1485 bool bSelected
= rMrkPnts
.find( sal_uInt16(i
-nSiz0
) ) != rMrkPnts
.end();
1486 pHdl
->SetSelected(bSelected
);
1487 if (mbPlusHdlAlways
|| bSelected
)
1489 SdrHdlList
plusList(nullptr);
1490 pObj
->AddToPlusHdlList(plusList
, *pHdl
);
1491 sal_uInt32 nPlusHdlCnt
=plusList
.GetHdlCount();
1492 for (sal_uInt32 nPlusNum
=0; nPlusNum
<nPlusHdlCnt
; nPlusNum
++)
1494 SdrHdl
* pPlusHdl
=plusList
.GetHdl(nPlusNum
);
1495 pPlusHdl
->SetObj(pObj
);
1496 pPlusHdl
->SetPageView(pPV
);
1497 pPlusHdl
->SetPlusHdl(true);
1499 plusList
.MoveTo(maHdlList
);
1507 // GluePoint handles
1508 for (size_t nMarkNum
=0; nMarkNum
<nMarkCount
; ++nMarkNum
)
1510 const SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
1511 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1512 const SdrGluePointList
* pGPL
=pObj
->GetGluePointList();
1516 SdrPageView
* pPV
=pM
->GetPageView();
1517 const SdrUShortCont
& rMrkGlue
=pM
->GetMarkedGluePoints();
1518 for (sal_uInt16 nId
: rMrkGlue
)
1520 //nNum changed to nNumGP because already used in for loop
1521 sal_uInt16 nNumGP
=pGPL
->FindGluePoint(nId
);
1522 if (nNumGP
!=SDRGLUEPOINT_NOTFOUND
)
1524 const SdrGluePoint
& rGP
=(*pGPL
)[nNumGP
];
1525 Point
aPos(rGP
.GetAbsolutePos(*pObj
));
1526 std::unique_ptr
<SdrHdl
> pGlueHdl(new SdrHdl(aPos
,SdrHdlKind::Glue
));
1527 pGlueHdl
->SetObj(pObj
);
1528 pGlueHdl
->SetPageView(pPV
);
1529 pGlueHdl
->SetObjHdlNum(nId
);
1530 maHdlList
.AddHdl(std::move(pGlueHdl
));
1535 // rotation point/axis of reflection
1536 if(!bLimitedRotation
)
1538 AddDragModeHdl(meDragMode
);
1544 // add custom handles (used by other apps, e.g. AnchorPos)
1547 // moved it here to access all the handles for callback.
1548 if (bTiledRendering
&& pViewShell
)
1550 SetMarkHandlesForLOKit(aRect
, pOtherShell
);
1553 // try to restore focus handle index from remembered values
1557 for(size_t a
= 0; a
< maHdlList
.GetHdlCount(); ++a
)
1559 SdrHdl
* pCandidate
= maHdlList
.GetHdl(a
);
1561 if(pCandidate
->GetObj()
1562 && pCandidate
->GetObj() == pSaveObj
1563 && pCandidate
->GetKind() == eSaveKind
1564 && pCandidate
->GetPolyNum() == nSavePolyNum
1565 && pCandidate
->GetPointNum() == nSavePointNum
)
1567 maHdlList
.SetFocusHdl(pCandidate
);
1573 void SdrMarkView::AddCustomHdl()
1575 // add custom handles (used by other apps, e.g. AnchorPos)
1578 void SdrMarkView::SetDragMode(SdrDragMode eMode
)
1580 SdrDragMode eMode0
=meDragMode
;
1582 if (meDragMode
==SdrDragMode::Resize
) meDragMode
=SdrDragMode::Move
;
1583 if (meDragMode
!=eMode0
) {
1585 SetMarkHandles(nullptr);
1587 if (AreObjectsMarked()) MarkListHasChanged();
1592 void SdrMarkView::AddDragModeHdl(SdrDragMode eMode
)
1596 case SdrDragMode::Rotate
:
1598 // add rotation center
1599 maHdlList
.AddHdl(std::make_unique
<SdrHdl
>(maRef1
, SdrHdlKind::Ref1
));
1602 case SdrDragMode::Mirror
:
1604 // add axis of reflection
1605 std::unique_ptr
<SdrHdl
> pHdl3(new SdrHdl(maRef2
, SdrHdlKind::Ref2
));
1606 std::unique_ptr
<SdrHdl
> pHdl2(new SdrHdl(maRef1
, SdrHdlKind::Ref1
));
1607 std::unique_ptr
<SdrHdl
> pHdl1(new SdrHdlLine(*pHdl2
, *pHdl3
, SdrHdlKind::MirrorAxis
));
1609 pHdl1
->SetObjHdlNum(1); // for sorting
1610 pHdl2
->SetObjHdlNum(2); // for sorting
1611 pHdl3
->SetObjHdlNum(3); // for sorting
1613 maHdlList
.AddHdl(std::move(pHdl1
)); // line comes first, so it is the last in HitTest
1614 maHdlList
.AddHdl(std::move(pHdl2
));
1615 maHdlList
.AddHdl(std::move(pHdl3
));
1619 case SdrDragMode::Transparence
:
1621 // add interactive transparency handle
1622 const size_t nMarkCount
= GetMarkedObjectCount();
1625 SdrObject
* pObj
= GetMarkedObjectByIndex(0);
1626 SdrModel
& rModel
= GetModel();
1627 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
1629 if(SfxItemState::SET
!= rSet
.GetItemState(XATTR_FILLFLOATTRANSPARENCE
, false))
1631 // add this item, it's not yet there
1632 XFillFloatTransparenceItem
aNewItem(rSet
.Get(XATTR_FILLFLOATTRANSPARENCE
));
1633 basegfx::BGradient aGrad
= aNewItem
.GetGradientValue();
1635 aNewItem
.SetEnabled(true);
1636 aGrad
.SetStartIntens(100);
1637 aGrad
.SetEndIntens(100);
1638 aNewItem
.SetGradientValue(aGrad
);
1640 // add undo to allow user to take back this step
1641 if (rModel
.IsUndoEnabled())
1643 rModel
.BegUndo(SvxResId(SIP_XA_FILLTRANSPARENCE
));
1644 rModel
.AddUndo(rModel
.GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
1648 SfxItemSet
aNewSet(rModel
.GetItemPool());
1649 aNewSet
.Put(aNewItem
);
1650 pObj
->SetMergedItemSetAndBroadcast(aNewSet
);
1653 // set values and transform to vector set
1654 GradTransVector aGradTransVector
;
1655 GradTransGradient aGradTransGradient
;
1657 aGradTransGradient
.aGradient
= rSet
.Get(XATTR_FILLFLOATTRANSPARENCE
).GetGradientValue();
1658 GradTransformer::GradToVec(aGradTransGradient
, aGradTransVector
, pObj
);
1661 const Point
aTmpPos1(basegfx::fround(aGradTransVector
.maPositionA
.getX()), basegfx::fround(aGradTransVector
.maPositionA
.getY()));
1662 const Point
aTmpPos2(basegfx::fround(aGradTransVector
.maPositionB
.getX()), basegfx::fround(aGradTransVector
.maPositionB
.getY()));
1663 std::unique_ptr
<SdrHdlColor
> pColHdl1(new SdrHdlColor(aTmpPos1
, aGradTransVector
.aCol1
, SDR_HANDLE_COLOR_SIZE_NORMAL
, true));
1664 std::unique_ptr
<SdrHdlColor
> pColHdl2(new SdrHdlColor(aTmpPos2
, aGradTransVector
.aCol2
, SDR_HANDLE_COLOR_SIZE_NORMAL
, true));
1665 std::unique_ptr
<SdrHdlGradient
> pGradHdl(new SdrHdlGradient(aTmpPos1
, aTmpPos2
, false));
1666 DBG_ASSERT(pColHdl1
&& pColHdl2
&& pGradHdl
, "Could not get all necessary handles!");
1669 pGradHdl
->SetColorHandles(pColHdl1
.get(), pColHdl2
.get());
1670 pGradHdl
->SetObj(pObj
);
1671 pColHdl1
->SetColorChangeHdl(LINK(pGradHdl
.get(), SdrHdlGradient
, ColorChangeHdl
));
1672 pColHdl2
->SetColorChangeHdl(LINK(pGradHdl
.get(), SdrHdlGradient
, ColorChangeHdl
));
1675 maHdlList
.AddHdl(std::move(pColHdl1
));
1676 maHdlList
.AddHdl(std::move(pColHdl2
));
1677 maHdlList
.AddHdl(std::move(pGradHdl
));
1681 case SdrDragMode::Gradient
:
1683 // add interactive gradient handle
1684 const size_t nMarkCount
= GetMarkedObjectCount();
1687 SdrObject
* pObj
= GetMarkedObjectByIndex(0);
1688 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
1689 drawing::FillStyle eFillStyle
= rSet
.Get(XATTR_FILLSTYLE
).GetValue();
1691 if(eFillStyle
== drawing::FillStyle_GRADIENT
)
1693 // set values and transform to vector set
1694 GradTransVector aGradTransVector
;
1695 GradTransGradient aGradTransGradient
;
1696 Size
aHdlSize(15, 15);
1698 aGradTransGradient
.aGradient
= rSet
.Get(XATTR_FILLGRADIENT
).GetGradientValue();
1699 GradTransformer::GradToVec(aGradTransGradient
, aGradTransVector
, pObj
);
1702 const Point
aTmpPos1(basegfx::fround(aGradTransVector
.maPositionA
.getX()), basegfx::fround(aGradTransVector
.maPositionA
.getY()));
1703 const Point
aTmpPos2(basegfx::fround(aGradTransVector
.maPositionB
.getX()), basegfx::fround(aGradTransVector
.maPositionB
.getY()));
1704 std::unique_ptr
<SdrHdlColor
> pColHdl1(new SdrHdlColor(aTmpPos1
, aGradTransVector
.aCol1
, aHdlSize
, false));
1705 std::unique_ptr
<SdrHdlColor
> pColHdl2(new SdrHdlColor(aTmpPos2
, aGradTransVector
.aCol2
, aHdlSize
, false));
1706 std::unique_ptr
<SdrHdlGradient
> pGradHdl(new SdrHdlGradient(aTmpPos1
, aTmpPos2
, true));
1707 DBG_ASSERT(pColHdl1
&& pColHdl2
&& pGradHdl
, "Could not get all necessary handles!");
1710 pGradHdl
->SetColorHandles(pColHdl1
.get(), pColHdl2
.get());
1711 pGradHdl
->SetObj(pObj
);
1712 pColHdl1
->SetColorChangeHdl(LINK(pGradHdl
.get(), SdrHdlGradient
, ColorChangeHdl
));
1713 pColHdl2
->SetColorChangeHdl(LINK(pGradHdl
.get(), SdrHdlGradient
, ColorChangeHdl
));
1716 maHdlList
.AddHdl(std::move(pColHdl1
));
1717 maHdlList
.AddHdl(std::move(pColHdl2
));
1718 maHdlList
.AddHdl(std::move(pGradHdl
));
1723 case SdrDragMode::Crop
:
1732 /** handle mouse over effects for handles */
1733 bool SdrMarkView::MouseMove(const MouseEvent
& rMEvt
, OutputDevice
* pWin
)
1735 if(maHdlList
.GetHdlCount())
1737 SdrHdl
* pMouseOverHdl
= nullptr;
1738 if( !rMEvt
.IsLeaveWindow() && pWin
)
1740 Point
aMDPos( pWin
->PixelToLogic( rMEvt
.GetPosPixel() ) );
1741 pMouseOverHdl
= PickHandle(aMDPos
);
1744 // notify last mouse over handle that he lost the mouse
1745 const size_t nHdlCount
= maHdlList
.GetHdlCount();
1747 for(size_t nHdl
= 0; nHdl
< nHdlCount
; ++nHdl
)
1749 SdrHdl
* pCurrentHdl
= GetHdl(nHdl
);
1750 if( pCurrentHdl
->mbMouseOver
)
1752 if( pCurrentHdl
!= pMouseOverHdl
)
1754 pCurrentHdl
->mbMouseOver
= false;
1755 pCurrentHdl
->onMouseLeave();
1761 // notify current mouse over handle
1764 pMouseOverHdl
->mbMouseOver
= true;
1765 pMouseOverHdl
->onMouseEnter(rMEvt
);
1768 return SdrSnapView::MouseMove(rMEvt
, pWin
);
1771 bool SdrMarkView::RequestHelp(const HelpEvent
& rHEvt
)
1773 if (maHdlList
.GetHdlCount())
1775 const size_t nHdlCount
= maHdlList
.GetHdlCount();
1777 for (size_t nHdl
= 0; nHdl
< nHdlCount
; ++nHdl
)
1779 SdrHdl
* pCurrentHdl
= GetHdl(nHdl
);
1780 if (pCurrentHdl
->mbMouseOver
)
1782 pCurrentHdl
->onHelpRequest();
1787 return SdrSnapView::RequestHelp(rHEvt
);
1790 void SdrMarkView::ForceRefToMarked()
1794 case SdrDragMode::Rotate
:
1796 tools::Rectangle
aR(GetMarkedObjRect());
1797 maRef1
= aR
.Center();
1802 case SdrDragMode::Mirror
:
1804 // first calculate the length of the axis of reflection
1805 tools::Long nOutMin
=0;
1806 tools::Long nOutMax
=0;
1807 tools::Long nMinLen
=0;
1808 tools::Long nObjDst
=0;
1809 tools::Long nOutHgt
=0;
1810 OutputDevice
* pOut
=GetFirstOutputDevice();
1811 if (pOut
!=nullptr) {
1812 // minimum length: 50 pixels
1813 nMinLen
=pOut
->PixelToLogic(Size(0,50)).Height();
1814 // 20 pixels distance to the Obj for the reference point
1815 nObjDst
=pOut
->PixelToLogic(Size(0,20)).Height();
1817 // margin = minimum length = 10 pixels
1818 tools::Long nDst
=pOut
->PixelToLogic(Size(0,10)).Height();
1819 nOutMin
=-pOut
->GetMapMode().GetOrigin().Y();
1820 nOutMax
=pOut
->GetOutputSize().Height()-1+nOutMin
;
1823 // absolute minimum length, however, is 10 pixels
1824 if (nOutMax
-nOutMin
<nDst
) {
1827 nOutMin
-=(nDst
+1)/2;
1828 nOutMax
=nOutMin
+nDst
;
1830 nOutHgt
=nOutMax
-nOutMin
;
1831 // otherwise minimum length = 1/4 OutHgt
1832 tools::Long nTemp
=nOutHgt
/4;
1833 if (nTemp
>nMinLen
) nMinLen
=nTemp
;
1836 tools::Rectangle
aR(GetMarkedObjBoundRect());
1837 Point
aCenter(aR
.Center());
1838 tools::Long nMarkHgt
=aR
.GetHeight()-1;
1839 tools::Long nHgt
=nMarkHgt
+nObjDst
*2; // 20 pixels overlapping above and below
1840 if (nHgt
<nMinLen
) nHgt
=nMinLen
; // minimum length 50 pixels or 1/4 OutHgt, respectively
1842 tools::Long nY1
=aCenter
.Y()-(nHgt
+1)/2;
1843 tools::Long nY2
=nY1
+nHgt
;
1845 if (pOut
!=nullptr && nMinLen
>nOutHgt
) nMinLen
=nOutHgt
; // TODO: maybe shorten this a little
1847 if (pOut
!=nullptr) { // now move completely into the visible area
1850 if (nY2
<nY1
+nMinLen
) nY2
=nY1
+nMinLen
;
1854 if (nY1
>nY2
-nMinLen
) nY1
=nY2
-nMinLen
;
1858 maRef1
.setX(aCenter
.X() );
1860 maRef2
.setX(aCenter
.X() );
1866 case SdrDragMode::Transparence
:
1867 case SdrDragMode::Gradient
:
1868 case SdrDragMode::Crop
:
1870 tools::Rectangle
aRect(GetMarkedObjBoundRect());
1871 maRef1
= aRect
.TopLeft();
1872 maRef2
= aRect
.BottomRight();
1879 void SdrMarkView::SetRef1(const Point
& rPt
)
1881 if(meDragMode
== SdrDragMode::Rotate
|| meDragMode
== SdrDragMode::Mirror
)
1884 SdrHdl
* pH
= maHdlList
.GetHdl(SdrHdlKind::Ref1
);
1890 void SdrMarkView::SetRef2(const Point
& rPt
)
1892 if(meDragMode
== SdrDragMode::Mirror
)
1895 SdrHdl
* pH
= maHdlList
.GetHdl(SdrHdlKind::Ref2
);
1901 SfxViewShell
* SdrMarkView::GetSfxViewShell() const
1903 return SfxViewShell::Current();
1906 void SdrMarkView::CheckMarked()
1908 for (size_t nm
=GetMarkedObjectCount(); nm
>0;) {
1910 SdrMark
* pM
= GetSdrMarkByIndex(nm
);
1911 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1912 SdrPageView
* pPV
= pM
->GetPageView();
1913 bool bRaus
= !pObj
|| !pPV
->IsObjMarkable(pObj
);
1916 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1920 if (!IsGluePointEditMode()) { // selected gluepoints only in GlueEditMode
1921 SdrUShortCont
& rPts
= pM
->GetMarkedGluePoints();
1927 // at least reset the remembered BoundRect to prevent handle
1928 // generation if bForceFrameHandles is TRUE.
1929 mbMarkedObjRectDirty
= true;
1932 void SdrMarkView::SetMarkRects()
1934 SdrPageView
* pPV
= GetSdrPageView();
1938 pPV
->SetHasMarkedObj(GetMarkedObjectList().TakeSnapRect(pPV
, pPV
->MarkSnap()));
1939 GetMarkedObjectList().TakeBoundRect(pPV
, pPV
->MarkBound());
1943 void SdrMarkView::SetFrameHandles(bool bOn
)
1945 if (bOn
!=mbForceFrameHandles
) {
1946 bool bOld
=ImpIsFrameHandles();
1947 mbForceFrameHandles
=bOn
;
1948 bool bNew
=ImpIsFrameHandles();
1951 MarkListHasChanged();
1956 void SdrMarkView::SetEditMode(SdrViewEditMode eMode
)
1958 if (eMode
==meEditMode
) return;
1960 bool bGlue0
=meEditMode
==SdrViewEditMode::GluePointEdit
;
1961 bool bEdge0
=static_cast<SdrCreateView
*>(this)->IsEdgeTool();
1962 meEditMode0
=meEditMode
;
1964 bool bGlue1
=meEditMode
==SdrViewEditMode::GluePointEdit
;
1965 bool bEdge1
=static_cast<SdrCreateView
*>(this)->IsEdgeTool();
1966 // avoid flickering when switching between GlueEdit and EdgeTool
1967 if (bGlue1
&& !bGlue0
) ImpSetGlueVisible2(bGlue1
);
1968 if (bEdge1
!=bEdge0
) ImpSetGlueVisible3(bEdge1
);
1969 if (!bGlue1
&& bGlue0
) ImpSetGlueVisible2(bGlue1
);
1970 if (bGlue0
&& !bGlue1
) UnmarkAllGluePoints();
1974 bool SdrMarkView::IsObjMarkable(SdrObject
const * pObj
, SdrPageView
const * pPV
) const
1978 if (pObj
->IsMarkProtect() ||
1979 (!mbDesignMode
&& pObj
->IsUnoObj()))
1981 // object not selectable or
1982 // SdrUnoObj not in DesignMode
1986 return pPV
==nullptr || pPV
->IsObjMarkable(pObj
);
1989 bool SdrMarkView::IsMarkedObjHit(const Point
& rPnt
, short nTol
) const
1992 nTol
=ImpGetHitTolLogic(nTol
,nullptr);
1993 for (size_t nm
=0; nm
<GetMarkedObjectCount() && !bRet
; ++nm
) {
1994 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1995 bRet
= nullptr != CheckSingleSdrObjectHit(rPnt
,sal_uInt16(nTol
),pM
->GetMarkedSdrObj(),pM
->GetPageView(),SdrSearchOptions::NONE
,nullptr);
2000 SdrHdl
* SdrMarkView::PickHandle(const Point
& rPnt
) const
2002 if (mbSomeObjChgdFlag
) { // recalculate handles, if necessary
2003 FlushComeBackTimer();
2005 return maHdlList
.IsHdlListHit(rPnt
);
2008 bool SdrMarkView::MarkObj(const Point
& rPnt
, short nTol
, bool bToggle
, bool bDeep
)
2011 nTol
=ImpGetHitTolLogic(nTol
,nullptr);
2012 SdrSearchOptions nOptions
=SdrSearchOptions::PICKMARKABLE
;
2013 if (bDeep
) nOptions
=nOptions
|SdrSearchOptions::DEEP
;
2014 SdrObject
* pObj
= PickObj(rPnt
, static_cast<sal_uInt16
>(nTol
), pPV
, nOptions
);
2016 bool bUnmark
=bToggle
&& IsObjMarked(pObj
);
2017 MarkObj(pObj
,pPV
,bUnmark
);
2019 return pObj
!= nullptr;
2022 bool SdrMarkView::MarkNextObj(bool bPrev
)
2024 SdrPageView
* pPageView
= GetSdrPageView();
2031 SortMarkedObjects();
2032 const size_t nMarkCount
=GetMarkedObjectCount();
2033 size_t nChgMarkNum
= SAL_MAX_SIZE
; // number of the MarkEntry we want to replace
2034 size_t nSearchObjNum
= bPrev
? 0 : SAL_MAX_SIZE
;
2035 if (nMarkCount
!=0) {
2036 nChgMarkNum
=bPrev
? 0 : nMarkCount
-1;
2037 SdrMark
* pM
=GetSdrMarkByIndex(nChgMarkNum
);
2038 OSL_ASSERT(pM
!=nullptr);
2039 if (pM
->GetMarkedSdrObj() != nullptr)
2040 nSearchObjNum
= pM
->GetMarkedSdrObj()->GetNavigationPosition();
2043 SdrObject
* pMarkObj
=nullptr;
2044 SdrObjList
* pSearchObjList
=pPageView
->GetObjList();
2045 const size_t nObjCount
= pSearchObjList
->GetObjCount();
2047 if (nSearchObjNum
>nObjCount
) nSearchObjNum
=nObjCount
;
2048 while (pMarkObj
==nullptr && ((!bPrev
&& nSearchObjNum
>0) || (bPrev
&& nSearchObjNum
<nObjCount
)))
2052 SdrObject
* pSearchObj
= pSearchObjList
->GetObjectForNavigationPosition(nSearchObjNum
);
2053 if (IsObjMarkable(pSearchObj
,pPageView
))
2055 if (TryToFindMarkedObject(pSearchObj
)==SAL_MAX_SIZE
)
2057 pMarkObj
=pSearchObj
;
2060 if (bPrev
) nSearchObjNum
++;
2069 if (nChgMarkNum
!=SAL_MAX_SIZE
)
2071 GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum
);
2073 MarkObj(pMarkObj
,pPageView
); // also calls MarkListHasChanged(), AdjustMarkHdl()
2077 bool SdrMarkView::MarkNextObj(const Point
& rPnt
, short nTol
, bool bPrev
)
2079 SortMarkedObjects();
2080 nTol
=ImpGetHitTolLogic(nTol
,nullptr);
2081 SdrMark
* pTopMarkHit
=nullptr;
2082 SdrMark
* pBtmMarkHit
=nullptr;
2083 size_t nTopMarkHit
=0;
2084 size_t nBtmMarkHit
=0;
2085 // find topmost of the selected objects that is hit by rPnt
2086 const size_t nMarkCount
=GetMarkedObjectCount();
2087 for (size_t nm
=nMarkCount
; nm
>0 && pTopMarkHit
==nullptr;) {
2089 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2090 if(CheckSingleSdrObjectHit(rPnt
,sal_uInt16(nTol
),pM
->GetMarkedSdrObj(),pM
->GetPageView(),SdrSearchOptions::NONE
,nullptr))
2096 // nothing found, in this case, just select an object
2097 if (pTopMarkHit
==nullptr) return MarkObj(rPnt
,sal_uInt16(nTol
));
2099 SdrObject
* pTopObjHit
=pTopMarkHit
->GetMarkedSdrObj();
2100 SdrObjList
* pObjList
=pTopObjHit
->getParentSdrObjListFromSdrObject();
2101 SdrPageView
* pPV
=pTopMarkHit
->GetPageView();
2102 // find lowermost of the selected objects that is hit by rPnt
2103 // and is placed on the same PageView as pTopMarkHit
2104 for (size_t nm
=0; nm
<nMarkCount
&& pBtmMarkHit
==nullptr; ++nm
) {
2105 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2106 SdrPageView
* pPV2
=pM
->GetPageView();
2107 if (pPV2
==pPV
&& CheckSingleSdrObjectHit(rPnt
,sal_uInt16(nTol
),pM
->GetMarkedSdrObj(),pPV2
,SdrSearchOptions::NONE
,nullptr))
2113 if (pBtmMarkHit
==nullptr) { pBtmMarkHit
=pTopMarkHit
; nBtmMarkHit
=nTopMarkHit
; }
2114 SdrObject
* pBtmObjHit
=pBtmMarkHit
->GetMarkedSdrObj();
2115 const size_t nObjCount
= pObjList
->GetObjCount();
2117 size_t nSearchBeg(0);
2118 E3dScene
* pScene(nullptr);
2119 SdrObject
* pObjHit(bPrev
? pBtmObjHit
: pTopObjHit
);
2121 nullptr != dynamic_cast< const E3dCompoundObject
* >(pObjHit
);
2124 pScene
= DynCastE3dScene(pObjHit
->getParentSdrObjectFromSdrObject());
2125 bRemap
= nullptr != pScene
;
2130 sal_uInt32
nOrdNumBtm(pBtmObjHit
->GetOrdNum());
2134 nOrdNumBtm
= pScene
->RemapOrdNum(nOrdNumBtm
);
2137 nSearchBeg
= nOrdNumBtm
+ 1;
2141 sal_uInt32
nOrdNumTop(pTopObjHit
->GetOrdNum());
2145 nOrdNumTop
= pScene
->RemapOrdNum(nOrdNumTop
);
2148 nSearchBeg
= nOrdNumTop
;
2151 size_t no
=nSearchBeg
;
2152 SdrObject
* pFndObj
=nullptr;
2153 while (pFndObj
==nullptr && ((!bPrev
&& no
>0) || (bPrev
&& no
<nObjCount
))) {
2159 pObj
= pObjList
->GetObj(pScene
->RemapOrdNum(no
));
2163 pObj
= pObjList
->GetObj(no
);
2166 if (CheckSingleSdrObjectHit(rPnt
,sal_uInt16(nTol
),pObj
,pPV
,SdrSearchOptions::TESTMARKABLE
,nullptr))
2168 if (TryToFindMarkedObject(pObj
)==SAL_MAX_SIZE
) {
2171 // TODO: for performance reasons set on to Top or Btm, if necessary
2176 if (pFndObj
!=nullptr)
2178 GetMarkedObjectListWriteAccess().DeleteMark(bPrev
?nBtmMarkHit
:nTopMarkHit
);
2179 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj
,pPV
));
2180 MarkListHasChanged();
2183 return pFndObj
!=nullptr;
2186 void SdrMarkView::MarkObj(const tools::Rectangle
& rRect
, bool bUnmark
)
2189 tools::Rectangle
aR(rRect
);
2190 SdrObjList
* pObjList
;
2192 SdrPageView
* pPV
= GetSdrPageView();
2196 pObjList
=pPV
->GetObjList();
2197 tools::Rectangle
aFrm1(aR
);
2198 for (const rtl::Reference
<SdrObject
>& pObj
: *pObjList
) {
2199 tools::Rectangle
aRect(pObj
->GetCurrentBoundRect());
2200 if (aFrm1
.Contains(aRect
)) {
2202 if (IsObjMarkable(pObj
.get(),pPV
))
2204 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj
.get(),pPV
));
2208 const size_t nPos
=TryToFindMarkedObject(pObj
.get());
2209 if (nPos
!=SAL_MAX_SIZE
)
2211 GetMarkedObjectListWriteAccess().DeleteMark(nPos
);
2219 SortMarkedObjects();
2220 MarkListHasChanged();
2227 void collectUIInformation(const SdrObject
* pObj
)
2229 EventDescription aDescription
;
2230 aDescription
.aAction
= "SELECT";
2231 aDescription
.aParent
= "MainWindow";
2232 aDescription
.aKeyWord
= "CurrentApp";
2234 if (!pObj
->GetName().isEmpty())
2235 aDescription
.aParameters
= {{"OBJECT", pObj
->GetName()}};
2237 aDescription
.aParameters
= {{"OBJECT", "Unnamed_Obj_" + OUString::number(pObj
->GetOrdNum())}};
2239 UITestLogger::getInstance().logEvent(aDescription
);
2244 void SdrMarkView::MarkObj(SdrObject
* pObj
, SdrPageView
* pPV
, bool bUnmark
, bool bDoNoSetMarkHdl
,
2245 std::vector
<basegfx::B2DRectangle
> && rSubSelections
)
2247 if (!(pObj
!=nullptr && pPV
!=nullptr && IsObjMarkable(pObj
, pPV
)))
2253 GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj
,pPV
));
2254 collectUIInformation(pObj
);
2258 const size_t nPos
=TryToFindMarkedObject(pObj
);
2259 if (nPos
!=SAL_MAX_SIZE
)
2261 GetMarkedObjectListWriteAccess().DeleteMark(nPos
);
2265 maSubSelectionList
= std::move(rSubSelections
);
2267 if (!bDoNoSetMarkHdl
) {
2268 MarkListHasChanged();
2273 bool SdrMarkView::IsObjMarked(SdrObject
const * pObj
) const
2275 return TryToFindMarkedObject(pObj
)!=SAL_MAX_SIZE
;
2278 sal_uInt16
SdrMarkView::GetMarkHdlSizePixel() const
2280 return maHdlList
.GetHdlSize()*2+1;
2283 void SdrMarkView::SetMarkHdlSizePixel(sal_uInt16 nSiz
)
2287 if (nSiz
!=maHdlList
.GetHdlSize()) {
2288 maHdlList
.SetHdlSize(nSiz
);
2292 bool SdrMarkView::getPossibleGridOffsetForSdrObject(
2293 basegfx::B2DVector
& rOffset
,
2294 const SdrObject
* pObj
,
2295 const SdrPageView
* pPV
) const
2297 if(nullptr == pObj
|| nullptr == pPV
)
2302 const OutputDevice
* pOutputDevice(GetFirstOutputDevice());
2304 if(nullptr == pOutputDevice
)
2309 const SdrPageWindow
* pSdrPageWindow(pPV
->FindPageWindow(*pOutputDevice
));
2311 if(nullptr == pSdrPageWindow
)
2316 const sdr::contact::ObjectContact
& rObjectContact(pSdrPageWindow
->GetObjectContact());
2318 if(!rObjectContact
.supportsGridOffsets())
2323 const sdr::contact::ViewObjectContact
& rVOC(pObj
->GetViewContact().GetViewObjectContact(
2324 const_cast<sdr::contact::ObjectContact
&>(rObjectContact
)));
2326 rOffset
= rVOC
.getGridOffset();
2328 return !rOffset
.equalZero();
2331 bool SdrMarkView::getPossibleGridOffsetForPosition(
2332 basegfx::B2DVector
& rOffset
,
2333 const basegfx::B2DPoint
& rPoint
,
2334 const SdrPageView
* pPV
) const
2341 const OutputDevice
* pOutputDevice(GetFirstOutputDevice());
2343 if(nullptr == pOutputDevice
)
2348 const SdrPageWindow
* pSdrPageWindow(pPV
->FindPageWindow(*pOutputDevice
));
2350 if(nullptr == pSdrPageWindow
)
2355 const sdr::contact::ObjectContact
& rObjectContact(pSdrPageWindow
->GetObjectContact());
2357 if(!rObjectContact
.supportsGridOffsets())
2362 rObjectContact
.calculateGridOffsetForB2DRange(rOffset
, basegfx::B2DRange(rPoint
));
2364 return !rOffset
.equalZero();
2367 SdrObject
* SdrMarkView::CheckSingleSdrObjectHit(const Point
& rPnt
, sal_uInt16 nTol
, SdrObject
* pObj
, SdrPageView
* pPV
, SdrSearchOptions nOptions
, const SdrLayerIDSet
* pMVisLay
) const
2369 if(((nOptions
& SdrSearchOptions::IMPISMASTER
) && pObj
->IsNotVisibleAsMaster()) || (!pObj
->IsVisible()))
2374 const bool bCheckIfMarkable(nOptions
& SdrSearchOptions::TESTMARKABLE
);
2375 const bool bDeep(nOptions
& SdrSearchOptions::DEEP
);
2376 const bool bOLE(dynamic_cast< const SdrOle2Obj
* >(pObj
) != nullptr);
2377 auto pTextObj
= DynCastSdrTextObj( pObj
);
2378 const bool bTXT(pTextObj
&& pTextObj
->IsTextFrame());
2379 SdrObject
* pRet
=nullptr;
2380 tools::Rectangle
aRect(pObj
->GetCurrentBoundRect());
2382 // add possible GridOffset to up-to-now view-independent BoundRect data
2383 basegfx::B2DVector
aGridOffset(0.0, 0.0);
2384 if(getPossibleGridOffsetForSdrObject(aGridOffset
, pObj
, pPV
))
2387 basegfx::fround(aGridOffset
.getX()),
2388 basegfx::fround(aGridOffset
.getY()));
2393 // double tolerance for OLE, text frames and objects in
2395 if(bOLE
|| bTXT
|| pObj
==static_cast<const SdrObjEditView
*>(this)->GetTextEditObject())
2400 aRect
.AdjustLeft( -nTol2
); // add 1 tolerance for all objects
2401 aRect
.AdjustTop( -nTol2
);
2402 aRect
.AdjustRight(nTol2
);
2403 aRect
.AdjustBottom(nTol2
);
2405 if (aRect
.Contains(rPnt
))
2407 if (!bCheckIfMarkable
|| IsObjMarkable(pObj
,pPV
))
2409 SdrObjList
* pOL
=pObj
->GetSubList();
2411 if (pOL
!=nullptr && pOL
->GetObjCount()!=0)
2414 // adjustment hit point for virtual objects
2417 if ( auto pVirtObj
= dynamic_cast<const SdrVirtObj
*>( pObj
) )
2419 Point aOffset
= pVirtObj
->GetOffset();
2420 aPnt
.Move( -aOffset
.X(), -aOffset
.Y() );
2423 pRet
=CheckSingleSdrObjectHit(aPnt
,nTol
,pOL
,pPV
,nOptions
,pMVisLay
,pTmpObj
);
2427 if(!pMVisLay
|| pMVisLay
->IsSet(pObj
->GetLayer()))
2429 pRet
= SdrObjectPrimitiveHit(*pObj
, rPnt
, {nTol2
, nTol2
}, *pPV
, &pPV
->GetVisibleLayers(), false);
2435 if (!bDeep
&& pRet
!=nullptr)
2443 SdrObject
* SdrMarkView::CheckSingleSdrObjectHit(const Point
& rPnt
, sal_uInt16 nTol
, SdrObjList
const * pOL
, SdrPageView
* pPV
, SdrSearchOptions nOptions
, const SdrLayerIDSet
* pMVisLay
, SdrObject
*& rpRootObj
) const
2445 return (*this).CheckSingleSdrObjectHit(rPnt
,nTol
,pOL
,pPV
,nOptions
,pMVisLay
,rpRootObj
,nullptr);
2447 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
2449 SdrObject
* pRet
=nullptr;
2453 const E3dScene
* pRemapScene
= DynCastE3dScene(pOL
->getSdrObjectFromSdrObjList());
2454 const size_t nObjCount(pOL
->GetObjCount());
2455 size_t nObjNum(nObjCount
);
2457 while (pRet
==nullptr && nObjNum
>0)
2464 pObj
= pOL
->GetObj(pRemapScene
->RemapOrdNum(nObjNum
));
2468 pObj
= pOL
->GetObj(nObjNum
);
2470 if (nOptions
& SdrSearchOptions::BEFOREMARK
)
2472 if (pMarkList
!=nullptr)
2474 if ((*pMarkList
).FindObject(pObj
)!=SAL_MAX_SIZE
)
2480 pRet
=CheckSingleSdrObjectHit(rPnt
,nTol
,pObj
,pPV
,nOptions
,pMVisLay
);
2481 if (pRet
!=nullptr) rpRootObj
=pObj
;
2486 SdrObject
* SdrMarkView::PickObj(const Point
& rPnt
, short nTol
, SdrPageView
*& rpPV
, SdrSearchOptions nOptions
) const
2488 return PickObj(rPnt
, nTol
, rpPV
, nOptions
, nullptr);
2491 SdrObject
* SdrMarkView::PickObj(const Point
& rPnt
, short nTol
, SdrPageView
*& rpPV
, SdrSearchOptions nOptions
, SdrObject
** ppRootObj
, bool* pbHitPassDirect
) const
2492 { // TODO: lacks a Pass2,Pass3
2493 SortMarkedObjects();
2494 if (ppRootObj
!=nullptr) *ppRootObj
=nullptr;
2495 if (pbHitPassDirect
!=nullptr) *pbHitPassDirect
=true;
2496 SdrObject
* pRet
= nullptr;
2498 bool bMarked(nOptions
& SdrSearchOptions::MARKED
);
2499 bool bMasters
=!bMarked
&& bool(nOptions
& SdrSearchOptions::ALSOONMASTER
);
2500 // nOptions & SdrSearchOptions::NEXT: n.i.
2501 // nOptions & SdrSearchOptions::PASS2BOUND: n.i.
2502 // nOptions & SdrSearchOptions::PASS3NEAREST// n.i.
2503 if (nTol
<0) nTol
=ImpGetHitTolLogic(nTol
,nullptr);
2504 SdrObject
* pObj
=nullptr;
2505 SdrObject
* pHitObj
=nullptr;
2506 SdrPageView
* pPV
=nullptr;
2507 if (static_cast<const SdrObjEditView
*>(this)->IsTextEditFrameHit(rPnt
)) {
2508 pObj
=static_cast<const SdrObjEditView
*>(this)->GetTextEditObject();
2510 pPV
=static_cast<const SdrObjEditView
*>(this)->GetTextEditPageView();
2513 const size_t nMrkCnt
=GetMarkedObjectCount();
2514 size_t nMrkNum
=nMrkCnt
;
2515 while (pHitObj
==nullptr && nMrkNum
>0) {
2517 SdrMark
* pM
=GetSdrMarkByIndex(nMrkNum
);
2518 pObj
=pM
->GetMarkedSdrObj();
2519 pPV
=pM
->GetPageView();
2520 pHitObj
=CheckSingleSdrObjectHit(rPnt
,nTol
,pObj
,pPV
,nOptions
,nullptr);
2525 pPV
= GetSdrPageView();
2529 SdrPage
* pPage
=pPV
->GetPage();
2530 sal_uInt16 nPgCount
=1;
2532 if(bMasters
&& pPage
->TRG_HasMasterPage())
2536 bool bWholePage(nOptions
& SdrSearchOptions::WHOLEPAGE
);
2537 bool bExtraPassForWholePage
=bWholePage
&& pPage
!=pPV
->GetObjList();
2538 if (bExtraPassForWholePage
) nPgCount
++; // First search in AktObjList, then on the entire page
2539 sal_uInt16 nPgNum
=nPgCount
;
2540 while (pHitObj
==nullptr && nPgNum
>0) {
2541 SdrSearchOptions nTmpOptions
=nOptions
;
2543 const SdrLayerIDSet
* pMVisLay
=nullptr;
2544 SdrObjList
* pObjList
=nullptr;
2545 if (pbHitPassDirect
!=nullptr) *pbHitPassDirect
= true;
2546 if (nPgNum
>=nPgCount
-1 || (bExtraPassForWholePage
&& nPgNum
>=nPgCount
-2))
2548 pObjList
=pPV
->GetObjList();
2549 if (bExtraPassForWholePage
&& nPgNum
==nPgCount
-2) {
2551 if (pbHitPassDirect
!=nullptr) *pbHitPassDirect
= false;
2556 // otherwise MasterPage
2557 SdrPage
& rMasterPage
= pPage
->TRG_GetMasterPage();
2558 pMVisLay
= &pPage
->TRG_GetMasterPageVisibleLayers();
2559 pObjList
= &rMasterPage
;
2561 if (pbHitPassDirect
!=nullptr) *pbHitPassDirect
= false;
2562 nTmpOptions
=nTmpOptions
| SdrSearchOptions::IMPISMASTER
;
2564 pHitObj
=CheckSingleSdrObjectHit(rPnt
,nTol
,pObjList
,pPV
,nTmpOptions
,pMVisLay
,pObj
,&(GetMarkedObjectList()));
2568 if (pHitObj
!=nullptr) {
2569 if (ppRootObj
!=nullptr) *ppRootObj
=pObj
;
2570 if (nOptions
& SdrSearchOptions::DEEP
) pObj
=pHitObj
;
2571 if (nOptions
& SdrSearchOptions::TESTTEXTEDIT
) {
2572 if (!pObj
->HasTextEdit() || pPV
->GetLockedLayers().IsSet(pObj
->GetLayer())) {
2576 if (pObj
!=nullptr && (nOptions
& SdrSearchOptions::TESTMACRO
)) {
2577 SdrObjMacroHitRec aHitRec
;
2580 aHitRec
.pVisiLayer
=&pPV
->GetVisibleLayers();
2581 aHitRec
.pPageView
=pPV
;
2582 if (!pObj
->HasMacro() || !pObj
->IsMacroHit(aHitRec
)) pObj
=nullptr;
2584 if (pObj
!=nullptr) {
2592 bool SdrMarkView::PickMarkedObj(const Point
& rPnt
, SdrObject
*& rpObj
, SdrPageView
*& rpPV
, SdrSearchOptions nOptions
) const
2594 SortMarkedObjects();
2595 const bool bBoundCheckOn2ndPass(nOptions
& SdrSearchOptions::PASS2BOUND
);
2598 const size_t nMarkCount
=GetMarkedObjectCount();
2599 for (size_t nMarkNum
=nMarkCount
; nMarkNum
>0;) {
2601 SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
2602 SdrPageView
* pPV
=pM
->GetPageView();
2603 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2604 if (CheckSingleSdrObjectHit(rPnt
,mnHitTolLog
,pObj
,pPV
,SdrSearchOptions::TESTMARKABLE
,nullptr)) {
2610 if (bBoundCheckOn2ndPass
) {
2611 for (size_t nMarkNum
=nMarkCount
; nMarkNum
>0;) {
2613 SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
2614 SdrPageView
* pPV
=pM
->GetPageView();
2615 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2616 tools::Rectangle
aRect(pObj
->GetCurrentBoundRect());
2617 aRect
.AdjustLeft( -mnHitTolLog
);
2618 aRect
.AdjustTop( -mnHitTolLog
);
2619 aRect
.AdjustRight(mnHitTolLog
);
2620 aRect
.AdjustBottom(mnHitTolLog
);
2621 if (aRect
.Contains(rPnt
)) {
2632 void SdrMarkView::UnmarkAllObj(SdrPageView
const * pPV
)
2634 if (GetMarkedObjectCount()==0)
2640 GetMarkedObjectListWriteAccess().DeletePageView(*pPV
);
2644 GetMarkedObjectListWriteAccess().Clear();
2646 mpMarkedObj
=nullptr;
2648 MarkListHasChanged();
2652 void SdrMarkView::MarkAllObj(SdrPageView
* pPV
)
2658 pPV
= GetSdrPageView();
2661 // #i69171# pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting
2665 const bool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*pPV
));
2669 MarkListHasChanged();
2673 if(GetMarkedObjectCount())
2679 void SdrMarkView::AdjustMarkHdl(SfxViewShell
* pOtherShell
)
2683 SetMarkHandles(pOtherShell
);
2686 // BoundRect in model coordinates, no GridOffset added
2687 tools::Rectangle
SdrMarkView::GetMarkedObjBoundRect() const
2689 tools::Rectangle aRect
;
2690 for (size_t nm
=0; nm
<GetMarkedObjectCount(); ++nm
) {
2691 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2692 SdrObject
* pO
=pM
->GetMarkedSdrObj();
2693 tools::Rectangle
aR1(pO
->GetCurrentBoundRect());
2694 if (aRect
.IsEmpty()) aRect
=aR1
;
2695 else aRect
.Union(aR1
);
2700 // ObjRect in model coordinates, no GridOffset added
2701 const tools::Rectangle
& SdrMarkView::GetMarkedObjRect() const
2703 if (mbMarkedObjRectDirty
) {
2704 const_cast<SdrMarkView
*>(this)->mbMarkedObjRectDirty
=false;
2705 tools::Rectangle aRect
;
2706 for (size_t nm
=0; nm
<GetMarkedObjectCount(); ++nm
) {
2707 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2708 SdrObject
* pO
= pM
->GetMarkedSdrObj();
2711 tools::Rectangle
aR1(pO
->GetSnapRect());
2712 if (aRect
.IsEmpty()) aRect
=aR1
;
2713 else aRect
.Union(aR1
);
2715 const_cast<SdrMarkView
*>(this)->maMarkedObjRect
=aRect
;
2717 return maMarkedObjRect
;
2721 OUString
SdrMarkView::ImpGetDescriptionString(TranslateId pStrCacheID
, ImpGetDescriptionOptions nOpt
) const
2723 OUString sStr
= SvxResId(pStrCacheID
);
2724 const sal_Int32 nPos
= sStr
.indexOf("%1");
2728 if(nOpt
== ImpGetDescriptionOptions::POINTS
)
2730 sStr
= sStr
.replaceAt(nPos
, 2, GetDescriptionOfMarkedPoints());
2732 else if(nOpt
== ImpGetDescriptionOptions::GLUEPOINTS
)
2734 sStr
= sStr
.replaceAt(nPos
, 2, GetDescriptionOfMarkedGluePoints());
2738 sStr
= sStr
.replaceAt(nPos
, 2, GetDescriptionOfMarkedObjects());
2742 return sStr
.replaceFirst("%2", "0");
2746 void SdrMarkView::EnterMarkedGroup()
2748 // We enter only the first group found (in only one PageView), because
2749 // PageView::EnterGroup calls an AdjustMarkHdl.
2750 // TODO: I'll have to prevent that via a flag.
2751 SdrPageView
* pPV
= GetSdrPageView();
2757 for (size_t nm
= GetMarkedObjectCount(); nm
> 0 && !bEnter
;)
2760 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2761 if (pM
->GetPageView()==pPV
) {
2762 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2763 if (pObj
->IsGroupObject()) {
2764 if (pPV
->EnterGroup(pObj
)) {
2773 void SdrMarkView::MarkListHasChanged()
2775 GetMarkedObjectListWriteAccess().SetNameDirty();
2776 maSdrViewSelection
.SetEdgesOfMarkedNodesDirty();
2778 mbMarkedObjRectDirty
=true;
2779 mbMarkedPointsRectsDirty
=true;
2780 bool bOneEdgeMarked
=false;
2781 if (GetMarkedObjectCount()==1) {
2782 const SdrObject
* pObj
=GetMarkedObjectByIndex(0);
2783 if (pObj
->GetObjInventor()==SdrInventor::Default
) {
2784 bOneEdgeMarked
= pObj
->GetObjIdentifier() == SdrObjKind::Edge
;
2787 ImpSetGlueVisible4(bOneEdgeMarked
);
2791 void SdrMarkView::SetMoveOutside(bool bOn
)
2793 maHdlList
.SetMoveOutside(bOn
);
2796 void SdrMarkView::SetDesignMode( bool bOn
)
2798 if ( mbDesignMode
!= bOn
)
2801 SdrPageView
* pPageView
= GetSdrPageView();
2803 pPageView
->SetDesignMode( bOn
);
2807 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */