Bug Summary

File:home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx
Warning:line 1629, column 13
Use of memory after it is freed

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 svdedxv.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/svdedxv.cxx

/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.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#include <com/sun/star/i18n/WordType.hpp>
21#include <editeng/editdata.hxx>
22#include <editeng/editeng.hxx>
23#include <editeng/editobj.hxx>
24#include <editeng/editstat.hxx>
25#include <editeng/outlobj.hxx>
26#include <editeng/unotext.hxx>
27#include <svl/itemiter.hxx>
28#include <svl/style.hxx>
29#include <svl/whiter.hxx>
30#include <svtools/accessibilityoptions.hxx>
31#include <svx/sdtfchim.hxx>
32#include <svx/selectioncontroller.hxx>
33#include <svx/svdedxv.hxx>
34#include <svx/svdetc.hxx>
35#include <svx/svdotable.hxx>
36#include <svx/svdotext.hxx>
37#include <svx/svdoutl.hxx>
38#include <svx/svdpage.hxx>
39#include <svx/svdpagv.hxx>
40#include <svx/svdundo.hxx>
41#include <vcl/canvastools.hxx>
42#include <vcl/commandevent.hxx>
43#include <vcl/cursor.hxx>
44#include <vcl/weld.hxx>
45#include <comphelper/lok.hxx>
46#include <drawinglayer/processor2d/baseprocessor2d.hxx>
47#include <drawinglayer/processor2d/processor2dtools.hxx>
48#include <editeng/outliner.hxx>
49#include <sal/log.hxx>
50#include <sdr/overlay/overlaytools.hxx>
51#include <sfx2/viewsh.hxx>
52#include <svx/dialmgr.hxx>
53#include <svx/sdr/overlay/overlaymanager.hxx>
54#include <svx/sdr/overlay/overlayselection.hxx>
55#include <svx/sdr/table/tablecontroller.hxx>
56#include <svx/sdrpagewindow.hxx>
57#include <svx/sdrpaintwindow.hxx>
58#include <svx/sdrundomanager.hxx>
59#include <svx/strings.hrc>
60#include <svx/svdviter.hxx>
61#include <textchain.hxx>
62#include <textchaincursor.hxx>
63#include <tools/debug.hxx>
64#include <vcl/svapp.hxx>
65
66#include <memory>
67
68SdrObjEditView::SdrObjEditView(SdrModel& rSdrModel, OutputDevice* pOut)
69 : SdrGlueEditView(rSdrModel, pOut)
70 , pTextEditPV(nullptr)
71 , pTextEditOutlinerView(nullptr)
72 , pTextEditWin(nullptr)
73 , pTextEditCursorBuffer(nullptr)
74 , pMacroObj(nullptr)
75 , pMacroPV(nullptr)
76 , pMacroWin(nullptr)
77 , nMacroTol(0)
78 , bTextEditDontDelete(false)
79 , bTextEditOnlyOneView(false)
80 , bTextEditNewObj(false)
81 , bQuickTextEditMode(true)
82 , bMacroDown(false)
83 , mpOldTextEditUndoManager(nullptr)
84{
85}
86
87SdrObjEditView::~SdrObjEditView()
88{
89 pTextEditWin = nullptr; // so there's no ShowCursor in SdrEndTextEdit
90 assert(!IsTextEdit())(static_cast <bool> (!IsTextEdit()) ? void (0) : __assert_fail
("!IsTextEdit()", "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
, 90, __extension__ __PRETTY_FUNCTION__))
;
91 if (IsTextEdit())
92 SdrEndTextEdit();
93 pTextEditOutliner.reset();
94 assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager
) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager"
, "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
, 94, __extension__ __PRETTY_FUNCTION__))
; // should have been reset
95}
96
97bool SdrObjEditView::IsAction() const { return IsMacroObj() || SdrGlueEditView::IsAction(); }
98
99void SdrObjEditView::MovAction(const Point& rPnt)
100{
101 if (IsMacroObj())
102 MovMacroObj(rPnt);
103 SdrGlueEditView::MovAction(rPnt);
104}
105
106void SdrObjEditView::EndAction()
107{
108 if (IsMacroObj())
109 EndMacroObj();
110 SdrGlueEditView::EndAction();
111}
112
113void SdrObjEditView::BckAction()
114{
115 BrkMacroObj();
116 SdrGlueEditView::BckAction();
117}
118
119void SdrObjEditView::BrkAction()
120{
121 BrkMacroObj();
122 SdrGlueEditView::BrkAction();
123}
124
125SdrPageView* SdrObjEditView::ShowSdrPage(SdrPage* pPage)
126{
127 SdrPageView* pPageView = SdrGlueEditView::ShowSdrPage(pPage);
128
129 if (comphelper::LibreOfficeKit::isActive() && pPageView)
130 {
131 // Check if other views have an active text edit on the same page as
132 // this one.
133 SdrViewIter aIter(pPageView->GetPage());
134 for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
135 {
136 if (pView == this || !pView->IsTextEdit())
137 continue;
138
139 OutputDevice* pOutDev = GetFirstOutputDevice();
140 if (!pOutDev || pOutDev->GetOutDevType() != OUTDEV_WINDOW)
141 continue;
142
143 // Found one, so create an outliner view, to get invalidations when
144 // the text edit changes.
145 // Call GetSfxViewShell() to make sure ImpMakeOutlinerView()
146 // registers the view shell of this draw view, and not the view
147 // shell of pView.
148 OutlinerView* pOutlinerView = pView->ImpMakeOutlinerView(
149 static_cast<vcl::Window*>(pOutDev), nullptr, GetSfxViewShell());
150 pOutlinerView->HideCursor();
151 pView->GetTextEditOutliner()->InsertView(pOutlinerView);
152 }
153 }
154
155 return pPageView;
156}
157
158namespace
159{
160/// Removes outliner views registered in other draw views that use pOutputDevice.
161void lcl_RemoveTextEditOutlinerViews(SdrObjEditView const* pThis, SdrPageView const* pPageView,
162 OutputDevice const* pOutputDevice)
163{
164 if (!comphelper::LibreOfficeKit::isActive())
165 return;
166
167 if (!pPageView)
168 return;
169
170 if (!pOutputDevice || pOutputDevice->GetOutDevType() != OUTDEV_WINDOW)
171 return;
172
173 SdrViewIter aIter(pPageView->GetPage());
174 for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
175 {
176 if (pView == pThis || !pView->IsTextEdit())
177 continue;
178
179 SdrOutliner* pOutliner = pView->GetTextEditOutliner();
180 for (size_t nView = 0; nView < pOutliner->GetViewCount(); ++nView)
181 {
182 OutlinerView* pOutlinerView = pOutliner->GetView(nView);
183 if (pOutlinerView->GetWindow() != pOutputDevice)
184 continue;
185
186 pOutliner->RemoveView(pOutlinerView);
187 delete pOutlinerView;
188 }
189 }
190}
191}
192
193void SdrObjEditView::HideSdrPage()
194{
195 lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), GetFirstOutputDevice());
196
197 SdrGlueEditView::HideSdrPage();
198}
199
200void SdrObjEditView::TakeActionRect(tools::Rectangle& rRect) const
201{
202 if (IsMacroObj())
203 {
204 rRect = pMacroObj->GetCurrentBoundRect();
205 }
206 else
207 {
208 SdrGlueEditView::TakeActionRect(rRect);
209 }
210}
211
212void SdrObjEditView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
213{
214 SdrGlueEditView::Notify(rBC, rHint);
215 if (pTextEditOutliner == nullptr)
216 return;
217
218 // change of printer while editing
219 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
220 return;
221
222 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
223 SdrHintKind eKind = pSdrHint->GetKind();
224 if (eKind == SdrHintKind::RefDeviceChange)
225 {
226 pTextEditOutliner->SetRefDevice(mpModel->GetRefDevice());
227 }
228 if (eKind == SdrHintKind::DefaultTabChange)
229 {
230 pTextEditOutliner->SetDefTab(mpModel->GetDefaultTabulator());
231 }
232}
233
234void SdrObjEditView::ModelHasChanged()
235{
236 SdrGlueEditView::ModelHasChanged();
237 if (mxTextEditObj.is() && !mxTextEditObj->IsInserted())
238 SdrEndTextEdit(); // object deleted
239 // TextEditObj changed?
240 if (!IsTextEdit())
241 return;
242
243 SdrTextObj* pTextObj = mxTextEditObj.get();
244 if (pTextObj != nullptr)
245 {
246 size_t nOutlViewCnt = pTextEditOutliner->GetViewCount();
247 bool bAreaChg = false;
248 bool bAnchorChg = false;
249 bool bColorChg = false;
250 bool bContourFrame = pTextObj->IsContourTextFrame();
251 EEAnchorMode eNewAnchor(EEAnchorMode::VCenterHCenter);
252 tools::Rectangle aOldArea(aMinTextEditArea);
253 aOldArea.Union(aTextEditArea);
254 Color aNewColor;
255 { // check area
256 Size aPaperMin1;
257 Size aPaperMax1;
258 tools::Rectangle aEditArea1;
259 tools::Rectangle aMinArea1;
260 pTextObj->TakeTextEditArea(&aPaperMin1, &aPaperMax1, &aEditArea1, &aMinArea1);
261 Point aPvOfs(pTextObj->GetTextEditOffset());
262
263 // add possible GridOffset to up-to-now view-independent EditAreas
264 basegfx::B2DVector aGridOffset(0.0, 0.0);
265 if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, GetSdrPageView()))
266 {
267 const Point aOffset(basegfx::fround(aGridOffset.getX()),
268 basegfx::fround(aGridOffset.getY()));
269
270 aEditArea1 += aOffset;
271 aMinArea1 += aOffset;
272 }
273
274 aEditArea1.Move(aPvOfs.X(), aPvOfs.Y());
275 aMinArea1.Move(aPvOfs.X(), aPvOfs.Y());
276 tools::Rectangle aNewArea(aMinArea1);
277 aNewArea.Union(aEditArea1);
278
279 if (aNewArea != aOldArea || aEditArea1 != aTextEditArea || aMinArea1 != aMinTextEditArea
280 || pTextEditOutliner->GetMinAutoPaperSize() != aPaperMin1
281 || pTextEditOutliner->GetMaxAutoPaperSize() != aPaperMax1)
282 {
283 aTextEditArea = aEditArea1;
284 aMinTextEditArea = aMinArea1;
285 pTextEditOutliner->SetUpdateMode(false);
286 pTextEditOutliner->SetMinAutoPaperSize(aPaperMin1);
287 pTextEditOutliner->SetMaxAutoPaperSize(aPaperMax1);
288 pTextEditOutliner->SetPaperSize(Size(0, 0)); // re-format Outliner
289 if (!bContourFrame)
290 {
291 pTextEditOutliner->ClearPolygon();
292 EEControlBits nStat = pTextEditOutliner->GetControlWord();
293 nStat |= EEControlBits::AUTOPAGESIZE;
294 pTextEditOutliner->SetControlWord(nStat);
295 }
296 else
297 {
298 EEControlBits nStat = pTextEditOutliner->GetControlWord();
299 nStat &= ~EEControlBits::AUTOPAGESIZE;
300 pTextEditOutliner->SetControlWord(nStat);
301 tools::Rectangle aAnchorRect;
302 pTextObj->TakeTextAnchorRect(aAnchorRect);
303 pTextObj->ImpSetContourPolygon(*pTextEditOutliner, aAnchorRect, true);
304 }
305 for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++)
306 {
307 OutlinerView* pOLV = pTextEditOutliner->GetView(nOV);
308 EVControlBits nStat0 = pOLV->GetControlWord();
309 EVControlBits nStat = nStat0;
310 // AutoViewSize only if not ContourFrame.
311 if (!bContourFrame)
312 nStat |= EVControlBits::AUTOSIZE;
313 else
314 nStat &= ~EVControlBits::AUTOSIZE;
315 if (nStat != nStat0)
316 pOLV->SetControlWord(nStat);
317 }
318 pTextEditOutliner->SetUpdateMode(true);
319 bAreaChg = true;
320 }
321 }
322 if (pTextEditOutlinerView != nullptr)
323 { // check fill and anchor
324 EEAnchorMode eOldAnchor = pTextEditOutlinerView->GetAnchorMode();
325 eNewAnchor = pTextObj->GetOutlinerViewAnchorMode();
326 bAnchorChg = eOldAnchor != eNewAnchor;
327 Color aOldColor(pTextEditOutlinerView->GetBackgroundColor());
328 aNewColor = GetTextEditBackgroundColor(*this);
329 bColorChg = aOldColor != aNewColor;
330 }
331 // refresh always when it's a contour frame. That
332 // refresh is necessary since it triggers the repaint
333 // which makes the Handles visible. Changes at TakeTextRect()
334 // seem to have resulted in a case where no refresh is executed.
335 // Before that, a refresh must have been always executed
336 // (else this error would have happened earlier), thus I
337 // even think here a refresh should be done always.
338 // Since follow-up problems cannot even be guessed I only
339 // add this one more case to the if below.
340 // BTW: It's VERY bad style that here, inside ModelHasChanged()
341 // the outliner is again massively changed for the text object
342 // in text edit mode. Normally, all necessary data should be
343 // set at SdrBeginTextEdit(). Some changes and value assigns in
344 // SdrBeginTextEdit() are completely useless since they are set here
345 // again on ModelHasChanged().
346 if (bContourFrame || bAreaChg || bAnchorChg || bColorChg)
347 {
348 for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++)
349 {
350 OutlinerView* pOLV = pTextEditOutliner->GetView(nOV);
351 { // invalidate old OutlinerView area
352 vcl::Window* pWin = pOLV->GetWindow();
353 tools::Rectangle aTmpRect(aOldArea);
354 sal_uInt16 nPixSiz = pOLV->GetInvalidateMore() + 1;
355 Size aMore(pWin->PixelToLogic(Size(nPixSiz, nPixSiz)));
356 aTmpRect.AdjustLeft(-(aMore.Width()));
357 aTmpRect.AdjustRight(aMore.Width());
358 aTmpRect.AdjustTop(-(aMore.Height()));
359 aTmpRect.AdjustBottom(aMore.Height());
360 InvalidateOneWin(*pWin, aTmpRect);
361 }
362 if (bAnchorChg)
363 pOLV->SetAnchorMode(eNewAnchor);
364 if (bColorChg)
365 pOLV->SetBackgroundColor(aNewColor);
366
367 pOLV->SetOutputArea(
368 aTextEditArea); // because otherwise, we're not re-anchoring correctly
369 ImpInvalidateOutlinerView(*pOLV);
370 }
371 pTextEditOutlinerView->ShowCursor();
372 }
373 }
374 ImpMakeTextCursorAreaVisible();
375}
376
377namespace
378{
379/**
380 Helper class to visualize the content of an active EditView as an
381 OverlayObject. These objects work with Primitives and are handled
382 from the OverlayManager(s) in place as needed.
383
384 It allows complete visualization of the content of the active
385 EditView without the need of Invalidates triggered by the EditView
386 and thus avoiding potentially expensive repaints by using the
387 automatically buffered Overlay mechanism.
388
389 It buffers as much as possible locally and *only* triggers a real
390 change (see call to objectChange()) when really needed.
391 */
392class TextEditOverlayObject : public sdr::overlay::OverlayObject
393{
394protected:
395 /// local access to associated sdr::overlay::OverlaySelection
396 sdr::overlay::OverlaySelection* mpOverlaySelection;
397
398 /// local definition depends on active OutlinerView
399 OutlinerView& mrOutlinerView;
400
401 /// geometry definitions with buffering
402 basegfx::B2DRange maLastRange;
403 basegfx::B2DRange maRange;
404
405 /// text content definitions with buffering
406 drawinglayer::primitive2d::Primitive2DContainer maTextPrimitives;
407 drawinglayer::primitive2d::Primitive2DContainer maLastTextPrimitives;
408
409 /// bitfield
410 bool mbVisualizeSurroundingFrame : 1;
411
412 // geometry creation for OverlayObject, can use local *Last* values
413 virtual drawinglayer::primitive2d::Primitive2DContainer
414 createOverlayObjectPrimitive2DSequence() override;
415
416public:
417 TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView,
418 bool bVisualizeSurroundingFrame);
419 virtual ~TextEditOverlayObject() override;
420
421 // data read access
422 const sdr::overlay::OverlaySelection* getOverlaySelection() const { return mpOverlaySelection; }
423 const OutlinerView& getOutlinerView() const { return mrOutlinerView; }
424
425 /// override to check conditions for last createOverlayObjectPrimitive2DSequence
426 virtual drawinglayer::primitive2d::Primitive2DContainer
427 getOverlayObjectPrimitive2DSequence() const override;
428
429 // data write access. In this OverlayObject we only have the
430 // callback that triggers detecting if something *has* changed
431 void checkDataChange(const basegfx::B2DRange& rMinTextEditArea);
432 void checkSelectionChange();
433};
434
435drawinglayer::primitive2d::Primitive2DContainer
436TextEditOverlayObject::createOverlayObjectPrimitive2DSequence()
437{
438 drawinglayer::primitive2d::Primitive2DContainer aRetval;
439
440 /// outer frame visualization
441 if (mbVisualizeSurroundingFrame)
442 {
443 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
444 const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
445 const sal_uInt16 nPixSiz(getOutlinerView().GetInvalidateMore() - 1);
446
447 aRetval.push_back(new drawinglayer::primitive2d::OverlayRectanglePrimitive(
448 maRange, getBaseColor().getBColor(), fTransparence, std::max(6, nPixSiz - 2), // grow
449 0.0, // shrink
450 0.0));
451 }
452
453 // add buffered TextPrimitives
454 aRetval.append(maTextPrimitives);
455
456 return aRetval;
457}
458
459TextEditOverlayObject::TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView,
460 bool bVisualizeSurroundingFrame)
461 : OverlayObject(rColor)
462 , mpOverlaySelection(nullptr)
463 , mrOutlinerView(rOutlinerView)
464 , maLastRange()
465 , maRange()
466 , maTextPrimitives()
467 , maLastTextPrimitives()
468 , mbVisualizeSurroundingFrame(bVisualizeSurroundingFrame)
469{
470 // no AA for TextEdit overlay
471 allowAntiAliase(false);
472
473 // create local OverlaySelection - this is an integral part of EditText
474 // visualization
475 const std::vector<basegfx::B2DRange> aEmptySelection{};
476 mpOverlaySelection = new sdr::overlay::OverlaySelection(sdr::overlay::OverlayType::Transparent,
477 rColor, aEmptySelection, true);
478}
479
480TextEditOverlayObject::~TextEditOverlayObject()
481{
482 if (getOverlaySelection())
483 {
484 delete mpOverlaySelection;
485 mpOverlaySelection = nullptr;
486 }
487
488 if (getOverlayManager())
489 {
490 getOverlayManager()->remove(*this);
491 }
492}
493
494drawinglayer::primitive2d::Primitive2DContainer
495TextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const
496{
497 if (!getPrimitive2DSequence().empty())
498 {
499 if (!maRange.equal(maLastRange) || maLastTextPrimitives != maTextPrimitives)
500 {
501 // conditions of last local decomposition have changed, delete to force new evaluation
502 const_cast<TextEditOverlayObject*>(this)->resetPrimitive2DSequence();
503 }
504 }
505
506 if (getPrimitive2DSequence().empty())
507 {
508 // remember new buffered values
509 const_cast<TextEditOverlayObject*>(this)->maLastRange = maRange;
510 const_cast<TextEditOverlayObject*>(this)->maLastTextPrimitives = maTextPrimitives;
511 }
512
513 // call base implementation
514 return OverlayObject::getOverlayObjectPrimitive2DSequence();
515}
516
517void TextEditOverlayObject::checkDataChange(const basegfx::B2DRange& rMinTextEditArea)
518{
519 bool bObjectChange(false);
520
521 // check current range
522 const tools::Rectangle aOutArea(mrOutlinerView.GetOutputArea());
523 basegfx::B2DRange aNewRange = vcl::unotools::b2DRectangleFromRectangle(aOutArea);
524 aNewRange.expand(rMinTextEditArea);
525
526 if (aNewRange != maRange)
527 {
528 maRange = aNewRange;
529 bObjectChange = true;
530 }
531
532 // check if text primitives did change
533 SdrOutliner* pSdrOutliner = dynamic_cast<SdrOutliner*>(getOutlinerView().GetOutliner());
534
535 if (pSdrOutliner)
536 {
537 // get TextPrimitives directly from active Outliner
538 basegfx::B2DHomMatrix aNewTransformA;
539 basegfx::B2DHomMatrix aNewTransformB;
540 basegfx::B2DRange aClipRange;
541 drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives;
542
543 // active Outliner is always in unified oriented coordinate system (currently)
544 // so just translate to TopLeft of visible Range. Keep in mind that top-left
545 // depends on vertical text and top-to-bottom text attributes
546 const tools::Rectangle aVisArea(mrOutlinerView.GetVisArea());
547 const bool bVerticalWriting(pSdrOutliner->IsVertical());
548 const bool bTopToBottom(pSdrOutliner->IsTopToBottom());
549 const double fStartInX(bVerticalWriting && bTopToBottom
550 ? aOutArea.Right() - aVisArea.Left()
551 : aOutArea.Left() - aVisArea.Left());
552 const double fStartInY(bVerticalWriting && !bTopToBottom
553 ? aOutArea.Bottom() - aVisArea.Top()
554 : aOutArea.Top() - aVisArea.Top());
555
556 aNewTransformB.translate(fStartInX, fStartInY);
557
558 // get the current TextPrimitives. This is the most expensive part
559 // of this mechanism, it *may* be possible to buffer layouted
560 // primitives per ParaPortion with/in/dependent on the EditEngine
561 // content if needed. For now, get and compare
562 SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
563 aNewTextPrimitives, *pSdrOutliner, aNewTransformA, aNewTransformB, aClipRange);
564
565 if (aNewTextPrimitives != maTextPrimitives)
566 {
567 maTextPrimitives = aNewTextPrimitives;
568 bObjectChange = true;
569 }
570 }
571
572 if (bObjectChange)
573 {
574 // if there really *was* a change signal the OverlayManager to
575 // refresh this object's visualization
576 objectChange();
577
578 // on data change, always do a SelectionChange, too
579 // since the selection is an integral part of text visualization
580 checkSelectionChange();
581 }
582}
583
584void TextEditOverlayObject::checkSelectionChange()
585{
586 if (!(getOverlaySelection() && getOverlayManager()))
587 return;
588
589 std::vector<tools::Rectangle> aLogicRects;
590 std::vector<basegfx::B2DRange> aLogicRanges;
591 const Size aLogicPixel(getOverlayManager()->getOutputDevice().PixelToLogic(Size(1, 1)));
592
593 // get logic selection
594 getOutlinerView().GetSelectionRectangles(aLogicRects);
595
596 aLogicRanges.reserve(aLogicRects.size());
597 for (const auto& aRect : aLogicRects)
598 {
599 // convert from logic Rectangles to logic Ranges, do not forget to add
600 // one Unit (in this case logical units for one pixel, pre-calculated)
601 aLogicRanges.emplace_back(
602 aRect.Left() - aLogicPixel.Width(), aRect.Top() - aLogicPixel.Height(),
603 aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height());
604 }
605
606 mpOverlaySelection->setRanges(aLogicRanges);
607}
608} // end of anonymous namespace
609
610// TextEdit
611
612// callback from the active EditView, forward to evtl. existing instances of the
613// TextEditOverlayObject(s). This will additionally update the selection which
614// is an integral part of the text visualization
615void SdrObjEditView::EditViewInvalidate(const tools::Rectangle&)
616{
617 if (!IsTextEdit())
618 return;
619
620 // MinTextRange may have changed. Forward it, too
621 const basegfx::B2DRange aMinTextRange
622 = vcl::unotools::b2DRectangleFromRectangle(aMinTextEditArea);
623
624 for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
625 {
626 TextEditOverlayObject* pCandidate
627 = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a));
628
629 if (pCandidate)
630 {
631 pCandidate->checkDataChange(aMinTextRange);
632 }
633 }
634}
635
636// callback from the active EditView, forward to evtl. existing instances of the
637// TextEditOverlayObject(s). This cvall *only* updates the selection visualization
638// which is e.g. used when only the selection is changed, but not the text
639void SdrObjEditView::EditViewSelectionChange()
640{
641 if (!IsTextEdit())
642 return;
643
644 for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
645 {
646 TextEditOverlayObject* pCandidate
647 = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a));
648
649 if (pCandidate)
650 {
651 pCandidate->checkSelectionChange();
652 }
653 }
654}
655
656OutputDevice& SdrObjEditView::EditViewOutputDevice() const { return *pTextEditWin; }
657
658void SdrObjEditView::EditViewInputContext(const InputContext& rInputContext)
659{
660 if (!pTextEditWin)
661 return;
662 pTextEditWin->SetInputContext(rInputContext);
663}
664
665void SdrObjEditView::EditViewCursorRect(const tools::Rectangle& rRect, int nExtTextInputWidth)
666{
667 if (!pTextEditWin)
668 return;
669 pTextEditWin->SetCursorRect(&rRect, nExtTextInputWidth);
670}
671
672void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow)
673{
674 if (!comphelper::LibreOfficeKit::isActive())
675 {
676 // adapt all TextEditOverlayObject(s), so call EditViewInvalidate()
677 // to update accordingly (will update selection, too). Suppress new
678 // stuff when LibreOfficeKit is active
679 EditViewInvalidate(tools::Rectangle());
680 }
681 else
682 {
683 // draw old text edit stuff
684 if (IsTextEdit())
685 {
686 const SdrOutliner* pActiveOutliner = GetTextEditOutliner();
687
688 if (pActiveOutliner)
689 {
690 const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount());
691
692 if (nViewCount)
693 {
694 const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion();
695 const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect());
696
697 for (sal_uInt32 i(0); i < nViewCount; i++)
698 {
699 OutlinerView* pOLV = pActiveOutliner->GetView(i);
700
701 // If rPaintWindow knows that the output device is a render
702 // context and is aware of the underlying vcl::Window,
703 // compare against that; that's how double-buffering can
704 // still find the matching OutlinerView.
705 OutputDevice* pOutputDevice = rPaintWindow.GetWindow()
706 ? rPaintWindow.GetWindow()
707 : &rPaintWindow.GetOutputDevice();
708 if (pOLV->GetWindow() == pOutputDevice
709 || comphelper::LibreOfficeKit::isActive())
710 {
711 ImpPaintOutlinerView(*pOLV, aCheckRect,
712 rPaintWindow.GetTargetOutputDevice());
713 return;
714 }
715 }
716 }
717 }
718 }
719 }
720}
721
722void SdrObjEditView::ImpPaintOutlinerView(OutlinerView& rOutlView, const tools::Rectangle& rRect,
723 OutputDevice& rTargetDevice) const
724{
725 const SdrTextObj* pText = GetTextEditObject();
726 bool bTextFrame(pText && pText->IsTextFrame());
727 bool bFitToSize(pTextEditOutliner->GetControlWord() & EEControlBits::STRETCHING);
728 bool bModified(pTextEditOutliner->IsModified());
729 tools::Rectangle aBlankRect(rOutlView.GetOutputArea());
730 aBlankRect.Union(aMinTextEditArea);
731 tools::Rectangle aPixRect(rTargetDevice.LogicToPixel(aBlankRect));
732
733 // in the tiled rendering case, the setup is incomplete, and we very
734 // easily get an empty rRect on input - that will cause that everything is
735 // clipped; happens in case of editing text inside a shape in Calc.
736 // FIXME would be better to complete the setup so that we don't get an
737 // empty rRect here
738 if (!comphelper::LibreOfficeKit::isActive() || !rRect.IsEmpty())
739 aBlankRect.Intersection(rRect);
740
741 rOutlView.GetOutliner()->SetUpdateMode(true); // Bugfix #22596#
742 rOutlView.Paint(aBlankRect, &rTargetDevice);
743
744 if (!bModified)
745 {
746 pTextEditOutliner->ClearModifyFlag();
747 }
748
749 if (bTextFrame && !bFitToSize)
750 {
751 // completely reworked to use primitives; this ensures same look and functionality
752 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
753 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor(
754 drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTargetDevice,
755 aViewInformation2D));
756
757 if (xProcessor)
758 {
759 const bool bMapModeEnabled(rTargetDevice.IsMapModeEnabled());
760 const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aPixRect);
761 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
762 const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
763 const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent()
764 * 0.01);
765 const sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1);
766 const drawinglayer::primitive2d::Primitive2DReference xReference(
767 new drawinglayer::primitive2d::OverlayRectanglePrimitive(
768 aRange, aHilightColor.getBColor(), fTransparence,
769 std::max(6, nPixSiz - 2), // grow
770 0.0, // shrink
771 0.0));
772 const drawinglayer::primitive2d::Primitive2DContainer aSequence{ xReference };
773
774 rTargetDevice.EnableMapMode(false);
775 xProcessor->process(aSequence);
776 rTargetDevice.EnableMapMode(bMapModeEnabled);
777 }
778 }
779
780 rOutlView.ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
781}
782
783void SdrObjEditView::ImpInvalidateOutlinerView(OutlinerView const& rOutlView) const
784{
785 vcl::Window* pWin = rOutlView.GetWindow();
786
787 if (!pWin)
788 return;
789
790 const SdrTextObj* pText = GetTextEditObject();
791 bool bTextFrame(pText && pText->IsTextFrame());
792 bool bFitToSize(pText && pText->IsFitToSize());
793
794 if (!bTextFrame || bFitToSize)
795 return;
796
797 tools::Rectangle aBlankRect(rOutlView.GetOutputArea());
798 aBlankRect.Union(aMinTextEditArea);
799 tools::Rectangle aPixRect(pWin->LogicToPixel(aBlankRect));
800 sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1);
801
802 aPixRect.AdjustLeft(-1);
803 aPixRect.AdjustTop(-1);
804 aPixRect.AdjustRight(1);
805 aPixRect.AdjustBottom(1);
806
807 {
808 // limit xPixRect because of driver problems when pixel coordinates are too far out
809 Size aMaxXY(pWin->GetOutputSizePixel());
810 long a(2 * nPixSiz);
811 long nMaxX(aMaxXY.Width() + a);
812 long nMaxY(aMaxXY.Height() + a);
813
814 if (aPixRect.Left() < -a)
815 aPixRect.SetLeft(-a);
816 if (aPixRect.Top() < -a)
817 aPixRect.SetTop(-a);
818 if (aPixRect.Right() > nMaxX)
819 aPixRect.SetRight(nMaxX);
820 if (aPixRect.Bottom() > nMaxY)
821 aPixRect.SetBottom(nMaxY);
822 }
823
824 tools::Rectangle aOuterPix(aPixRect);
825 aOuterPix.AdjustLeft(-nPixSiz);
826 aOuterPix.AdjustTop(-nPixSiz);
827 aOuterPix.AdjustRight(nPixSiz);
828 aOuterPix.AdjustBottom(nPixSiz);
829
830 bool bMapModeEnabled(pWin->IsMapModeEnabled());
831 pWin->EnableMapMode(false);
832 pWin->Invalidate(aOuterPix);
833 pWin->EnableMapMode(bMapModeEnabled);
834}
835
836OutlinerView* SdrObjEditView::ImpMakeOutlinerView(vcl::Window* pWin, OutlinerView* pGivenView,
837 SfxViewShell* pViewShell) const
838{
839 // background
840 Color aBackground(GetTextEditBackgroundColor(*this));
841 SdrTextObj* pText = mxTextEditObj.get();
842 bool bTextFrame = pText != nullptr && pText->IsTextFrame();
843 bool bContourFrame = pText != nullptr && pText->IsContourTextFrame();
844 // create OutlinerView
845 OutlinerView* pOutlView = pGivenView;
846 pTextEditOutliner->SetUpdateMode(false);
847
848 if (pOutlView == nullptr)
849 {
850 pOutlView = new OutlinerView(pTextEditOutliner.get(), pWin);
851 }
852 else
853 {
854 pOutlView->SetWindow(pWin);
855 }
856
857 // disallow scrolling
858 EVControlBits nStat = pOutlView->GetControlWord();
859 nStat &= ~EVControlBits::AUTOSCROLL;
860 // AutoViewSize only if not ContourFrame.
861 if (!bContourFrame)
862 nStat |= EVControlBits::AUTOSIZE;
863 if (bTextFrame)
864 {
865 sal_uInt16 nPixSiz = maHdlList.GetHdlSize() * 2 + 1;
866 nStat |= EVControlBits::INVONEMORE;
867 pOutlView->SetInvalidateMore(nPixSiz);
868 }
869 pOutlView->SetControlWord(nStat);
870 pOutlView->SetBackgroundColor(aBackground);
871
872 // In case we're in the process of constructing a new view shell,
873 // SfxViewShell::Current() may still point to the old one. So if possible,
874 // depend on the application owning this draw view to provide the view
875 // shell.
876 SfxViewShell* pSfxViewShell = pViewShell ? pViewShell : GetSfxViewShell();
877 pOutlView->RegisterViewShell(pSfxViewShell ? pSfxViewShell : SfxViewShell::Current());
878
879 if (pText != nullptr)
880 {
881 pOutlView->SetAnchorMode(pText->GetOutlinerViewAnchorMode());
882 pTextEditOutliner->SetFixedCellHeight(
883 pText->GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
884 }
885 // do update before setting output area so that aTextEditArea can be recalculated
886 pTextEditOutliner->SetUpdateMode(true);
887 pOutlView->SetOutputArea(aTextEditArea);
888 ImpInvalidateOutlinerView(*pOutlView);
889 return pOutlView;
890}
891
892IMPL_LINK(SdrObjEditView, ImpOutlinerStatusEventHdl, EditStatus&, rEditStat, void)void SdrObjEditView::LinkStubImpOutlinerStatusEventHdl(void *
instance, EditStatus& data) { return static_cast<SdrObjEditView
*>(instance)->ImpOutlinerStatusEventHdl(data); } void SdrObjEditView
::ImpOutlinerStatusEventHdl(EditStatus& rEditStat)
893{
894 if (pTextEditOutliner)
895 {
896 SdrTextObj* pTextObj = mxTextEditObj.get();
897 if (pTextObj)
898 {
899 pTextObj->onEditOutlinerStatusEvent(&rEditStat);
900 }
901 }
902}
903
904void SdrObjEditView::ImpChainingEventHdl()
905{
906 if (!pTextEditOutliner)
907 return;
908
909 SdrTextObj* pTextObj = mxTextEditObj.get();
910 OutlinerView* pOLV = GetTextEditOutlinerView();
911 if (pTextObj && pOLV)
912 {
913 TextChain* pTextChain = pTextObj->GetTextChain();
914
915 // XXX: IsChainable and GetNilChainingEvent are a bit mixed up atm
916 if (!pTextObj->IsChainable())
917 {
918 return;
919 }
920 // This is true during an underflow-caused overflow (with pEdtOutl->SetText())
921 if (pTextChain->GetNilChainingEvent(pTextObj))
922 {
923 return;
924 }
925
926 // We prevent to trigger further handling of overflow/underflow for pTextObj
927 pTextChain->SetNilChainingEvent(pTextObj, true); // XXX
928
929 // Save previous selection pos // NOTE: It must be done to have the right CursorEvent in KeyInput
930 pTextChain->SetPreChainingSel(pTextObj, pOLV->GetSelection());
931 //maPreChainingSel = new ESelection(pOLV->GetSelection());
932
933 // Handling Undo
934 const int nText = 0; // XXX: hardcoded index (SdrTextObj::getText handles only 0)
935
936 const bool bUndoEnabled = GetModel() && IsUndoEnabled();
937 std::unique_ptr<SdrUndoObjSetText> pTxtUndo;
938 if (bUndoEnabled)
939 pTxtUndo.reset(
940 dynamic_cast<SdrUndoObjSetText*>(GetModel()
941 ->GetSdrUndoFactory()
942 .CreateUndoObjectSetText(*pTextObj, nText)
943 .release()));
944
945 // trigger actual chaining
946 pTextObj->onChainingEvent();
947
948 if (pTxtUndo)
949 {
950 pTxtUndo->AfterSetText();
951 if (!pTxtUndo->IsDifferent())
952 {
953 pTxtUndo.reset();
954 }
955 }
956
957 if (pTxtUndo)
958 AddUndo(std::move(pTxtUndo));
959
960 //maCursorEvent = new CursorChainingEvent(pTextChain->GetCursorEvent(pTextObj));
961 //SdrTextObj *pNextLink = pTextObj->GetNextLinkInChain();
962
963 // NOTE: Must be called. Don't let the function return if you set it to true and not reset it
964 pTextChain->SetNilChainingEvent(pTextObj, false);
965 }
966 else
967 {
968 // XXX
969 SAL_INFO("svx.chaining", "[OnChaining] No Edit Outliner View")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "[OnChaining] No Edit Outliner View"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "969" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "[OnChaining] No Edit Outliner View"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "[OnChaining] No Edit Outliner View"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "969" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "[OnChaining] No Edit Outliner View") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "969" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "[OnChaining] No Edit Outliner View"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "[OnChaining] No Edit Outliner View"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "969" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
970 }
971}
972
973IMPL_LINK_NOARG(SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl, LinkParamNone*, void)void SdrObjEditView::LinkStubImpAfterCutOrPasteChainingEventHdl
(void * instance, LinkParamNone* data) { return static_cast<
SdrObjEditView *>(instance)->ImpAfterCutOrPasteChainingEventHdl
(data); } void SdrObjEditView::ImpAfterCutOrPasteChainingEventHdl
(__attribute__ ((unused)) LinkParamNone*)
974{
975 SdrTextObj* pTextObj = GetTextEditObject();
976 if (!pTextObj)
977 return;
978 ImpChainingEventHdl();
979 TextChainCursorManager aCursorManager(this, pTextObj);
980 ImpMoveCursorAfterChainingEvent(&aCursorManager);
981}
982
983void SdrObjEditView::ImpMoveCursorAfterChainingEvent(TextChainCursorManager* pCursorManager)
984{
985 if (!mxTextEditObj.is() || !pCursorManager)
986 return;
987
988 SdrTextObj* pTextObj = mxTextEditObj.get();
989
990 // Check if it has links to move it to
991 if (!pTextObj || !pTextObj->IsChainable())
992 return;
993
994 TextChain* pTextChain = pTextObj->GetTextChain();
995 ESelection aNewSel = pTextChain->GetPostChainingSel(pTextObj);
996
997 pCursorManager->HandleCursorEventAfterChaining(pTextChain->GetCursorEvent(pTextObj), aNewSel);
998
999 // Reset event
1000 pTextChain->SetCursorEvent(pTextObj, CursorChainingEvent::NULL_EVENT);
1001}
1002
1003IMPL_LINK(SdrObjEditView, ImpOutlinerCalcFieldValueHdl, EditFieldInfo*, pFI, void)void SdrObjEditView::LinkStubImpOutlinerCalcFieldValueHdl(void
* instance, EditFieldInfo* data) { return static_cast<SdrObjEditView
*>(instance)->ImpOutlinerCalcFieldValueHdl(data); } void
SdrObjEditView::ImpOutlinerCalcFieldValueHdl(EditFieldInfo* pFI
)
1004{
1005 bool bOk = false;
1006 OUString& rStr = pFI->GetRepresentation();
1007 rStr.clear();
1008 SdrTextObj* pTextObj = mxTextEditObj.get();
1009 if (pTextObj != nullptr)
1010 {
1011 std::optional<Color> pTxtCol;
1012 std::optional<Color> pFldCol;
1013 bOk = pTextObj->CalcFieldValue(pFI->GetField(), pFI->GetPara(), pFI->GetPos(), true,
1014 pTxtCol, pFldCol, rStr);
1015 if (bOk)
1016 {
1017 if (pTxtCol)
1018 {
1019 pFI->SetTextColor(*pTxtCol);
1020 }
1021 if (pFldCol)
1022 {
1023 pFI->SetFieldColor(*pFldCol);
1024 }
1025 else
1026 {
1027 pFI->SetFieldColor(COL_LIGHTGRAY); // TODO: remove this later on (357)
1028 }
1029 }
1030 }
1031 Outliner& rDrawOutl = mpModel->GetDrawOutliner(pTextObj);
1032 Link<EditFieldInfo*, void> aDrawOutlLink = rDrawOutl.GetCalcFieldValueHdl();
1033 if (!bOk && aDrawOutlLink.IsSet())
1034 {
1035 aDrawOutlLink.Call(pFI);
1036 bOk = !rStr.isEmpty();
1037 }
1038 if (!bOk)
1039 {
1040 aOldCalcFieldValueLink.Call(pFI);
1041 }
1042}
1043
1044IMPL_LINK_NOARG(SdrObjEditView, EndTextEditHdl, SdrUndoManager*, void)void SdrObjEditView::LinkStubEndTextEditHdl(void * instance, SdrUndoManager
* data) { return static_cast<SdrObjEditView *>(instance
)->EndTextEditHdl(data); } void SdrObjEditView::EndTextEditHdl
(__attribute__ ((unused)) SdrUndoManager*)
{ SdrEndTextEdit(); }
1045
1046SdrUndoManager* SdrObjEditView::getSdrUndoManagerForEnhancedTextEdit() const
1047{
1048 // default returns registered UndoManager
1049 return GetModel() ? dynamic_cast<SdrUndoManager*>(GetModel()->GetSdrUndoManager()) : nullptr;
1050}
1051
1052bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, SdrPageView* pPV, vcl::Window* pWin,
1053 bool bIsNewObj, SdrOutliner* pGivenOutliner,
1054 OutlinerView* pGivenOutlinerView, bool bDontDeleteOutliner,
1055 bool bOnlyOneView, bool bGrabFocus)
1056{
1057 // FIXME cannot be an assert() yet, the code is not ready for that;
1058 // eg. press F7 in Impress when you are inside a text object with spelling
1059 // mistakes => boom; and it is unclear how to avoid that
1060 SAL_WARN_IF(IsTextEdit(), "svx", "SdrBeginTextEdit called when IsTextEdit() is already true.")do { if (true && (IsTextEdit())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1060" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SdrBeginTextEdit called when IsTextEdit() is already true."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"),
("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1060" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SdrBeginTextEdit called when IsTextEdit() is already true."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1060" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SdrBeginTextEdit called when IsTextEdit() is already true."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SdrBeginTextEdit called when IsTextEdit() is already true."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"),
("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1060" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1061 // FIXME this encourages all sorts of bad habits and should be removed
1062 SdrEndTextEdit();
1063
1064 SdrTextObj* pObj = dynamic_cast<SdrTextObj*>(pObj_);
1065 if (!pObj)
1066 return false; // currently only possible with text objects
1067
1068 if (bGrabFocus && pWin)
1069 {
1070 // attention, this call may cause an EndTextEdit() call to this view
1071 pWin->GrabFocus(); // to force the cursor into the edit view
1072 }
1073
1074 bTextEditDontDelete = bDontDeleteOutliner && pGivenOutliner != nullptr;
1075 bTextEditOnlyOneView = bOnlyOneView;
1076 bTextEditNewObj = bIsNewObj;
1077 const sal_uInt32 nWinCount(PaintWindowCount());
1078 sal_uInt32 i;
1079 bool bBrk(false);
1080
1081 if (!pWin)
1082 {
1083 for (i = 0; i < nWinCount && !pWin; i++)
1084 {
1085 SdrPaintWindow* pPaintWindow = GetPaintWindow(i);
1086
1087 if (OUTDEV_WINDOW == pPaintWindow->GetOutputDevice().GetOutDevType())
1088 {
1089 pWin = static_cast<vcl::Window*>(&pPaintWindow->GetOutputDevice());
1090 }
1091 }
1092
1093 // break, when no window exists
1094 if (!pWin)
1095 {
1096 bBrk = true;
1097 }
1098 }
1099
1100 if (!bBrk && !pPV)
1101 {
1102 pPV = GetSdrPageView();
1103
1104 // break, when no PageView for the object exists
1105 if (!pPV)
1106 {
1107 bBrk = true;
1108 }
1109 }
1110
1111 // no TextEdit on objects in locked Layer
1112 if (pPV && pPV->GetLockedLayers().IsSet(pObj->GetLayer()))
1113 {
1114 bBrk = true;
1115 }
1116
1117 if (pTextEditOutliner)
1118 {
1119 OSL_FAIL("SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists.")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1119" ": "), "%s", "SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists."
); } } while (false)
;
1120 pTextEditOutliner.reset();
1121 }
1122
1123 if (!bBrk)
1124 {
1125 pTextEditWin = pWin;
1126 pTextEditPV = pPV;
1127 mxTextEditObj.reset(pObj);
1128 if (pGivenOutliner)
1129 {
1130 pTextEditOutliner.reset(pGivenOutliner);
1131 pGivenOutliner = nullptr; // so we don't delete it on the error path
1132 }
1133 else
1134 pTextEditOutliner = SdrMakeOutliner(OutlinerMode::TextObject,
1135 mxTextEditObj->getSdrModelFromSdrObject());
1136
1137 {
1138 SvtAccessibilityOptions aOptions;
1139 pTextEditOutliner->ForceAutoColor(aOptions.GetIsAutomaticFontColor());
1140 }
1141
1142 aOldCalcFieldValueLink = pTextEditOutliner->GetCalcFieldValueHdl();
1143 // FieldHdl has to be set by SdrBeginTextEdit, because this call an UpdateFields
1144 pTextEditOutliner->SetCalcFieldValueHdl(
1145 LINK(this, SdrObjEditView, ImpOutlinerCalcFieldValueHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubImpOutlinerCalcFieldValueHdl
)
);
1146 pTextEditOutliner->SetBeginPasteOrDropHdl(LINK(this, SdrObjEditView, BeginPasteOrDropHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubBeginPasteOrDropHdl
)
);
1147 pTextEditOutliner->SetEndPasteOrDropHdl(LINK(this, SdrObjEditView, EndPasteOrDropHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubEndPasteOrDropHdl)
);
1148
1149 // It is just necessary to make the visualized page known. Set it.
1150 pTextEditOutliner->setVisualizedPage(pPV->GetPage());
1151
1152 pTextEditOutliner->SetTextObjNoInit(mxTextEditObj.get());
1153
1154 if (mxTextEditObj->BegTextEdit(*pTextEditOutliner))
1155 {
1156 SdrTextObj* pTextObj = mxTextEditObj.get();
1157 DBG_ASSERT(pTextObj, "svx::SdrObjEditView::BegTextEdit(), no text object?")do { if (true && (!(pTextObj))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1157" ": "), "%s", "svx::SdrObjEditView::BegTextEdit(), no text object?"
); } } while (false)
;
1158 if (!pTextObj)
1159 return false;
1160
1161 // switch off any running TextAnimations
1162 pTextObj->SetTextAnimationAllowed(false);
1163
1164 // remember old cursor
1165 if (pTextEditOutliner->GetViewCount() != 0)
1166 {
1167 pTextEditOutliner->RemoveView(static_cast<size_t>(0));
1168 }
1169
1170 // Determine EditArea via TakeTextEditArea.
1171 // TODO: This could theoretically be left out, because TakeTextRect() calculates the aTextEditArea,
1172 // but aMinTextEditArea has to happen, too (therefore leaving this in right now)
1173 pTextObj->TakeTextEditArea(nullptr, nullptr, &aTextEditArea, &aMinTextEditArea);
1174
1175 tools::Rectangle aTextRect;
1176 tools::Rectangle aAnchorRect;
1177 pTextObj->TakeTextRect(*pTextEditOutliner, aTextRect, true,
1178 &aAnchorRect /* Give true here, not false */);
1179
1180 if (!pTextObj->IsContourTextFrame())
1181 {
1182 // FitToSize not together with ContourFrame, for now
1183 if (pTextObj->IsFitToSize())
1184 aTextRect = aAnchorRect;
1185 }
1186
1187 aTextEditArea = aTextRect;
1188
1189 // add possible GridOffset to up-to-now view-independent EditAreas
1190 basegfx::B2DVector aGridOffset(0.0, 0.0);
1191 if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, pPV))
1192 {
1193 const Point aOffset(basegfx::fround(aGridOffset.getX()),
1194 basegfx::fround(aGridOffset.getY()));
1195
1196 aTextEditArea += aOffset;
1197 aMinTextEditArea += aOffset;
1198 }
1199
1200 Point aPvOfs(pTextObj->GetTextEditOffset());
1201 aTextEditArea.Move(aPvOfs.X(), aPvOfs.Y());
1202 aMinTextEditArea.Move(aPvOfs.X(), aPvOfs.Y());
1203 pTextEditCursorBuffer = pWin->GetCursor();
1204
1205 maHdlList.SetMoveOutside(true);
1206
1207 // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
1208 // to call AdjustMarkHdl() always.
1209 AdjustMarkHdl();
1210
1211 pTextEditOutlinerView = ImpMakeOutlinerView(pWin, pGivenOutlinerView);
1212
1213 if (!comphelper::LibreOfficeKit::isActive() && pTextEditOutlinerView)
1214 {
1215 // activate visualization of EditView on Overlay, suppress when
1216 // LibreOfficeKit is active
1217 pTextEditOutlinerView->GetEditView().setEditViewCallbacks(this);
1218
1219 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1220 const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
1221 const SdrTextObj* pText = GetTextEditObject();
1222 const bool bTextFrame(pText && pText->IsTextFrame());
1223 const bool bFitToSize(pTextEditOutliner->GetControlWord()
1224 & EEControlBits::STRETCHING);
1225 const bool bVisualizeSurroundingFrame(bTextFrame && !bFitToSize);
1226 SdrPageView* pPageView = GetSdrPageView();
1227
1228 if (pPageView)
1229 {
1230 for (sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1231 {
1232 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1233
1234 if (rPageWindow.GetPaintWindow().OutputToWindow())
1235 {
1236 const rtl::Reference<sdr::overlay::OverlayManager>& xManager
1237 = rPageWindow.GetOverlayManager();
1238 if (xManager.is())
1239 {
1240 std::unique_ptr<TextEditOverlayObject> pNewTextEditOverlayObject(
1241 new TextEditOverlayObject(aHilightColor, *pTextEditOutlinerView,
1242 bVisualizeSurroundingFrame));
1243
1244 xManager->add(*pNewTextEditOverlayObject);
1245 xManager->add(const_cast<sdr::overlay::OverlaySelection&>(
1246 *pNewTextEditOverlayObject->getOverlaySelection()));
1247
1248 maTEOverlayGroup.append(std::move(pNewTextEditOverlayObject));
1249 }
1250 }
1251 }
1252 }
1253 }
1254
1255 // check if this view is already inserted
1256 size_t i2, nCount = pTextEditOutliner->GetViewCount();
1257 for (i2 = 0; i2 < nCount; i2++)
1258 {
1259 if (pTextEditOutliner->GetView(i2) == pTextEditOutlinerView)
1260 break;
1261 }
1262
1263 if (i2 == nCount)
1264 pTextEditOutliner->InsertView(pTextEditOutlinerView, 0);
1265
1266 maHdlList.SetMoveOutside(false);
1267 maHdlList.SetMoveOutside(true);
1268
1269 // register all windows as OutlinerViews with the Outliner
1270 if (!bOnlyOneView)
1271 {
1272 for (i = 0; i < nWinCount; i++)
1273 {
1274 SdrPaintWindow* pPaintWindow = GetPaintWindow(i);
1275 OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
1276
1277 if (&rOutDev != pWin && OUTDEV_WINDOW == rOutDev.GetOutDevType())
1278 {
1279 OutlinerView* pOutlView
1280 = ImpMakeOutlinerView(static_cast<vcl::Window*>(&rOutDev), nullptr);
1281 pTextEditOutliner->InsertView(pOutlView, static_cast<sal_uInt16>(i));
1282 }
1283 }
1284
1285 if (comphelper::LibreOfficeKit::isActive())
1286 {
1287 // Register an outliner view for all other sdr views that
1288 // show the same page, so that when the text edit changes,
1289 // all interested windows get an invalidation.
1290 SdrViewIter aIter(pObj->getSdrPageFromSdrObject());
1291 for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
1292 {
1293 if (pView == this)
1294 continue;
1295
1296 for (sal_uInt32 nViewPaintWindow = 0;
1297 nViewPaintWindow < pView->PaintWindowCount(); ++nViewPaintWindow)
1298 {
1299 SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(nViewPaintWindow);
1300 OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
1301
1302 if (&rOutDev != pWin && OUTDEV_WINDOW == rOutDev.GetOutDevType())
1303 {
1304 OutlinerView* pOutlView = ImpMakeOutlinerView(
1305 static_cast<vcl::Window*>(&rOutDev), nullptr);
1306 pOutlView->HideCursor();
1307 static_cast<vcl::Window*>(&rOutDev)->SetCursor(nullptr);
1308 pTextEditOutliner->InsertView(pOutlView);
1309 }
1310 }
1311 }
1312 }
1313 }
1314
1315 pTextEditOutlinerView->ShowCursor();
1316 pTextEditOutliner->SetStatusEventHdl(
1317 LINK(this, SdrObjEditView, ImpOutlinerStatusEventHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubImpOutlinerStatusEventHdl
)
);
1318 if (pTextObj->IsChainable())
1319 {
1320 pTextEditOutlinerView->SetEndCutPasteLinkHdl(
1321 LINK(this, SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubImpAfterCutOrPasteChainingEventHdl
)
);
1322 }
1323
1324 pTextEditOutliner->ClearModifyFlag();
1325
1326 if (pTextObj->IsFitToSize())
1327 {
1328 pWin->Invalidate(aTextEditArea);
1329 }
1330
1331 if (GetModel())
1332 {
1333 SdrHint aHint(SdrHintKind::BeginEdit, *pTextObj);
1334 GetModel()->Broadcast(aHint);
1335 }
1336
1337 pTextEditOutliner->setVisualizedPage(nullptr);
1338
1339 if (mxSelectionController.is())
1340 mxSelectionController->onSelectionHasChanged();
1341
1342 if (GetModel() && IsUndoEnabled()
1343 && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
1344 {
1345 SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit();
1346
1347 if (pSdrUndoManager)
1348 {
1349 // we have an outliner, undo manager and it's an EditUndoManager, exchange
1350 // the document undo manager and the default one from the outliner and tell
1351 // it that text edit starts by setting a callback if it needs to end text edit mode.
1352 assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager
) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager"
, "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
, 1352, __extension__ __PRETTY_FUNCTION__))
;
1353
1354 mpOldTextEditUndoManager = pTextEditOutliner->SetUndoManager(pSdrUndoManager);
1355 pSdrUndoManager->SetEndTextEditHdl(LINK(this, SdrObjEditView, EndTextEditHdl)::tools::detail::makeLink( ::tools::detail::castTo<SdrObjEditView
*>(this), &SdrObjEditView::LinkStubEndTextEditHdl)
);
1356 }
1357 else
1358 {
1359 OSL_ENSURE(false,do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1360" ": "), "%s", "The document undo manager is not derived from SdrUndoManager (!)"
); } } while (false)
1360 "The document undo manager is not derived from SdrUndoManager (!)")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1360" ": "), "%s", "The document undo manager is not derived from SdrUndoManager (!)"
); } } while (false)
;
1361 }
1362 }
1363
1364 return true; // ran fine, let TextEdit run now
1365 }
1366 else
1367 {
1368 pTextEditOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink);
1369 pTextEditOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
1370 pTextEditOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
1371 }
1372 }
1373 if (pTextEditOutliner != nullptr)
1374 {
1375 pTextEditOutliner->setVisualizedPage(nullptr);
1376 }
1377
1378 // something went wrong...
1379 if (!bDontDeleteOutliner)
1380 {
1381 delete pGivenOutliner;
1382 if (pGivenOutlinerView != nullptr)
1383 {
1384 delete pGivenOutlinerView;
1385 pGivenOutlinerView = nullptr;
1386 }
1387 }
1388 pTextEditOutliner.reset();
1389
1390 pTextEditOutlinerView = nullptr;
1391 mxTextEditObj.reset(nullptr);
1392 pTextEditPV = nullptr;
1393 pTextEditWin = nullptr;
1394 maHdlList.SetMoveOutside(false);
1395
1396 return false;
1397}
1398
1399SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
1400{
1401 SdrEndTextEditKind eRet = SdrEndTextEditKind::Unchanged;
1402 SdrTextObj* pTEObj = mxTextEditObj.get();
1403 vcl::Window* pTEWin = pTextEditWin;
1404 OutlinerView* pTEOutlinerView = pTextEditOutlinerView;
1405 vcl::Cursor* pTECursorBuffer = pTextEditCursorBuffer;
1406 SdrUndoManager* pUndoEditUndoManager = nullptr;
1407 bool bNeedToUndoSavedRedoTextEdit(false);
1408
1409 if (GetModel() && IsUndoEnabled() && pTEObj && pTextEditOutliner
1
Assuming the condition is false
1410 && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
1411 {
1412 // change back the UndoManager to the remembered original one
1413 SfxUndoManager* pOriginal = pTextEditOutliner->SetUndoManager(mpOldTextEditUndoManager);
1414 mpOldTextEditUndoManager = nullptr;
1415
1416 if (pOriginal)
1417 {
1418 // check if we got back our document undo manager
1419 SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit();
1420
1421 if (pSdrUndoManager && dynamic_cast<SdrUndoManager*>(pOriginal) == pSdrUndoManager)
1422 {
1423 if (pSdrUndoManager->isEndTextEditTriggeredFromUndo())
1424 {
1425 // remember the UndoManager where missing Undos have to be triggered after end
1426 // text edit. When the undo had triggered the end text edit, the original action
1427 // which had to be undone originally is not yet undone.
1428 pUndoEditUndoManager = pSdrUndoManager;
1429
1430 // We are ending text edit; if text edit was triggered from undo, execute all redos
1431 // to create a complete text change undo action for the redo buffer. Also mark this
1432 // state when at least one redo was executed; the created extra TextChange needs to
1433 // be undone in addition to the first real undo outside the text edit changes
1434 while (pSdrUndoManager->GetRedoActionCount())
1435 {
1436 bNeedToUndoSavedRedoTextEdit = true;
1437 pSdrUndoManager->Redo();
1438 }
1439 }
1440
1441 // reset the callback link and let the undo manager cleanup all text edit
1442 // undo actions to get the stack back to the form before the text edit
1443 pSdrUndoManager->SetEndTextEditHdl(Link<SdrUndoManager*, void>());
1444 }
1445 else
1446 {
1447 OSL_ENSURE(false, "Got UndoManager back in SdrEndTextEdit which is NOT the "do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1448" ": "), "%s", "Got UndoManager back in SdrEndTextEdit which is NOT the "
"expected document UndoManager (!)"); } } while (false)
1448 "expected document UndoManager (!)")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1448" ": "), "%s", "Got UndoManager back in SdrEndTextEdit which is NOT the "
"expected document UndoManager (!)"); } } while (false)
;
1449 delete pOriginal;
1450 }
1451 }
1452 }
1453 else
1454 {
1455 assert(nullptr == mpOldTextEditUndoManager)(static_cast <bool> (nullptr == mpOldTextEditUndoManager
) ? void (0) : __assert_fail ("nullptr == mpOldTextEditUndoManager"
, "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
, 1455, __extension__ __PRETTY_FUNCTION__))
; // cannot be restored!
2
Assuming the condition is true
3
'?' condition is true
1456 }
1457
1458 if (GetModel() && mxTextEditObj.is())
1459 {
1460 SdrHint aHint(SdrHintKind::EndEdit, *mxTextEditObj);
1461 GetModel()->Broadcast(aHint);
1462 }
1463
1464 // if new mechanism was used, clean it up. At cleanup no need to check
1465 // for LibreOfficeKit
1466 if (pTextEditOutlinerView)
4
Assuming field 'pTextEditOutlinerView' is null
5
Taking false branch
1467 {
1468 pTextEditOutlinerView->GetEditView().setEditViewCallbacks(nullptr);
1469 maTEOverlayGroup.clear();
1470 }
1471
1472 mxTextEditObj.reset(nullptr);
1473 pTextEditPV = nullptr;
1474 pTextEditWin = nullptr;
6
Calling 'VclPtr::operator='
17
Returning; memory was released
1475 SdrOutliner* pTEOutliner = pTextEditOutliner.release();
1476 pTextEditOutlinerView = nullptr;
1477 pTextEditCursorBuffer = nullptr;
1478 aTextEditArea = tools::Rectangle();
1479
1480 if (pTEOutliner != nullptr)
18
Assuming the condition is true
19
Taking true branch
1481 {
1482 bool bModified = pTEOutliner->IsModified();
1483 if (pTEOutlinerView != nullptr)
20
Taking false branch
1484 {
1485 pTEOutlinerView->HideCursor();
1486 }
1487 if (pTEObj != nullptr)
21
Taking true branch
1488 {
1489 pTEOutliner->CompleteOnlineSpelling();
1490
1491 std::unique_ptr<SdrUndoObjSetText> pTxtUndo;
1492
1493 if (bModified)
22
Assuming 'bModified' is false
23
Taking false branch
1494 {
1495 sal_Int32 nText;
1496 for (nText = 0; nText < pTEObj->getTextCount(); ++nText)
1497 if (pTEObj->getText(nText) == pTEObj->getActiveText())
1498 break;
1499
1500 pTxtUndo.reset(
1501 dynamic_cast<SdrUndoObjSetText*>(GetModel()
1502 ->GetSdrUndoFactory()
1503 .CreateUndoObjectSetText(*pTEObj, nText)
1504 .release()));
1505 }
1506 DBG_ASSERT(!bModified || pTxtUndo,do { if (true && (!(!bModified || pTxtUndo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1507" ": "), "%s", "svx::SdrObjEditView::EndTextEdit(), could not create undo action!"
); } } while (false)
24
Taking false branch
25
Loop condition is false. Exiting loop
1507 "svx::SdrObjEditView::EndTextEdit(), could not create undo action!")do { if (true && (!(!bModified || pTxtUndo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1507" ": "), "%s", "svx::SdrObjEditView::EndTextEdit(), could not create undo action!"
); } } while (false)
;
1508 // Set old CalcFieldValue-Handler again, this
1509 // has to happen before Obj::EndTextEdit(), as this does UpdateFields().
1510 pTEOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink);
1511 pTEOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
1512 pTEOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
1513
1514 const bool bUndo = IsUndoEnabled();
1515 if (bUndo)
26
Assuming 'bUndo' is false
27
Taking false branch
1516 {
1517 EndTextEditAllViews();
1518 OUString aObjName(pTEObj->TakeObjNameSingul());
1519 BegUndo(SvxResId(STR_UndoObjSetTextreinterpret_cast<char const *>("STR_UndoObjSetText" "\004"
u8"Edit text of %1")
), aObjName);
1520 }
1521
1522 pTEObj->EndTextEdit(*pTEOutliner);
1523
1524 if ((pTEObj->GetRotateAngle() != 0)
28
Assuming the condition is true
1525 || (dynamic_cast<const SdrTextObj*>(pTEObj) != nullptr && pTEObj->IsFontwork()))
1526 {
1527 pTEObj->ActionChanged();
1528 }
1529
1530 if (pTxtUndo != nullptr)
29
Taking false branch
1531 {
1532 pTxtUndo->AfterSetText();
1533 if (!pTxtUndo->IsDifferent())
1534 {
1535 pTxtUndo.reset();
1536 }
1537 }
1538 // check deletion of entire TextObj
1539 std::unique_ptr<SdrUndoAction> pDelUndo;
1540 bool bDelObj = false;
1541 if (bTextEditNewObj)
30
Assuming field 'bTextEditNewObj' is false
31
Taking false branch
1542 {
1543 bDelObj = pTEObj->IsTextFrame() && !pTEObj->HasText() && !pTEObj->IsEmptyPresObj()
1544 && !pTEObj->HasFill() && !pTEObj->HasLine();
1545
1546 if (pTEObj->IsInserted() && bDelObj
1547 && pTEObj->GetObjInventor() == SdrInventor::Default && !bDontDeleteReally)
1548 {
1549 SdrObjKind eIdent = static_cast<SdrObjKind>(pTEObj->GetObjIdentifier());
1550 if (eIdent == OBJ_TEXT)
1551 {
1552 pDelUndo = GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pTEObj);
1553 }
1554 }
1555 }
1556 if (pTxtUndo)
32
Taking false branch
1557 {
1558 if (bUndo)
1559 AddUndo(std::move(pTxtUndo));
1560 eRet = SdrEndTextEditKind::Changed;
1561 }
1562 if (pDelUndo != nullptr)
33
Taking false branch
1563 {
1564 if (bUndo)
1565 {
1566 AddUndo(std::move(pDelUndo));
1567 }
1568 eRet = SdrEndTextEditKind::Deleted;
1569 DBG_ASSERT(pTEObj->getParentSdrObjListFromSdrObject() != nullptr,do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject
() != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "
"ObjList!"); } } while (false)
1570 "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject
() != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "
"ObjList!"); } } while (false)
1571 "ObjList!")do { if (true && (!(pTEObj->getParentSdrObjListFromSdrObject
() != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "1571" ": "), "%s", "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "
"ObjList!"); } } while (false)
;
1572 if (pTEObj->getParentSdrObjListFromSdrObject() != nullptr)
1573 {
1574 pTEObj->getParentSdrObjListFromSdrObject()->RemoveObject(pTEObj->GetOrdNum());
1575 CheckMarked(); // remove selection immediately...
1576 }
1577 }
1578 else if (bDelObj
33.1
'bDelObj' is false
33.1
'bDelObj' is false
33.1
'bDelObj' is false
33.1
'bDelObj' is false
)
34
Taking false branch
1579 { // for Writer: the app has to do the deletion itself.
1580 eRet = SdrEndTextEditKind::ShouldBeDeleted;
1581 }
1582
1583 if (bUndo
34.1
'bUndo' is false
34.1
'bUndo' is false
34.1
'bUndo' is false
34.1
'bUndo' is false
)
35
Taking false branch
1584 EndUndo(); // EndUndo after Remove, in case UndoStack is deleted immediately
1585
1586 // Switch on any TextAnimation again after TextEdit
1587 if (dynamic_cast<const SdrTextObj*>(pTEObj) != nullptr)
36
Taking true branch
1588 {
1589 pTEObj->SetTextAnimationAllowed(true);
1590 }
1591
1592 // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
1593 // to call AdjustMarkHdl() always.
1594 AdjustMarkHdl();
1595 }
1596 // delete all OutlinerViews
1597 for (size_t i = pTEOutliner->GetViewCount(); i > 0;)
37
Assuming 'i' is <= 0
38
Loop condition is false. Execution continues on line 1623
1598 {
1599 i--;
1600 OutlinerView* pOLV = pTEOutliner->GetView(i);
1601 sal_uInt16 nMorePix = pOLV->GetInvalidateMore() + 10;
1602 vcl::Window* pWin = pOLV->GetWindow();
1603 tools::Rectangle aRect(pOLV->GetOutputArea());
1604 pTEOutliner->RemoveView(i);
1605 if (!bTextEditDontDelete || i != 0)
1606 {
1607 // may not own the zeroth one
1608 delete pOLV;
1609 }
1610 aRect.Union(aTextEditArea);
1611 aRect.Union(aMinTextEditArea);
1612 aRect = pWin->LogicToPixel(aRect);
1613 aRect.AdjustLeft(-nMorePix);
1614 aRect.AdjustTop(-nMorePix);
1615 aRect.AdjustRight(nMorePix);
1616 aRect.AdjustBottom(nMorePix);
1617 aRect = pWin->PixelToLogic(aRect);
1618 InvalidateOneWin(*pWin, aRect);
1619 pWin->SetFillColor();
1620 pWin->SetLineColor(COL_BLACK);
1621 }
1622 // and now the Outliner itself
1623 if (!bTextEditDontDelete)
39
Assuming field 'bTextEditDontDelete' is true
40
Taking false branch
1624 delete pTEOutliner;
1625 else
1626 pTEOutliner->Clear();
1627 if (pTEWin != nullptr)
41
Taking true branch
1628 {
1629 pTEWin->SetCursor(pTECursorBuffer);
42
Use of memory after it is freed
1630 }
1631 maHdlList.SetMoveOutside(false);
1632 if (eRet != SdrEndTextEditKind::Unchanged)
1633 {
1634 GetMarkedObjectListWriteAccess().SetNameDirty();
1635 }
1636 }
1637
1638 if (pTEObj && !pTEObj->getSdrModelFromSdrObject().isLocked() && pTEObj->GetBroadcaster())
1639 {
1640 SdrHint aHint(SdrHintKind::EndEdit, *pTEObj);
1641 const_cast<SfxBroadcaster*>(pTEObj->GetBroadcaster())->Broadcast(aHint);
1642 }
1643
1644 if (pUndoEditUndoManager)
1645 {
1646 if (bNeedToUndoSavedRedoTextEdit)
1647 {
1648 // undo the text edit action since it was created as part of an EndTextEdit
1649 // callback from undo itself. This needs to be done after the call to
1650 // FmFormView::SdrEndTextEdit since it gets created there
1651 pUndoEditUndoManager->Undo();
1652 }
1653
1654 // trigger the Undo which was not executed, but lead to this
1655 // end text edit
1656 pUndoEditUndoManager->Undo();
1657 }
1658
1659 return eRet;
1660}
1661
1662// info about TextEdit. Default is false.
1663bool SdrObjEditView::IsTextEdit() const { return mxTextEditObj.is(); }
1664
1665// info about TextEditPageView. Default is 0L.
1666SdrPageView* SdrObjEditView::GetTextEditPageView() const { return pTextEditPV; }
1667
1668OutlinerView* SdrObjEditView::ImpFindOutlinerView(vcl::Window const* pWin) const
1669{
1670 if (pWin == nullptr)
1671 return nullptr;
1672 if (pTextEditOutliner == nullptr)
1673 return nullptr;
1674 OutlinerView* pNewView = nullptr;
1675 size_t nWinCount = pTextEditOutliner->GetViewCount();
1676 for (size_t i = 0; i < nWinCount && pNewView == nullptr; i++)
1677 {
1678 OutlinerView* pView = pTextEditOutliner->GetView(i);
1679 if (pView->GetWindow() == pWin)
1680 pNewView = pView;
1681 }
1682 return pNewView;
1683}
1684
1685void SdrObjEditView::SetTextEditWin(vcl::Window* pWin)
1686{
1687 if (!(mxTextEditObj.is() && pWin != nullptr && pWin != pTextEditWin))
1688 return;
1689
1690 OutlinerView* pNewView = ImpFindOutlinerView(pWin);
1691 if (pNewView != nullptr && pNewView != pTextEditOutlinerView)
1692 {
1693 if (pTextEditOutlinerView != nullptr)
1694 {
1695 pTextEditOutlinerView->HideCursor();
1696 }
1697 pTextEditOutlinerView = pNewView;
1698 pTextEditWin = pWin;
1699 pWin->GrabFocus(); // Make the cursor blink here as well
1700 pNewView->ShowCursor();
1701 ImpMakeTextCursorAreaVisible();
1702 }
1703}
1704
1705bool SdrObjEditView::IsTextEditHit(const Point& rHit) const
1706{
1707 bool bOk = false;
1708 if (mxTextEditObj.is())
1709 {
1710 tools::Rectangle aEditArea;
1711 OutlinerView* pOLV = pTextEditOutliner->GetView(0);
1712 if (pOLV != nullptr)
1713 {
1714 aEditArea.Union(pOLV->GetOutputArea());
1715 }
1716 bOk = aEditArea.IsInside(rHit);
1717 if (bOk)
1718 { // check if any characters were actually hit
1719 Point aPnt(rHit);
1720 aPnt -= aEditArea.TopLeft();
1721 long nHitTol = 2000;
1722 OutputDevice* pRef = pTextEditOutliner->GetRefDevice();
1723 if (pRef)
1724 nHitTol = OutputDevice::LogicToLogic(nHitTol, MapUnit::Map100thMM,
1725 pRef->GetMapMode().GetMapUnit());
1726
1727 bOk = pTextEditOutliner->IsTextPos(aPnt, static_cast<sal_uInt16>(nHitTol));
1728 }
1729 }
1730 return bOk;
1731}
1732
1733bool SdrObjEditView::IsTextEditFrameHit(const Point& rHit) const
1734{
1735 bool bOk = false;
1736 if (mxTextEditObj.is())
1737 {
1738 SdrTextObj* pText = mxTextEditObj.get();
1739 OutlinerView* pOLV = pTextEditOutliner->GetView(0);
1740 if (pOLV)
1741 {
1742 vcl::Window* pWin = pOLV->GetWindow();
1743 if (pText != nullptr && pText->IsTextFrame() && pWin != nullptr)
1744 {
1745 sal_uInt16 nPixSiz = pOLV->GetInvalidateMore();
1746 tools::Rectangle aEditArea(aMinTextEditArea);
1747 aEditArea.Union(pOLV->GetOutputArea());
1748 if (!aEditArea.IsInside(rHit))
1749 {
1750 Size aSiz(pWin->PixelToLogic(Size(nPixSiz, nPixSiz)));
1751 aEditArea.AdjustLeft(-(aSiz.Width()));
1752 aEditArea.AdjustTop(-(aSiz.Height()));
1753 aEditArea.AdjustRight(aSiz.Width());
1754 aEditArea.AdjustBottom(aSiz.Height());
1755 bOk = aEditArea.IsInside(rHit);
1756 }
1757 }
1758 }
1759 }
1760 return bOk;
1761}
1762
1763TextChainCursorManager* SdrObjEditView::ImpHandleMotionThroughBoxesKeyInput(const KeyEvent& rKEvt,
1764 bool* bOutHandled)
1765{
1766 *bOutHandled = false;
1767
1768 SdrTextObj* pTextObj = mxTextEditObj.get();
1769 if (!pTextObj)
1770 return nullptr;
1771
1772 if (!pTextObj->GetNextLinkInChain() && !pTextObj->GetPrevLinkInChain())
1773 return nullptr;
1774
1775 TextChainCursorManager* pCursorManager = new TextChainCursorManager(this, pTextObj);
1776 if (pCursorManager->HandleKeyEvent(rKEvt))
1777 {
1778 // Possibly do other stuff here if necessary...
1779 // XXX: Careful with the checks below (in KeyInput) for pWin and co. You should do them here I guess.
1780 *bOutHandled = true;
1781 }
1782
1783 return pCursorManager;
1784}
1785
1786bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
1787{
1788 if (pTextEditOutlinerView)
1789 {
1790 /* Start special handling of keys within a chain */
1791 // We possibly move to another box before any handling
1792 bool bHandled = false;
1793 std::unique_ptr<TextChainCursorManager> xCursorManager(
1794 ImpHandleMotionThroughBoxesKeyInput(rKEvt, &bHandled));
1795 if (bHandled)
1796 return true;
1797 /* End special handling of keys within a chain */
1798
1799 if (pTextEditOutlinerView->PostKeyEvent(rKEvt, pWin))
1800 {
1801 if (mpModel)
1802 {
1803 if (pTextEditOutliner && pTextEditOutliner->IsModified())
1804 mpModel->SetChanged();
1805 }
1806
1807 /* Start chaining processing */
1808 ImpChainingEventHdl();
1809 ImpMoveCursorAfterChainingEvent(xCursorManager.get());
1810 /* End chaining processing */
1811
1812 if (pWin != nullptr && pWin != pTextEditWin)
1813 SetTextEditWin(pWin);
1814 ImpMakeTextCursorAreaVisible();
1815 return true;
1816 }
1817 }
1818 return SdrGlueEditView::KeyInput(rKEvt, pWin);
1819}
1820
1821bool SdrObjEditView::MouseButtonDown(const MouseEvent& rMEvt, OutputDevice* pWin)
1822{
1823 if (pTextEditOutlinerView != nullptr)
1824 {
1825 bool bPostIt = pTextEditOutliner->IsInSelectionMode();
1826 if (!bPostIt)
1827 {
1828 Point aPt(rMEvt.GetPosPixel());
1829 if (pWin != nullptr)
1830 aPt = pWin->PixelToLogic(aPt);
1831 else if (pTextEditWin != nullptr)
1832 aPt = pTextEditWin->PixelToLogic(aPt);
1833 bPostIt = IsTextEditHit(aPt);
1834 }
1835 if (bPostIt)
1836 {
1837 Point aPixPos(rMEvt.GetPosPixel());
1838 if (pWin)
1839 {
1840 tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea()));
1841 if (aPixPos.X() < aR.Left())
1842 aPixPos.setX(aR.Left());
1843 if (aPixPos.X() > aR.Right())
1844 aPixPos.setX(aR.Right());
1845 if (aPixPos.Y() < aR.Top())
1846 aPixPos.setY(aR.Top());
1847 if (aPixPos.Y() > aR.Bottom())
1848 aPixPos.setY(aR.Bottom());
1849 }
1850 MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
1851 rMEvt.GetModifier());
1852 if (pTextEditOutlinerView->MouseButtonDown(aMEvt))
1853 {
1854 if (pWin != nullptr && pWin != pTextEditWin
1855 && pWin->GetOutDevType() == OUTDEV_WINDOW)
1856 SetTextEditWin(static_cast<vcl::Window*>(pWin));
1857 ImpMakeTextCursorAreaVisible();
1858 return true;
1859 }
1860 }
1861 }
1862 return SdrGlueEditView::MouseButtonDown(rMEvt, pWin);
1863}
1864
1865bool SdrObjEditView::MouseButtonUp(const MouseEvent& rMEvt, OutputDevice* pWin)
1866{
1867 if (pTextEditOutlinerView != nullptr)
1868 {
1869 bool bPostIt = pTextEditOutliner->IsInSelectionMode();
1870 if (!bPostIt)
1871 {
1872 Point aPt(rMEvt.GetPosPixel());
1873 if (pWin != nullptr)
1874 aPt = pWin->PixelToLogic(aPt);
1875 else if (pTextEditWin != nullptr)
1876 aPt = pTextEditWin->PixelToLogic(aPt);
1877 bPostIt = IsTextEditHit(aPt);
1878 }
1879 if (bPostIt && pWin)
1880 {
1881 Point aPixPos(rMEvt.GetPosPixel());
1882 tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea()));
1883 if (aPixPos.X() < aR.Left())
1884 aPixPos.setX(aR.Left());
1885 if (aPixPos.X() > aR.Right())
1886 aPixPos.setX(aR.Right());
1887 if (aPixPos.Y() < aR.Top())
1888 aPixPos.setY(aR.Top());
1889 if (aPixPos.Y() > aR.Bottom())
1890 aPixPos.setY(aR.Bottom());
1891 MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
1892 rMEvt.GetModifier());
1893 if (pTextEditOutlinerView->MouseButtonUp(aMEvt))
1894 {
1895 ImpMakeTextCursorAreaVisible();
1896 return true;
1897 }
1898 }
1899 }
1900 return SdrGlueEditView::MouseButtonUp(rMEvt, pWin);
1901}
1902
1903bool SdrObjEditView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
1904{
1905 if (pTextEditOutlinerView != nullptr)
1906 {
1907 bool bSelMode = pTextEditOutliner->IsInSelectionMode();
1908 bool bPostIt = bSelMode;
1909 if (!bPostIt)
1910 {
1911 Point aPt(rMEvt.GetPosPixel());
1912 if (pWin)
1913 aPt = pWin->PixelToLogic(aPt);
1914 else if (pTextEditWin)
1915 aPt = pTextEditWin->PixelToLogic(aPt);
1916 bPostIt = IsTextEditHit(aPt);
1917 }
1918 if (bPostIt)
1919 {
1920 Point aPixPos(rMEvt.GetPosPixel());
1921 tools::Rectangle aR(pTextEditOutlinerView->GetOutputArea());
1922 if (pWin)
1923 aR = pWin->LogicToPixel(aR);
1924 else if (pTextEditWin)
1925 aR = pTextEditWin->LogicToPixel(aR);
1926 if (aPixPos.X() < aR.Left())
1927 aPixPos.setX(aR.Left());
1928 if (aPixPos.X() > aR.Right())
1929 aPixPos.setX(aR.Right());
1930 if (aPixPos.Y() < aR.Top())
1931 aPixPos.setY(aR.Top());
1932 if (aPixPos.Y() > aR.Bottom())
1933 aPixPos.setY(aR.Bottom());
1934 MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
1935 rMEvt.GetModifier());
1936 if (pTextEditOutlinerView->MouseMove(aMEvt) && bSelMode)
1937 {
1938 ImpMakeTextCursorAreaVisible();
1939 return true;
1940 }
1941 }
1942 }
1943 return SdrGlueEditView::MouseMove(rMEvt, pWin);
1944}
1945
1946bool SdrObjEditView::Command(const CommandEvent& rCEvt, vcl::Window* pWin)
1947{
1948 // as long as OutlinerView returns a sal_Bool, it only gets CommandEventId::StartDrag
1949 if (pTextEditOutlinerView != nullptr)
1950 {
1951 if (rCEvt.GetCommand() == CommandEventId::StartDrag)
1952 {
1953 bool bPostIt = pTextEditOutliner->IsInSelectionMode() || !rCEvt.IsMouseEvent();
1954 if (!bPostIt && rCEvt.IsMouseEvent())
1955 {
1956 Point aPt(rCEvt.GetMousePosPixel());
1957 if (pWin != nullptr)
1958 aPt = pWin->PixelToLogic(aPt);
1959 else if (pTextEditWin != nullptr)
1960 aPt = pTextEditWin->PixelToLogic(aPt);
1961 bPostIt = IsTextEditHit(aPt);
1962 }
1963 if (bPostIt)
1964 {
1965 Point aPixPos(rCEvt.GetMousePosPixel());
1966 if (rCEvt.IsMouseEvent() && pWin)
1967 {
1968 tools::Rectangle aR(pWin->LogicToPixel(pTextEditOutlinerView->GetOutputArea()));
1969 if (aPixPos.X() < aR.Left())
1970 aPixPos.setX(aR.Left());
1971 if (aPixPos.X() > aR.Right())
1972 aPixPos.setX(aR.Right());
1973 if (aPixPos.Y() < aR.Top())
1974 aPixPos.setY(aR.Top());
1975 if (aPixPos.Y() > aR.Bottom())
1976 aPixPos.setY(aR.Bottom());
1977 }
1978 CommandEvent aCEvt(aPixPos, rCEvt.GetCommand(), rCEvt.IsMouseEvent());
1979 // Command is void at the OutlinerView, sadly
1980 pTextEditOutlinerView->Command(aCEvt);
1981 if (pWin != nullptr && pWin != pTextEditWin)
1982 SetTextEditWin(pWin);
1983 ImpMakeTextCursorAreaVisible();
1984 return true;
1985 }
1986 }
1987 else
1988 {
1989 pTextEditOutlinerView->Command(rCEvt);
1990 if (mpModel && comphelper::LibreOfficeKit::isActive())
1991 {
1992 // It could execute CommandEventId::ExtTextInput, while SdrObjEditView::KeyInput
1993 // isn't called
1994 if (pTextEditOutliner && pTextEditOutliner->IsModified())
1995 mpModel->SetChanged();
1996 }
1997 return true;
1998 }
1999 }
2000 return SdrGlueEditView::Command(rCEvt, pWin);
2001}
2002
2003bool SdrObjEditView::ImpIsTextEditAllSelected() const
2004{
2005 bool bRet = false;
2006 if (pTextEditOutliner != nullptr && pTextEditOutlinerView != nullptr)
2007 {
2008 if (SdrTextObj::HasTextImpl(pTextEditOutliner.get()))
2009 {
2010 const sal_Int32 nParaCnt = pTextEditOutliner->GetParagraphCount();
2011 Paragraph* pLastPara = pTextEditOutliner->GetParagraph(nParaCnt > 1 ? nParaCnt - 1 : 0);
2012
2013 ESelection aESel(pTextEditOutlinerView->GetSelection());
2014 if (aESel.nStartPara == 0 && aESel.nStartPos == 0 && aESel.nEndPara == (nParaCnt - 1))
2015 {
2016 if (pTextEditOutliner->GetText(pLastPara).getLength() == aESel.nEndPos)
2017 bRet = true;
2018 }
2019 // in case the selection was done backwards
2020 if (!bRet && aESel.nEndPara == 0 && aESel.nEndPos == 0
2021 && aESel.nStartPara == (nParaCnt - 1))
2022 {
2023 if (pTextEditOutliner->GetText(pLastPara).getLength() == aESel.nStartPos)
2024 bRet = true;
2025 }
2026 }
2027 else
2028 {
2029 bRet = true;
2030 }
2031 }
2032 return bRet;
2033}
2034
2035void SdrObjEditView::ImpMakeTextCursorAreaVisible()
2036{
2037 if (pTextEditOutlinerView != nullptr && pTextEditWin != nullptr)
2038 {
2039 vcl::Cursor* pCsr = pTextEditWin->GetCursor();
2040 if (pCsr != nullptr)
2041 {
2042 Size aSiz(pCsr->GetSize());
2043 if (!aSiz.IsEmpty())
2044 {
2045 MakeVisible(tools::Rectangle(pCsr->GetPos(), aSiz), *pTextEditWin);
2046 }
2047 }
2048 }
2049}
2050
2051SvtScriptType SdrObjEditView::GetScriptType() const
2052{
2053 SvtScriptType nScriptType = SvtScriptType::NONE;
2054
2055 if (IsTextEdit())
2056 {
2057 if (mxTextEditObj->GetOutlinerParaObject())
2058 nScriptType = mxTextEditObj->GetOutlinerParaObject()->GetTextObject().GetScriptType();
2059
2060 if (pTextEditOutlinerView)
2061 nScriptType = pTextEditOutlinerView->GetSelectedScriptType();
2062 }
2063 else
2064 {
2065 const size_t nMarkCount(GetMarkedObjectCount());
2066
2067 for (size_t i = 0; i < nMarkCount; ++i)
2068 {
2069 OutlinerParaObject* pParaObj = GetMarkedObjectByIndex(i)->GetOutlinerParaObject();
2070
2071 if (pParaObj)
2072 {
2073 nScriptType |= pParaObj->GetTextObject().GetScriptType();
2074 }
2075 }
2076 }
2077
2078 if (nScriptType == SvtScriptType::NONE)
2079 nScriptType = SvtScriptType::LATIN;
2080
2081 return nScriptType;
2082}
2083
2084void SdrObjEditView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
2085{
2086 if (mxSelectionController.is())
2087 if (mxSelectionController->GetAttributes(rTargetSet, bOnlyHardAttr))
2088 return;
2089
2090 if (IsTextEdit())
2091 {
2092 DBG_ASSERT(pTextEditOutlinerView != nullptr,do { if (true && (!(pTextEditOutlinerView != nullptr)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2093" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL"
); } } while (false)
2093 "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL")do { if (true && (!(pTextEditOutlinerView != nullptr)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2093" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL"
); } } while (false)
;
2094 DBG_ASSERT(pTextEditOutliner != nullptr,do { if (true && (!(pTextEditOutliner != nullptr))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2095" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL"
); } } while (false)
2095 "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL")do { if (true && (!(pTextEditOutliner != nullptr))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2095" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL"
); } } while (false)
;
2096
2097 // take care of bOnlyHardAttr(!)
2098 if (!bOnlyHardAttr && mxTextEditObj->GetStyleSheet())
2099 rTargetSet.Put(mxTextEditObj->GetStyleSheet()->GetItemSet());
2100
2101 // add object attributes
2102 rTargetSet.Put(mxTextEditObj->GetMergedItemSet());
2103
2104 if (pTextEditOutlinerView)
2105 {
2106 // FALSE= regard InvalidItems as "holes," not as Default
2107 rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), false);
2108 }
2109
2110 if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj.get())
2111 {
2112 MergeNotPersistAttrFromMarked(rTargetSet);
2113 }
2114 }
2115 else
2116 {
2117 SdrGlueEditView::GetAttributes(rTargetSet, bOnlyHardAttr);
2118 }
2119}
2120
2121bool SdrObjEditView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
2122{
2123 bool bRet = false;
2124 bool bTextEdit = pTextEditOutlinerView != nullptr && mxTextEditObj.is();
2125 bool bAllTextSelected = ImpIsTextEditAllSelected();
2126 const SfxItemSet* pSet = &rSet;
2127
2128 if (!bTextEdit)
2129 {
2130 // no TextEdit active -> all Items to drawing object
2131 if (mxSelectionController.is())
2132 bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll);
2133
2134 if (!bRet)
2135 {
2136 SdrGlueEditView::SetAttributes(*pSet, bReplaceAll);
2137 bRet = true;
2138 }
2139 }
2140 else
2141 {
2142#ifdef DBG_UTIL
2143 {
2144 bool bHasEEFeatureItems = false;
2145 SfxItemIter aIter(rSet);
2146 for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem;
2147 pItem = aIter.NextItem())
2148 {
2149 if (!IsInvalidItem(pItem))
2150 {
2151 sal_uInt16 nW = pItem->Which();
2152 if (nW >= EE_FEATURE_START && nW <= EE_FEATURE_END)
2153 bHasEEFeatureItems = true;
2154 }
2155 }
2156
2157 if (bHasEEFeatureItems)
2158 {
2159 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(
2160 nullptr, VclMessageType::Info, VclButtonsType::Ok,
2161 "SdrObjEditView::SetAttributes(): Setting EE_FEATURE items "
2162 "at the SdrView does not make sense! It only leads to "
2163 "overhead and unreadable documents."));
2164 xInfoBox->run();
2165 }
2166 }
2167#endif
2168
2169 bool bOnlyEEItems;
2170 bool bNoEEItems = !SearchOutlinerItems(*pSet, bReplaceAll, &bOnlyEEItems);
2171 // everything selected? -> attributes to the border, too
2172 // if no EEItems, attributes to the border only
2173 if (bAllTextSelected || bNoEEItems)
2174 {
2175 if (mxSelectionController.is())
2176 bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll);
2177
2178 if (!bRet)
2179 {
2180 const bool bUndo = IsUndoEnabled();
2181
2182 if (bUndo)
2183 {
2184 BegUndo(ImpGetDescriptionString(STR_EditSetAttributesreinterpret_cast<char const *>("STR_EditSetAttributes" "\004"
u8"Apply attributes to %1")
));
2185 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj));
2186
2187 // If this is a text object also rescue the OutlinerParaObject since
2188 // applying attributes to the object may change text layout when
2189 // multiple portions exist with multiple formats. If an OutlinerParaObject
2190 // really exists and needs to be rescued is evaluated in the undo
2191 // implementation itself.
2192 bool bRescueText = mxTextEditObj;
2193
2194 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(
2195 *mxTextEditObj, false, !bNoEEItems || bRescueText));
2196 EndUndo();
2197 }
2198
2199 mxTextEditObj->SetMergedItemSetAndBroadcast(*pSet, bReplaceAll);
2200
2201 FlushComeBackTimer(); // to set ModeHasChanged immediately
2202 }
2203 }
2204 else if (!bOnlyEEItems)
2205 {
2206 // Otherwise split Set, if necessary.
2207 // Now we build an ItemSet aSet that doesn't contain EE_Items from
2208 // *pSet (otherwise it would be a copy).
2209 std::unique_ptr<sal_uInt16[]> pNewWhichTable
2210 = RemoveWhichRange(pSet->GetRanges(), EE_ITEMS_START, EE_ITEMS_END);
2211 SfxItemSet aSet(mpModel->GetItemPool(), pNewWhichTable.get());
2212 pNewWhichTable.reset();
2213 SfxWhichIter aIter(aSet);
2214 sal_uInt16 nWhich = aIter.FirstWhich();
2215 while (nWhich != 0)
2216 {
2217 const SfxPoolItem* pItem;
2218 SfxItemState eState = pSet->GetItemState(nWhich, false, &pItem);
2219 if (eState == SfxItemState::SET)
2220 aSet.Put(*pItem);
2221 nWhich = aIter.NextWhich();
2222 }
2223
2224 if (mxSelectionController.is())
2225 bRet = mxSelectionController->SetAttributes(aSet, bReplaceAll);
2226
2227 if (!bRet)
2228 {
2229 if (IsUndoEnabled())
2230 {
2231 BegUndo(ImpGetDescriptionString(STR_EditSetAttributesreinterpret_cast<char const *>("STR_EditSetAttributes" "\004"
u8"Apply attributes to %1")
));
2232 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj));
2233 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*mxTextEditObj));
2234 EndUndo();
2235 }
2236
2237 mxTextEditObj->SetMergedItemSetAndBroadcast(aSet, bReplaceAll);
2238
2239 if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj.get())
2240 {
2241 SetNotPersistAttrToMarked(aSet);
2242 }
2243 }
2244 FlushComeBackTimer();
2245 }
2246 if (!bNoEEItems)
2247 {
2248 // and now the attributes to the EditEngine
2249 if (bReplaceAll)
2250 {
2251 pTextEditOutlinerView->RemoveAttribs(true);
2252 }
2253 pTextEditOutlinerView->SetAttribs(rSet);
2254
2255 Outliner* pTEOutliner = pTextEditOutlinerView->GetOutliner();
2256 if (mpModel && pTEOutliner && pTEOutliner->IsModified())
2257 mpModel->SetChanged();
2258
2259 ImpMakeTextCursorAreaVisible();
2260 }
2261 bRet = true;
2262 }
2263 return bRet;
2264}
2265
2266SfxStyleSheet* SdrObjEditView::GetStyleSheet() const
2267{
2268 SfxStyleSheet* pSheet = nullptr;
2269
2270 if (mxSelectionController.is())
2271 {
2272 if (mxSelectionController->GetStyleSheet(pSheet))
2273 return pSheet;
2274 }
2275
2276 if (pTextEditOutlinerView)
2277 {
2278 pSheet = pTextEditOutlinerView->GetStyleSheet();
2279 }
2280 else
2281 {
2282 pSheet = SdrGlueEditView::GetStyleSheet();
2283 }
2284 return pSheet;
2285}
2286
2287void SdrObjEditView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
2288{
2289 if (mxSelectionController.is())
2290 {
2291 if (mxSelectionController->SetStyleSheet(pStyleSheet, bDontRemoveHardAttr))
2292 return;
2293 }
2294
2295 // if we are currently in edit mode we must also set the stylesheet
2296 // on all paragraphs in the Outliner for the edit view
2297 if (nullptr != pTextEditOutlinerView)
2298 {
2299 Outliner* pOutliner = pTextEditOutlinerView->GetOutliner();
2300
2301 const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
2302 for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
2303 {
2304 pOutliner->SetStyleSheet(nPara, pStyleSheet);
2305 }
2306 }
2307
2308 SdrGlueEditView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr);
2309}
2310
2311void SdrObjEditView::AddWindowToPaintView(OutputDevice* pNewWin, vcl::Window* pWindow)
2312{
2313 SdrGlueEditView::AddWindowToPaintView(pNewWin, pWindow);
2314
2315 if (mxTextEditObj.is() && !bTextEditOnlyOneView && pNewWin->GetOutDevType() == OUTDEV_WINDOW)
2316 {
2317 OutlinerView* pOutlView = ImpMakeOutlinerView(static_cast<vcl::Window*>(pNewWin), nullptr);
2318 pTextEditOutliner->InsertView(pOutlView);
2319 }
2320}
2321
2322void SdrObjEditView::DeleteWindowFromPaintView(OutputDevice* pOldWin)
2323{
2324 SdrGlueEditView::DeleteWindowFromPaintView(pOldWin);
2325
2326 if (mxTextEditObj.is() && !bTextEditOnlyOneView && pOldWin->GetOutDevType() == OUTDEV_WINDOW)
2327 {
2328 for (size_t i = pTextEditOutliner->GetViewCount(); i > 0;)
2329 {
2330 i--;
2331 OutlinerView* pOLV = pTextEditOutliner->GetView(i);
2332 if (pOLV && pOLV->GetWindow() == static_cast<vcl::Window*>(pOldWin))
2333 {
2334 pTextEditOutliner->RemoveView(i);
2335 }
2336 }
2337 }
2338
2339 lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), pOldWin);
2340}
2341
2342bool SdrObjEditView::IsTextEditInSelectionMode() const
2343{
2344 return pTextEditOutliner != nullptr && pTextEditOutliner->IsInSelectionMode();
2345}
2346
2347// MacroMode
2348
2349void SdrObjEditView::BegMacroObj(const Point& rPnt, short nTol, SdrObject* pObj, SdrPageView* pPV,
2350 vcl::Window* pWin)
2351{
2352 BrkMacroObj();
2353 if (pObj != nullptr && pPV != nullptr && pWin != nullptr && pObj->HasMacro())
2354 {
2355 nTol = ImpGetHitTolLogic(nTol, nullptr);
2356 pMacroObj = pObj;
2357 pMacroPV = pPV;
2358 pMacroWin = pWin;
2359 bMacroDown = false;
2360 nMacroTol = sal_uInt16(nTol);
2361 aMacroDownPos = rPnt;
2362 MovMacroObj(rPnt);
2363 }
2364}
2365
2366void SdrObjEditView::ImpMacroUp(const Point& rUpPos)
2367{
2368 if (pMacroObj != nullptr && bMacroDown)
2369 {
2370 SdrObjMacroHitRec aHitRec;
2371 aHitRec.aPos = rUpPos;
2372 aHitRec.nTol = nMacroTol;
2373 aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
2374 aHitRec.pPageView = pMacroPV;
2375 pMacroObj->PaintMacro(*pMacroWin, tools::Rectangle(), aHitRec);
2376 bMacroDown = false;
2377 }
2378}
2379
2380void SdrObjEditView::ImpMacroDown(const Point& rDownPos)
2381{
2382 if (pMacroObj != nullptr && !bMacroDown)
2383 {
2384 SdrObjMacroHitRec aHitRec;
2385 aHitRec.aPos = rDownPos;
2386 aHitRec.nTol = nMacroTol;
2387 aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
2388 aHitRec.pPageView = pMacroPV;
2389 pMacroObj->PaintMacro(*pMacroWin, tools::Rectangle(), aHitRec);
2390 bMacroDown = true;
2391 }
2392}
2393
2394void SdrObjEditView::MovMacroObj(const Point& rPnt)
2395{
2396 if (pMacroObj == nullptr)
2397 return;
2398
2399 SdrObjMacroHitRec aHitRec;
2400 aHitRec.aPos = rPnt;
2401 aHitRec.nTol = nMacroTol;
2402 aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
2403 aHitRec.pPageView = pMacroPV;
2404 bool bDown = pMacroObj->IsMacroHit(aHitRec);
2405 if (bDown)
2406 ImpMacroDown(rPnt);
2407 else
2408 ImpMacroUp(rPnt);
2409}
2410
2411void SdrObjEditView::BrkMacroObj()
2412{
2413 if (pMacroObj != nullptr)
2414 {
2415 ImpMacroUp(aMacroDownPos);
2416 pMacroObj = nullptr;
2417 pMacroPV = nullptr;
2418 pMacroWin = nullptr;
2419 }
2420}
2421
2422bool SdrObjEditView::EndMacroObj()
2423{
2424 if (pMacroObj != nullptr && bMacroDown)
2425 {
2426 ImpMacroUp(aMacroDownPos);
2427 SdrObjMacroHitRec aHitRec;
2428 aHitRec.aPos = aMacroDownPos;
2429 aHitRec.nTol = nMacroTol;
2430 aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
2431 aHitRec.pPageView = pMacroPV;
2432 bool bRet = pMacroObj->DoMacro(aHitRec);
2433 pMacroObj = nullptr;
2434 pMacroPV = nullptr;
2435 pMacroWin = nullptr;
2436 return bRet;
2437 }
2438 else
2439 {
2440 BrkMacroObj();
2441 return false;
2442 }
2443}
2444
2445/** fills the given any with a XTextCursor for the current text selection.
2446 Leaves the any untouched if there currently is no text selected */
2447void SdrObjEditView::getTextSelection(css::uno::Any& rSelection)
2448{
2449 if (!IsTextEdit())
2450 return;
2451
2452 OutlinerView* pOutlinerView = GetTextEditOutlinerView();
2453 if (!(pOutlinerView && pOutlinerView->HasSelection()))
2454 return;
2455
2456 SdrObject* pObj = GetTextEditObject();
2457
2458 if (!pObj)
2459 return;
2460
2461 css::uno::Reference<css::text::XText> xText(pObj->getUnoShape(), css::uno::UNO_QUERY);
2462 if (xText.is())
2463 {
2464 SvxUnoTextBase* pRange = comphelper::getUnoTunnelImplementation<SvxUnoTextBase>(xText);
2465 if (pRange)
2466 {
2467 rSelection <<= pRange->createTextCursorBySelection(pOutlinerView->GetSelection());
2468 }
2469 }
2470}
2471
2472/* check if we have a single selection and that single object likes
2473 to handle the mouse and keyboard events itself
2474
2475 TODO: the selection controller should be queried from the
2476 object specific view contact. Currently this method only
2477 works for tables.
2478*/
2479void SdrObjEditView::MarkListHasChanged()
2480{
2481 SdrGlueEditView::MarkListHasChanged();
2482
2483 if (mxSelectionController.is())
2484 {
2485 mxLastSelectionController = mxSelectionController;
2486 mxSelectionController->onSelectionHasChanged();
2487 }
2488
2489 mxSelectionController.clear();
2490
2491 const SdrMarkList& rMarkList = GetMarkedObjectList();
2492 if (rMarkList.GetMarkCount() != 1)
2493 return;
2494
2495 const SdrObject* pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
2496 SdrView* pView(dynamic_cast<SdrView*>(this));
2497
2498 // check for table
2499 if (pObj && pView && (pObj->GetObjInventor() == SdrInventor::Default)
2500 && (pObj->GetObjIdentifier() == OBJ_TABLE))
2501 {
2502 mxSelectionController = sdr::table::CreateTableController(
2503 *pView, static_cast<const sdr::table::SdrTableObj&>(*pObj), mxLastSelectionController);
2504
2505 if (mxSelectionController.is())
2506 {
2507 mxLastSelectionController.clear();
2508 mxSelectionController->onSelectionHasChanged();
2509 }
2510 }
2511}
2512
2513IMPL_LINK(SdrObjEditView, EndPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)void SdrObjEditView::LinkStubEndPasteOrDropHdl(void * instance
, PasteOrDropInfos* data) { return static_cast<SdrObjEditView
*>(instance)->EndPasteOrDropHdl(data); } void SdrObjEditView
::EndPasteOrDropHdl(PasteOrDropInfos* pInfo)
2514{
2515 OnEndPasteOrDrop(pInfo);
2516}
2517
2518IMPL_LINK(SdrObjEditView, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)void SdrObjEditView::LinkStubBeginPasteOrDropHdl(void * instance
, PasteOrDropInfos* data) { return static_cast<SdrObjEditView
*>(instance)->BeginPasteOrDropHdl(data); } void SdrObjEditView
::BeginPasteOrDropHdl(PasteOrDropInfos* pInfo)
2519{
2520 OnBeginPasteOrDrop(pInfo);
2521}
2522
2523void SdrObjEditView::OnBeginPasteOrDrop(PasteOrDropInfos*)
2524{
2525 // applications can derive from these virtual methods to do something before a drop or paste operation
2526}
2527
2528void SdrObjEditView::OnEndPasteOrDrop(PasteOrDropInfos*)
2529{
2530 // applications can derive from these virtual methods to do something before a drop or paste operation
2531}
2532
2533sal_uInt16 SdrObjEditView::GetSelectionLevel() const
2534{
2535 sal_uInt16 nLevel = 0xFFFF;
2536 if (IsTextEdit())
2537 {
2538 DBG_ASSERT(pTextEditOutlinerView != nullptr,do { if (true && (!(pTextEditOutlinerView != nullptr)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2539" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL"
); } } while (false)
2539 "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL")do { if (true && (!(pTextEditOutlinerView != nullptr)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2539" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL"
); } } while (false)
;
2540 DBG_ASSERT(pTextEditOutliner != nullptr,do { if (true && (!(pTextEditOutliner != nullptr))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2541" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL"
); } } while (false)
2541 "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL")do { if (true && (!(pTextEditOutliner != nullptr))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdedxv.cxx"
":" "2541" ": "), "%s", "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL"
); } } while (false)
;
2542 if (pTextEditOutlinerView)
2543 {
2544 //start and end position
2545 ESelection aSelect = pTextEditOutlinerView->GetSelection();
2546 sal_uInt16 nStartPara = ::std::min(aSelect.nStartPara, aSelect.nEndPara);
2547 sal_uInt16 nEndPara = ::std::max(aSelect.nStartPara, aSelect.nEndPara);
2548 //get level from each paragraph
2549 nLevel = 0;
2550 for (sal_uInt16 nPara = nStartPara; nPara <= nEndPara; nPara++)
2551 {
2552 sal_uInt16 nParaDepth
2553 = 1 << static_cast<sal_uInt16>(pTextEditOutliner->GetDepth(nPara));
2554 if (!(nLevel & nParaDepth))
2555 nLevel += nParaDepth;
2556 }
2557 //reduce one level for Outliner Object
2558 //if( nLevel > 0 && GetTextEditObject()->GetObjIdentifier() == OBJ_OUTLINETEXT )
2559 // nLevel = nLevel >> 1;
2560 //no bullet paragraph selected
2561 if (nLevel == 0)
2562 nLevel = 0xFFFF;
2563 }
2564 }
2565 return nLevel;
2566}
2567
2568bool SdrObjEditView::SupportsFormatPaintbrush(SdrInventor nObjectInventor,
2569 sal_uInt16 nObjectIdentifier)
2570{
2571 if (nObjectInventor != SdrInventor::Default && nObjectInventor != SdrInventor::E3d)
2572 return false;
2573 switch (nObjectIdentifier)
2574 {
2575 case OBJ_NONE:
2576 case OBJ_GRUP:
2577 return false;
2578 case OBJ_LINE:
2579 case OBJ_RECT:
2580 case OBJ_CIRC:
2581 case OBJ_SECT:
2582 case OBJ_CARC:
2583 case OBJ_CCUT:
2584 case OBJ_POLY:
2585 case OBJ_PLIN:
2586 case OBJ_PATHLINE:
2587 case OBJ_PATHFILL:
2588 case OBJ_FREELINE:
2589 case OBJ_FREEFILL:
2590 case OBJ_SPLNLINE:
2591 case OBJ_SPLNFILL:
2592 case OBJ_TEXT:
2593 case OBJ_TITLETEXT:
2594 case OBJ_OUTLINETEXT:
2595 case OBJ_GRAF:
2596 case OBJ_OLE2:
2597 case OBJ_TABLE:
2598 return true;
2599 case OBJ_EDGE:
2600 case OBJ_CAPTION:
2601 return false;
2602 case OBJ_PATHPOLY:
2603 case OBJ_PATHPLIN:
2604 return true;
2605 case OBJ_PAGE:
2606 case OBJ_MEASURE:
2607 case OBJ_FRAME:
2608 case OBJ_UNO:
2609 return false;
2610 case OBJ_CUSTOMSHAPE:
2611 return true;
2612 default:
2613 return false;
2614 }
2615}
2616
2617static const sal_uInt16* GetFormatRangeImpl(bool bTextOnly)
2618{
2619 static const sal_uInt16 gRanges[] = { SDRATTR_SHADOW_FIRST,
2620 SDRATTR_SHADOW_LAST,
2621 SDRATTR_GRAF_FIRST,
2622 SDRATTR_GRAF_LAST,
2623 SDRATTR_TABLE_FIRST,
2624 SDRATTR_TABLE_LAST,
2625 XATTR_LINE_FIRST,
2626 XATTR_LINE_LAST,
2627 XATTR_FILL_FIRST,
2628 XATTRSET_FILL,
2629 EE_PARA_START,
2630 EE_PARA_END, // text-only from here on
2631 EE_CHAR_START,
2632 EE_CHAR_END,
2633 SDRATTR_MISC_FIRST,
2634 SDRATTR_MISC_LAST, // table cell formats
2635 0,
2636 0 };
2637 return &gRanges[bTextOnly ? 10 : 0];
2638}
2639
2640void SdrObjEditView::TakeFormatPaintBrush(std::shared_ptr<SfxItemSet>& rFormatSet)
2641{
2642 const SdrMarkList& rMarkList = GetMarkedObjectList();
2643 if (rMarkList.GetMarkCount() <= 0)
2644 return;
2645
2646 OutlinerView* pOLV = GetTextEditOutlinerView();
2647
2648 rFormatSet = std::make_shared<SfxItemSet>(GetModel()->GetItemPool(),
2649 GetFormatRangeImpl(pOLV != nullptr));
2650 if (pOLV)
2651 {
2652 rFormatSet->Put(pOLV->GetAttribs());
2653 }
2654 else
2655 {
2656 const bool bOnlyHardAttr = false;
2657 rFormatSet->Put(GetAttrFromMarked(bOnlyHardAttr));
2658 }
2659
2660 // check for cloning from table cell, in which case we need to copy cell-specific formatting attributes
2661 const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
2662 if (pObj && (pObj->GetObjInventor() == SdrInventor::Default)
2663 && (pObj->GetObjIdentifier() == OBJ_TABLE))
2664 {
2665 auto pTable = static_cast<const sdr::table::SdrTableObj*>(pObj);
2666 if (mxSelectionController.is() && pTable->getActiveCell().is())
2667 {
2668 mxSelectionController->GetAttributes(*rFormatSet, false);
2669 }
2670 }
2671}
2672
2673static SfxItemSet CreatePaintSet(const sal_uInt16* pRanges, SfxItemPool& rPool,
2674 const SfxItemSet& rSourceSet, const SfxItemSet& rTargetSet,
2675 bool bNoCharacterFormats, bool bNoParagraphFormats)
2676{
2677 SfxItemSet aPaintSet(rPool, pRanges);
2678
2679 while (*pRanges)
2680 {
2681 sal_uInt16 nWhich = *pRanges++;
2682 const sal_uInt16 nLastWhich = *pRanges++;
2683
2684 if (bNoCharacterFormats && (nWhich == EE_CHAR_START))
2685 continue;
2686
2687 if (bNoParagraphFormats && (nWhich == EE_PARA_START))
2688 continue;
2689
2690 for (; nWhich < nLastWhich; nWhich++)
2691 {
2692 const SfxPoolItem* pSourceItem = rSourceSet.GetItem(nWhich);
2693 const SfxPoolItem* pTargetItem = rTargetSet.GetItem(nWhich);
2694
2695 if ((pSourceItem && !pTargetItem)
2696 || (pSourceItem && pTargetItem && *pSourceItem != *pTargetItem))
2697 {
2698 aPaintSet.Put(*pSourceItem);
2699 }
2700 }
2701 }
2702 return aPaintSet;
2703}
2704
2705void SdrObjEditView::ApplyFormatPaintBrushToText(SfxItemSet const& rFormatSet, SdrTextObj& rTextObj,
2706 SdrText* pText, bool bNoCharacterFormats,
2707 bool bNoParagraphFormats)
2708{
2709 OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
2710 if (!pParaObj)
2711 return;
2712
2713 SdrOutliner& rOutliner = rTextObj.ImpGetDrawOutliner();
2714 rOutliner.SetText(*pParaObj);
2715
2716 sal_Int32 nParaCount(rOutliner.GetParagraphCount());
2717
2718 if (!nParaCount)
2719 return;
2720
2721 for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
2722 {
2723 if (!bNoCharacterFormats)
2724 rOutliner.RemoveCharAttribs(nPara);
2725
2726 SfxItemSet aSet(rOutliner.GetParaAttribs(nPara));
2727 aSet.Put(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(), rFormatSet, aSet,
2728 bNoCharacterFormats, bNoParagraphFormats));
2729 rOutliner.SetParaAttribs(nPara, aSet);
2730 }
2731
2732 std::unique_ptr<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
2733 rOutliner.Clear();
2734
2735 rTextObj.NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
2736}
2737
2738void SdrObjEditView::ApplyFormatPaintBrush(SfxItemSet& rFormatSet, bool bNoCharacterFormats,
2739 bool bNoParagraphFormats)
2740{
2741 if (mxSelectionController.is()
2742 && mxSelectionController->ApplyFormatPaintBrush(rFormatSet, bNoCharacterFormats,
2743 bNoParagraphFormats))
2744 {
2745 return;
2746 }
2747
2748 OutlinerView* pOLV = GetTextEditOutlinerView();
2749 const SdrMarkList& rMarkList = GetMarkedObjectList();
2750 if (!pOLV)
2751 {
2752 SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
2753 const SfxItemSet& rShapeSet = pObj->GetMergedItemSet();
2754
2755 // if not in text edit mode (aka the user selected text or clicked on a word)
2756 // apply formatting attributes to selected shape
2757 // All formatting items (see ranges above) that are unequal in selected shape and
2758 // the format paintbrush are hard set on the selected shape.
2759
2760 const sal_uInt16* pRanges = rFormatSet.GetRanges();
2761 bool bTextOnly = true;
2762
2763 while (*pRanges)
2764 {
2765 if ((*pRanges != EE_PARA_START) && (*pRanges != EE_CHAR_START))
2766 {
2767 bTextOnly = false;
2768 break;
2769 }
2770 pRanges += 2;
2771 }
2772
2773 if (!bTextOnly)
2774 {
2775 SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(false), *rShapeSet.GetPool(),
2776 rFormatSet, rShapeSet, bNoCharacterFormats,
2777 bNoParagraphFormats));
2778 SetAttrToMarked(aPaintSet, false /*bReplaceAll*/);
2779 }
2780
2781 // now apply character and paragraph formatting to text, if the shape has any
2782 SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
2783 if (pTextObj)
2784 {
2785 sal_Int32 nText = pTextObj->getTextCount();
2786
2787 while (--nText >= 0)
2788 {
2789 SdrText* pText = pTextObj->getText(nText);
2790 ApplyFormatPaintBrushToText(rFormatSet, *pTextObj, pText, bNoCharacterFormats,
2791 bNoParagraphFormats);
2792 }
2793 }
2794 }
2795 else
2796 {
2797 ::Outliner* pOutliner = pOLV->GetOutliner();
2798 if (pOutliner)
2799 {
2800 const EditEngine& rEditEngine = pOutliner->GetEditEngine();
2801
2802 ESelection aSel(pOLV->GetSelection());
2803 if (!aSel.HasRange())
2804 pOLV->SetSelection(rEditEngine.GetWord(aSel, css::i18n::WordType::DICTIONARY_WORD));
2805
2806 const bool bRemoveParaAttribs = !bNoParagraphFormats;
2807 pOLV->RemoveAttribsKeepLanguages(bRemoveParaAttribs);
2808 SfxItemSet aSet(pOLV->GetAttribs());
2809 SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(),
2810 rFormatSet, aSet, bNoCharacterFormats,
2811 bNoParagraphFormats));
2812 pOLV->SetAttribs(aPaintSet);
2813 }
2814 }
2815
2816 // check for cloning to table cell, in which case we need to copy cell-specific formatting attributes
2817 SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
2818 if (pObj && (pObj->GetObjInventor() == SdrInventor::Default)
2819 && (pObj->GetObjIdentifier() == OBJ_TABLE))
2820 {
2821 auto pTable = static_cast<sdr::table::SdrTableObj*>(pObj);
2822 if (pTable->getActiveCell().is() && mxSelectionController.is())
2823 {
2824 mxSelectionController->SetAttributes(rFormatSet, false);
2825 }
2826 }
2827}
2828
2829/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
7
Calling 'Reference::set'
16
Returning; memory was released
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody
7.1
'pBody' is null
7.1
'pBody' is null
7.1
'pBody' is null
7.1
'pBody' is null
)
8
Taking false branch
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
9
Assuming 'pOld' is non-null
10
Taking true branch
127 pOld->release();
11
Calling 'VclReferenceBase::release'
15
Returning; memory was released
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
12
Assuming the condition is true
13
Taking true branch
40 delete this;
14
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif