Bug Summary

File:home/maarten/src/libreoffice/core/svx/source/svdraw/svdmrkv.cxx
Warning:line 1825, column 31
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

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