1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
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>
68 SdrObjEditView::SdrObjEditView(SdrModel
& rSdrModel
, OutputDevice
* pOut
)
69 : SdrGlueEditView(rSdrModel
, pOut
)
70 , pTextEditPV(nullptr)
71 , pTextEditOutlinerView(nullptr)
72 , pTextEditWin(nullptr)
73 , pTextEditCursorBuffer(nullptr)
78 , bTextEditDontDelete(false)
79 , bTextEditOnlyOneView(false)
80 , bTextEditNewObj(false)
81 , bQuickTextEditMode(true)
83 , mpOldTextEditUndoManager(nullptr)
87 SdrObjEditView::~SdrObjEditView()
89 pTextEditWin
= nullptr; // so there's no ShowCursor in SdrEndTextEdit
90 assert(!IsTextEdit());
93 pTextEditOutliner
.reset();
94 assert(nullptr == mpOldTextEditUndoManager
); // should have been reset
97 bool SdrObjEditView::IsAction() const { return IsMacroObj() || SdrGlueEditView::IsAction(); }
99 void SdrObjEditView::MovAction(const Point
& rPnt
)
103 SdrGlueEditView::MovAction(rPnt
);
106 void SdrObjEditView::EndAction()
110 SdrGlueEditView::EndAction();
113 void SdrObjEditView::BckAction()
116 SdrGlueEditView::BckAction();
119 void SdrObjEditView::BrkAction()
122 SdrGlueEditView::BrkAction();
125 SdrPageView
* SdrObjEditView::ShowSdrPage(SdrPage
* pPage
)
127 SdrPageView
* pPageView
= SdrGlueEditView::ShowSdrPage(pPage
);
129 if (comphelper::LibreOfficeKit::isActive() && pPageView
)
131 // Check if other views have an active text edit on the same page as
133 SdrViewIter
aIter(pPageView
->GetPage());
134 for (SdrView
* pView
= aIter
.FirstView(); pView
; pView
= aIter
.NextView())
136 if (pView
== this || !pView
->IsTextEdit())
139 OutputDevice
* pOutDev
= GetFirstOutputDevice();
140 if (!pOutDev
|| pOutDev
->GetOutDevType() != OUTDEV_WINDOW
)
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
148 OutlinerView
* pOutlinerView
= pView
->ImpMakeOutlinerView(
149 static_cast<vcl::Window
*>(pOutDev
), nullptr, GetSfxViewShell());
150 pOutlinerView
->HideCursor();
151 pView
->GetTextEditOutliner()->InsertView(pOutlinerView
);
160 /// Removes outliner views registered in other draw views that use pOutputDevice.
161 void lcl_RemoveTextEditOutlinerViews(SdrObjEditView
const* pThis
, SdrPageView
const* pPageView
,
162 OutputDevice
const* pOutputDevice
)
164 if (!comphelper::LibreOfficeKit::isActive())
170 if (!pOutputDevice
|| pOutputDevice
->GetOutDevType() != OUTDEV_WINDOW
)
173 SdrViewIter
aIter(pPageView
->GetPage());
174 for (SdrView
* pView
= aIter
.FirstView(); pView
; pView
= aIter
.NextView())
176 if (pView
== pThis
|| !pView
->IsTextEdit())
179 SdrOutliner
* pOutliner
= pView
->GetTextEditOutliner();
180 for (size_t nView
= 0; nView
< pOutliner
->GetViewCount(); ++nView
)
182 OutlinerView
* pOutlinerView
= pOutliner
->GetView(nView
);
183 if (pOutlinerView
->GetWindow() != pOutputDevice
)
186 pOutliner
->RemoveView(pOutlinerView
);
187 delete pOutlinerView
;
193 void SdrObjEditView::HideSdrPage()
195 lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), GetFirstOutputDevice());
197 SdrGlueEditView::HideSdrPage();
200 void SdrObjEditView::TakeActionRect(tools::Rectangle
& rRect
) const
204 rRect
= pMacroObj
->GetCurrentBoundRect();
208 SdrGlueEditView::TakeActionRect(rRect
);
212 void SdrObjEditView::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
214 SdrGlueEditView::Notify(rBC
, rHint
);
215 if (pTextEditOutliner
== nullptr)
218 // change of printer while editing
219 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
222 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
223 SdrHintKind eKind
= pSdrHint
->GetKind();
224 if (eKind
== SdrHintKind::RefDeviceChange
)
226 pTextEditOutliner
->SetRefDevice(mpModel
->GetRefDevice());
228 if (eKind
== SdrHintKind::DefaultTabChange
)
230 pTextEditOutliner
->SetDefTab(mpModel
->GetDefaultTabulator());
234 void SdrObjEditView::ModelHasChanged()
236 SdrGlueEditView::ModelHasChanged();
237 if (mxTextEditObj
.is() && !mxTextEditObj
->IsInserted())
238 SdrEndTextEdit(); // object deleted
239 // TextEditObj changed?
243 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
244 if (pTextObj
!= nullptr)
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
);
258 tools::Rectangle aEditArea1
;
259 tools::Rectangle aMinArea1
;
260 pTextObj
->TakeTextEditArea(&aPaperMin1
, &aPaperMax1
, &aEditArea1
, &aMinArea1
);
261 Point
aPvOfs(pTextObj
->GetTextEditOffset());
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()))
267 const Point
aOffset(basegfx::fround(aGridOffset
.getX()),
268 basegfx::fround(aGridOffset
.getY()));
270 aEditArea1
+= aOffset
;
271 aMinArea1
+= aOffset
;
274 aEditArea1
.Move(aPvOfs
.X(), aPvOfs
.Y());
275 aMinArea1
.Move(aPvOfs
.X(), aPvOfs
.Y());
276 tools::Rectangle
aNewArea(aMinArea1
);
277 aNewArea
.Union(aEditArea1
);
279 if (aNewArea
!= aOldArea
|| aEditArea1
!= aTextEditArea
|| aMinArea1
!= aMinTextEditArea
280 || pTextEditOutliner
->GetMinAutoPaperSize() != aPaperMin1
281 || pTextEditOutliner
->GetMaxAutoPaperSize() != aPaperMax1
)
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
291 pTextEditOutliner
->ClearPolygon();
292 EEControlBits nStat
= pTextEditOutliner
->GetControlWord();
293 nStat
|= EEControlBits::AUTOPAGESIZE
;
294 pTextEditOutliner
->SetControlWord(nStat
);
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);
305 for (size_t nOV
= 0; nOV
< nOutlViewCnt
; nOV
++)
307 OutlinerView
* pOLV
= pTextEditOutliner
->GetView(nOV
);
308 EVControlBits nStat0
= pOLV
->GetControlWord();
309 EVControlBits nStat
= nStat0
;
310 // AutoViewSize only if not ContourFrame.
312 nStat
|= EVControlBits::AUTOSIZE
;
314 nStat
&= ~EVControlBits::AUTOSIZE
;
316 pOLV
->SetControlWord(nStat
);
318 pTextEditOutliner
->SetUpdateMode(true);
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
;
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
)
348 for (size_t nOV
= 0; nOV
< nOutlViewCnt
; nOV
++)
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
);
363 pOLV
->SetAnchorMode(eNewAnchor
);
365 pOLV
->SetBackgroundColor(aNewColor
);
368 aTextEditArea
); // because otherwise, we're not re-anchoring correctly
369 ImpInvalidateOutlinerView(*pOLV
);
371 pTextEditOutlinerView
->ShowCursor();
374 ImpMakeTextCursorAreaVisible();
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.
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.
389 It buffers as much as possible locally and *only* triggers a real
390 change (see call to objectChange()) when really needed.
392 class TextEditOverlayObject
: public sdr::overlay::OverlayObject
395 /// local access to associated sdr::overlay::OverlaySelection
396 sdr::overlay::OverlaySelection
* mpOverlaySelection
;
398 /// local definition depends on active OutlinerView
399 OutlinerView
& mrOutlinerView
;
401 /// geometry definitions with buffering
402 basegfx::B2DRange maLastRange
;
403 basegfx::B2DRange maRange
;
405 /// text content definitions with buffering
406 drawinglayer::primitive2d::Primitive2DContainer maTextPrimitives
;
407 drawinglayer::primitive2d::Primitive2DContainer maLastTextPrimitives
;
410 bool mbVisualizeSurroundingFrame
: 1;
412 // geometry creation for OverlayObject, can use local *Last* values
413 virtual drawinglayer::primitive2d::Primitive2DContainer
414 createOverlayObjectPrimitive2DSequence() override
;
417 TextEditOverlayObject(const Color
& rColor
, OutlinerView
& rOutlinerView
,
418 bool bVisualizeSurroundingFrame
);
419 virtual ~TextEditOverlayObject() override
;
422 const sdr::overlay::OverlaySelection
* getOverlaySelection() const { return mpOverlaySelection
; }
423 const OutlinerView
& getOutlinerView() const { return mrOutlinerView
; }
425 /// override to check conditions for last createOverlayObjectPrimitive2DSequence
426 virtual drawinglayer::primitive2d::Primitive2DContainer
427 getOverlayObjectPrimitive2DSequence() const override
;
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();
435 drawinglayer::primitive2d::Primitive2DContainer
436 TextEditOverlayObject::createOverlayObjectPrimitive2DSequence()
438 drawinglayer::primitive2d::Primitive2DContainer aRetval
;
440 /// outer frame visualization
441 if (mbVisualizeSurroundingFrame
)
443 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer
;
444 const double fTransparence(aSvtOptionsDrawinglayer
.GetTransparentSelectionPercent() * 0.01);
445 const sal_uInt16
nPixSiz(getOutlinerView().GetInvalidateMore() - 1);
447 aRetval
.push_back(new drawinglayer::primitive2d::OverlayRectanglePrimitive(
448 maRange
, getBaseColor().getBColor(), fTransparence
, std::max(6, nPixSiz
- 2), // grow
453 // add buffered TextPrimitives
454 aRetval
.append(maTextPrimitives
);
459 TextEditOverlayObject::TextEditOverlayObject(const Color
& rColor
, OutlinerView
& rOutlinerView
,
460 bool bVisualizeSurroundingFrame
)
461 : OverlayObject(rColor
)
462 , mpOverlaySelection(nullptr)
463 , mrOutlinerView(rOutlinerView
)
467 , maLastTextPrimitives()
468 , mbVisualizeSurroundingFrame(bVisualizeSurroundingFrame
)
470 // no AA for TextEdit overlay
471 allowAntiAliase(false);
473 // create local OverlaySelection - this is an integral part of EditText
475 const std::vector
<basegfx::B2DRange
> aEmptySelection
{};
476 mpOverlaySelection
= new sdr::overlay::OverlaySelection(sdr::overlay::OverlayType::Transparent
,
477 rColor
, aEmptySelection
, true);
480 TextEditOverlayObject::~TextEditOverlayObject()
482 if (getOverlaySelection())
484 delete mpOverlaySelection
;
485 mpOverlaySelection
= nullptr;
488 if (getOverlayManager())
490 getOverlayManager()->remove(*this);
494 drawinglayer::primitive2d::Primitive2DContainer
495 TextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const
497 if (!getPrimitive2DSequence().empty())
499 if (!maRange
.equal(maLastRange
) || maLastTextPrimitives
!= maTextPrimitives
)
501 // conditions of last local decomposition have changed, delete to force new evaluation
502 const_cast<TextEditOverlayObject
*>(this)->resetPrimitive2DSequence();
506 if (getPrimitive2DSequence().empty())
508 // remember new buffered values
509 const_cast<TextEditOverlayObject
*>(this)->maLastRange
= maRange
;
510 const_cast<TextEditOverlayObject
*>(this)->maLastTextPrimitives
= maTextPrimitives
;
513 // call base implementation
514 return OverlayObject::getOverlayObjectPrimitive2DSequence();
517 void TextEditOverlayObject::checkDataChange(const basegfx::B2DRange
& rMinTextEditArea
)
519 bool bObjectChange(false);
521 // check current range
522 const tools::Rectangle
aOutArea(mrOutlinerView
.GetOutputArea());
523 basegfx::B2DRange aNewRange
= vcl::unotools::b2DRectangleFromRectangle(aOutArea
);
524 aNewRange
.expand(rMinTextEditArea
);
526 if (aNewRange
!= maRange
)
529 bObjectChange
= true;
532 // check if text primitives did change
533 SdrOutliner
* pSdrOutliner
= dynamic_cast<SdrOutliner
*>(getOutlinerView().GetOutliner());
537 // get TextPrimitives directly from active Outliner
538 basegfx::B2DHomMatrix aNewTransformA
;
539 basegfx::B2DHomMatrix aNewTransformB
;
540 basegfx::B2DRange aClipRange
;
541 drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives
;
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());
556 aNewTransformB
.translate(fStartInX
, fStartInY
);
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
);
565 if (aNewTextPrimitives
!= maTextPrimitives
)
567 maTextPrimitives
= aNewTextPrimitives
;
568 bObjectChange
= true;
574 // if there really *was* a change signal the OverlayManager to
575 // refresh this object's visualization
578 // on data change, always do a SelectionChange, too
579 // since the selection is an integral part of text visualization
580 checkSelectionChange();
584 void TextEditOverlayObject::checkSelectionChange()
586 if (!(getOverlaySelection() && getOverlayManager()))
589 std::vector
<tools::Rectangle
> aLogicRects
;
590 std::vector
<basegfx::B2DRange
> aLogicRanges
;
591 const Size
aLogicPixel(getOverlayManager()->getOutputDevice().PixelToLogic(Size(1, 1)));
593 // get logic selection
594 getOutlinerView().GetSelectionRectangles(aLogicRects
);
596 aLogicRanges
.reserve(aLogicRects
.size());
597 for (const auto& aRect
: aLogicRects
)
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());
606 mpOverlaySelection
->setRanges(aLogicRanges
);
608 } // end of anonymous namespace
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
615 void SdrObjEditView::EditViewInvalidate(const tools::Rectangle
&)
620 // MinTextRange may have changed. Forward it, too
621 const basegfx::B2DRange aMinTextRange
622 = vcl::unotools::b2DRectangleFromRectangle(aMinTextEditArea
);
624 for (sal_uInt32
a(0); a
< maTEOverlayGroup
.count(); a
++)
626 TextEditOverlayObject
* pCandidate
627 = dynamic_cast<TextEditOverlayObject
*>(&maTEOverlayGroup
.getOverlayObject(a
));
631 pCandidate
->checkDataChange(aMinTextRange
);
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
639 void SdrObjEditView::EditViewSelectionChange()
644 for (sal_uInt32
a(0); a
< maTEOverlayGroup
.count(); a
++)
646 TextEditOverlayObject
* pCandidate
647 = dynamic_cast<TextEditOverlayObject
*>(&maTEOverlayGroup
.getOverlayObject(a
));
651 pCandidate
->checkSelectionChange();
656 OutputDevice
& SdrObjEditView::EditViewOutputDevice() const { return *pTextEditWin
; }
658 css::uno::Reference
<css::datatransfer::dnd::XDropTarget
> SdrObjEditView::GetDropTarget()
662 return pTextEditWin
->GetDropTarget();
665 void SdrObjEditView::EditViewInputContext(const InputContext
& rInputContext
)
669 pTextEditWin
->SetInputContext(rInputContext
);
672 void SdrObjEditView::EditViewCursorRect(const tools::Rectangle
& rRect
, int nExtTextInputWidth
)
676 pTextEditWin
->SetCursorRect(&rRect
, nExtTextInputWidth
);
679 void SdrObjEditView::TextEditDrawing(SdrPaintWindow
& rPaintWindow
)
681 if (!comphelper::LibreOfficeKit::isActive())
683 // adapt all TextEditOverlayObject(s), so call EditViewInvalidate()
684 // to update accordingly (will update selection, too). Suppress new
685 // stuff when LibreOfficeKit is active
686 EditViewInvalidate(tools::Rectangle());
690 // draw old text edit stuff
693 const SdrOutliner
* pActiveOutliner
= GetTextEditOutliner();
697 const sal_uInt32
nViewCount(pActiveOutliner
->GetViewCount());
701 const vcl::Region
& rRedrawRegion
= rPaintWindow
.GetRedrawRegion();
702 const tools::Rectangle
aCheckRect(rRedrawRegion
.GetBoundRect());
704 for (sal_uInt32
i(0); i
< nViewCount
; i
++)
706 OutlinerView
* pOLV
= pActiveOutliner
->GetView(i
);
708 // If rPaintWindow knows that the output device is a render
709 // context and is aware of the underlying vcl::Window,
710 // compare against that; that's how double-buffering can
711 // still find the matching OutlinerView.
712 OutputDevice
* pOutputDevice
= rPaintWindow
.GetWindow()
713 ? rPaintWindow
.GetWindow()
714 : &rPaintWindow
.GetOutputDevice();
715 if (pOLV
->GetWindow() == pOutputDevice
716 || comphelper::LibreOfficeKit::isActive())
718 ImpPaintOutlinerView(*pOLV
, aCheckRect
,
719 rPaintWindow
.GetTargetOutputDevice());
729 void SdrObjEditView::ImpPaintOutlinerView(OutlinerView
& rOutlView
, const tools::Rectangle
& rRect
,
730 OutputDevice
& rTargetDevice
) const
732 const SdrTextObj
* pText
= GetTextEditObject();
733 bool bTextFrame(pText
&& pText
->IsTextFrame());
734 bool bFitToSize(pTextEditOutliner
->GetControlWord() & EEControlBits::STRETCHING
);
735 bool bModified(pTextEditOutliner
->IsModified());
736 tools::Rectangle
aBlankRect(rOutlView
.GetOutputArea());
737 aBlankRect
.Union(aMinTextEditArea
);
738 tools::Rectangle
aPixRect(rTargetDevice
.LogicToPixel(aBlankRect
));
740 // in the tiled rendering case, the setup is incomplete, and we very
741 // easily get an empty rRect on input - that will cause that everything is
742 // clipped; happens in case of editing text inside a shape in Calc.
743 // FIXME would be better to complete the setup so that we don't get an
745 if (!comphelper::LibreOfficeKit::isActive() || !rRect
.IsEmpty())
746 aBlankRect
.Intersection(rRect
);
748 rOutlView
.GetOutliner()->SetUpdateMode(true); // Bugfix #22596#
749 rOutlView
.Paint(aBlankRect
, &rTargetDevice
);
753 pTextEditOutliner
->ClearModifyFlag();
756 if (bTextFrame
&& !bFitToSize
)
758 // completely reworked to use primitives; this ensures same look and functionality
759 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
760 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> xProcessor(
761 drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTargetDevice
,
762 aViewInformation2D
));
766 const bool bMapModeEnabled(rTargetDevice
.IsMapModeEnabled());
767 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aPixRect
);
768 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer
;
769 const Color
aHilightColor(aSvtOptionsDrawinglayer
.getHilightColor());
770 const double fTransparence(aSvtOptionsDrawinglayer
.GetTransparentSelectionPercent()
772 const sal_uInt16
nPixSiz(rOutlView
.GetInvalidateMore() - 1);
773 const drawinglayer::primitive2d::Primitive2DReference
xReference(
774 new drawinglayer::primitive2d::OverlayRectanglePrimitive(
775 aRange
, aHilightColor
.getBColor(), fTransparence
,
776 std::max(6, nPixSiz
- 2), // grow
779 const drawinglayer::primitive2d::Primitive2DContainer aSequence
{ xReference
};
781 rTargetDevice
.EnableMapMode(false);
782 xProcessor
->process(aSequence
);
783 rTargetDevice
.EnableMapMode(bMapModeEnabled
);
787 rOutlView
.ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
790 void SdrObjEditView::ImpInvalidateOutlinerView(OutlinerView
const& rOutlView
) const
792 vcl::Window
* pWin
= rOutlView
.GetWindow();
797 const SdrTextObj
* pText
= GetTextEditObject();
798 bool bTextFrame(pText
&& pText
->IsTextFrame());
799 bool bFitToSize(pText
&& pText
->IsFitToSize());
801 if (!bTextFrame
|| bFitToSize
)
804 tools::Rectangle
aBlankRect(rOutlView
.GetOutputArea());
805 aBlankRect
.Union(aMinTextEditArea
);
806 tools::Rectangle
aPixRect(pWin
->LogicToPixel(aBlankRect
));
807 sal_uInt16
nPixSiz(rOutlView
.GetInvalidateMore() - 1);
809 aPixRect
.AdjustLeft(-1);
810 aPixRect
.AdjustTop(-1);
811 aPixRect
.AdjustRight(1);
812 aPixRect
.AdjustBottom(1);
815 // limit xPixRect because of driver problems when pixel coordinates are too far out
816 Size
aMaxXY(pWin
->GetOutputSizePixel());
817 tools::Long
a(2 * nPixSiz
);
818 tools::Long
nMaxX(aMaxXY
.Width() + a
);
819 tools::Long
nMaxY(aMaxXY
.Height() + a
);
821 if (aPixRect
.Left() < -a
)
822 aPixRect
.SetLeft(-a
);
823 if (aPixRect
.Top() < -a
)
825 if (aPixRect
.Right() > nMaxX
)
826 aPixRect
.SetRight(nMaxX
);
827 if (aPixRect
.Bottom() > nMaxY
)
828 aPixRect
.SetBottom(nMaxY
);
831 tools::Rectangle
aOuterPix(aPixRect
);
832 aOuterPix
.AdjustLeft(-nPixSiz
);
833 aOuterPix
.AdjustTop(-nPixSiz
);
834 aOuterPix
.AdjustRight(nPixSiz
);
835 aOuterPix
.AdjustBottom(nPixSiz
);
837 bool bMapModeEnabled(pWin
->IsMapModeEnabled());
838 pWin
->EnableMapMode(false);
839 pWin
->Invalidate(aOuterPix
);
840 pWin
->EnableMapMode(bMapModeEnabled
);
843 OutlinerView
* SdrObjEditView::ImpMakeOutlinerView(vcl::Window
* pWin
, OutlinerView
* pGivenView
,
844 SfxViewShell
* pViewShell
) const
847 Color
aBackground(GetTextEditBackgroundColor(*this));
848 SdrTextObj
* pText
= mxTextEditObj
.get();
849 bool bTextFrame
= pText
!= nullptr && pText
->IsTextFrame();
850 bool bContourFrame
= pText
!= nullptr && pText
->IsContourTextFrame();
851 // create OutlinerView
852 OutlinerView
* pOutlView
= pGivenView
;
853 pTextEditOutliner
->SetUpdateMode(false);
855 if (pOutlView
== nullptr)
857 pOutlView
= new OutlinerView(pTextEditOutliner
.get(), pWin
);
861 pOutlView
->SetWindow(pWin
);
864 // disallow scrolling
865 EVControlBits nStat
= pOutlView
->GetControlWord();
866 nStat
&= ~EVControlBits::AUTOSCROLL
;
867 // AutoViewSize only if not ContourFrame.
869 nStat
|= EVControlBits::AUTOSIZE
;
872 sal_uInt16 nPixSiz
= maHdlList
.GetHdlSize() * 2 + 1;
873 nStat
|= EVControlBits::INVONEMORE
;
874 pOutlView
->SetInvalidateMore(nPixSiz
);
876 pOutlView
->SetControlWord(nStat
);
877 pOutlView
->SetBackgroundColor(aBackground
);
879 // In case we're in the process of constructing a new view shell,
880 // SfxViewShell::Current() may still point to the old one. So if possible,
881 // depend on the application owning this draw view to provide the view
883 SfxViewShell
* pSfxViewShell
= pViewShell
? pViewShell
: GetSfxViewShell();
884 pOutlView
->RegisterViewShell(pSfxViewShell
? pSfxViewShell
: SfxViewShell::Current());
886 if (pText
!= nullptr)
888 pOutlView
->SetAnchorMode(pText
->GetOutlinerViewAnchorMode());
889 pTextEditOutliner
->SetFixedCellHeight(
890 pText
->GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
892 // do update before setting output area so that aTextEditArea can be recalculated
893 pTextEditOutliner
->SetUpdateMode(true);
894 pOutlView
->SetOutputArea(aTextEditArea
);
895 ImpInvalidateOutlinerView(*pOutlView
);
899 IMPL_LINK(SdrObjEditView
, ImpOutlinerStatusEventHdl
, EditStatus
&, rEditStat
, void)
901 if (pTextEditOutliner
)
903 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
906 pTextObj
->onEditOutlinerStatusEvent(&rEditStat
);
911 void SdrObjEditView::ImpChainingEventHdl()
913 if (!pTextEditOutliner
)
916 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
917 OutlinerView
* pOLV
= GetTextEditOutlinerView();
918 if (pTextObj
&& pOLV
)
920 TextChain
* pTextChain
= pTextObj
->GetTextChain();
922 // XXX: IsChainable and GetNilChainingEvent are a bit mixed up atm
923 if (!pTextObj
->IsChainable())
927 // This is true during an underflow-caused overflow (with pEdtOutl->SetText())
928 if (pTextChain
->GetNilChainingEvent(pTextObj
))
933 // We prevent to trigger further handling of overflow/underflow for pTextObj
934 pTextChain
->SetNilChainingEvent(pTextObj
, true); // XXX
936 // Save previous selection pos // NOTE: It must be done to have the right CursorEvent in KeyInput
937 pTextChain
->SetPreChainingSel(pTextObj
, pOLV
->GetSelection());
938 //maPreChainingSel = new ESelection(pOLV->GetSelection());
941 const int nText
= 0; // XXX: hardcoded index (SdrTextObj::getText handles only 0)
943 const bool bUndoEnabled
= GetModel() && IsUndoEnabled();
944 std::unique_ptr
<SdrUndoObjSetText
> pTxtUndo
;
947 dynamic_cast<SdrUndoObjSetText
*>(GetModel()
948 ->GetSdrUndoFactory()
949 .CreateUndoObjectSetText(*pTextObj
, nText
)
952 // trigger actual chaining
953 pTextObj
->onChainingEvent();
957 pTxtUndo
->AfterSetText();
958 if (!pTxtUndo
->IsDifferent())
965 AddUndo(std::move(pTxtUndo
));
967 //maCursorEvent = new CursorChainingEvent(pTextChain->GetCursorEvent(pTextObj));
968 //SdrTextObj *pNextLink = pTextObj->GetNextLinkInChain();
970 // NOTE: Must be called. Don't let the function return if you set it to true and not reset it
971 pTextChain
->SetNilChainingEvent(pTextObj
, false);
976 SAL_INFO("svx.chaining", "[OnChaining] No Edit Outliner View");
980 IMPL_LINK_NOARG(SdrObjEditView
, ImpAfterCutOrPasteChainingEventHdl
, LinkParamNone
*, void)
982 SdrTextObj
* pTextObj
= GetTextEditObject();
985 ImpChainingEventHdl();
986 TextChainCursorManager
aCursorManager(this, pTextObj
);
987 ImpMoveCursorAfterChainingEvent(&aCursorManager
);
990 void SdrObjEditView::ImpMoveCursorAfterChainingEvent(TextChainCursorManager
* pCursorManager
)
992 if (!mxTextEditObj
.is() || !pCursorManager
)
995 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
997 // Check if it has links to move it to
998 if (!pTextObj
|| !pTextObj
->IsChainable())
1001 TextChain
* pTextChain
= pTextObj
->GetTextChain();
1002 ESelection aNewSel
= pTextChain
->GetPostChainingSel(pTextObj
);
1004 pCursorManager
->HandleCursorEventAfterChaining(pTextChain
->GetCursorEvent(pTextObj
), aNewSel
);
1007 pTextChain
->SetCursorEvent(pTextObj
, CursorChainingEvent::NULL_EVENT
);
1010 IMPL_LINK(SdrObjEditView
, ImpOutlinerCalcFieldValueHdl
, EditFieldInfo
*, pFI
, void)
1013 OUString
& rStr
= pFI
->GetRepresentation();
1015 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
1016 if (pTextObj
!= nullptr)
1018 std::optional
<Color
> pTxtCol
;
1019 std::optional
<Color
> pFldCol
;
1020 bOk
= pTextObj
->CalcFieldValue(pFI
->GetField(), pFI
->GetPara(), pFI
->GetPos(), true,
1021 pTxtCol
, pFldCol
, rStr
);
1026 pFI
->SetTextColor(*pTxtCol
);
1030 pFI
->SetFieldColor(*pFldCol
);
1034 pFI
->SetFieldColor(COL_LIGHTGRAY
); // TODO: remove this later on (357)
1038 Outliner
& rDrawOutl
= mpModel
->GetDrawOutliner(pTextObj
);
1039 Link
<EditFieldInfo
*, void> aDrawOutlLink
= rDrawOutl
.GetCalcFieldValueHdl();
1040 if (!bOk
&& aDrawOutlLink
.IsSet())
1042 aDrawOutlLink
.Call(pFI
);
1043 bOk
= !rStr
.isEmpty();
1047 aOldCalcFieldValueLink
.Call(pFI
);
1051 IMPL_LINK_NOARG(SdrObjEditView
, EndTextEditHdl
, SdrUndoManager
*, void) { SdrEndTextEdit(); }
1053 SdrUndoManager
* SdrObjEditView::getSdrUndoManagerForEnhancedTextEdit() const
1055 // default returns registered UndoManager
1056 return GetModel() ? dynamic_cast<SdrUndoManager
*>(GetModel()->GetSdrUndoManager()) : nullptr;
1059 bool SdrObjEditView::SdrBeginTextEdit(SdrObject
* pObj_
, SdrPageView
* pPV
, vcl::Window
* pWin
,
1060 bool bIsNewObj
, SdrOutliner
* pGivenOutliner
,
1061 OutlinerView
* pGivenOutlinerView
, bool bDontDeleteOutliner
,
1062 bool bOnlyOneView
, bool bGrabFocus
)
1064 // FIXME cannot be an assert() yet, the code is not ready for that;
1065 // eg. press F7 in Impress when you are inside a text object with spelling
1066 // mistakes => boom; and it is unclear how to avoid that
1067 SAL_WARN_IF(IsTextEdit(), "svx", "SdrBeginTextEdit called when IsTextEdit() is already true.");
1068 // FIXME this encourages all sorts of bad habits and should be removed
1071 SdrTextObj
* pObj
= dynamic_cast<SdrTextObj
*>(pObj_
);
1073 return false; // currently only possible with text objects
1075 if (bGrabFocus
&& pWin
)
1077 // attention, this call may cause an EndTextEdit() call to this view
1078 pWin
->GrabFocus(); // to force the cursor into the edit view
1081 bTextEditDontDelete
= bDontDeleteOutliner
&& pGivenOutliner
!= nullptr;
1082 bTextEditOnlyOneView
= bOnlyOneView
;
1083 bTextEditNewObj
= bIsNewObj
;
1084 const sal_uInt32
nWinCount(PaintWindowCount());
1090 for (i
= 0; i
< nWinCount
&& !pWin
; i
++)
1092 SdrPaintWindow
* pPaintWindow
= GetPaintWindow(i
);
1094 if (OUTDEV_WINDOW
== pPaintWindow
->GetOutputDevice().GetOutDevType())
1096 pWin
= static_cast<vcl::Window
*>(&pPaintWindow
->GetOutputDevice());
1100 // break, when no window exists
1109 pPV
= GetSdrPageView();
1111 // break, when no PageView for the object exists
1118 // no TextEdit on objects in locked Layer
1119 if (pPV
&& pPV
->GetLockedLayers().IsSet(pObj
->GetLayer()))
1124 if (pTextEditOutliner
)
1126 OSL_FAIL("SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists.");
1127 pTextEditOutliner
.reset();
1132 pTextEditWin
= pWin
;
1134 mxTextEditObj
.reset(pObj
);
1137 pTextEditOutliner
.reset(pGivenOutliner
);
1138 pGivenOutliner
= nullptr; // so we don't delete it on the error path
1141 pTextEditOutliner
= SdrMakeOutliner(OutlinerMode::TextObject
,
1142 mxTextEditObj
->getSdrModelFromSdrObject());
1145 SvtAccessibilityOptions aOptions
;
1146 pTextEditOutliner
->ForceAutoColor(aOptions
.GetIsAutomaticFontColor());
1149 aOldCalcFieldValueLink
= pTextEditOutliner
->GetCalcFieldValueHdl();
1150 // FieldHdl has to be set by SdrBeginTextEdit, because this call an UpdateFields
1151 pTextEditOutliner
->SetCalcFieldValueHdl(
1152 LINK(this, SdrObjEditView
, ImpOutlinerCalcFieldValueHdl
));
1153 pTextEditOutliner
->SetBeginPasteOrDropHdl(LINK(this, SdrObjEditView
, BeginPasteOrDropHdl
));
1154 pTextEditOutliner
->SetEndPasteOrDropHdl(LINK(this, SdrObjEditView
, EndPasteOrDropHdl
));
1156 // It is just necessary to make the visualized page known. Set it.
1157 pTextEditOutliner
->setVisualizedPage(pPV
->GetPage());
1159 pTextEditOutliner
->SetTextObjNoInit(mxTextEditObj
.get());
1161 if (mxTextEditObj
->BegTextEdit(*pTextEditOutliner
))
1163 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
1164 DBG_ASSERT(pTextObj
, "svx::SdrObjEditView::BegTextEdit(), no text object?");
1168 // switch off any running TextAnimations
1169 pTextObj
->SetTextAnimationAllowed(false);
1171 // remember old cursor
1172 if (pTextEditOutliner
->GetViewCount() != 0)
1174 pTextEditOutliner
->RemoveView(static_cast<size_t>(0));
1177 // Determine EditArea via TakeTextEditArea.
1178 // TODO: This could theoretically be left out, because TakeTextRect() calculates the aTextEditArea,
1179 // but aMinTextEditArea has to happen, too (therefore leaving this in right now)
1180 pTextObj
->TakeTextEditArea(nullptr, nullptr, &aTextEditArea
, &aMinTextEditArea
);
1182 tools::Rectangle aTextRect
;
1183 tools::Rectangle aAnchorRect
;
1184 pTextObj
->TakeTextRect(*pTextEditOutliner
, aTextRect
, true,
1185 &aAnchorRect
/* Give true here, not false */);
1187 if (!pTextObj
->IsContourTextFrame())
1189 // FitToSize not together with ContourFrame, for now
1190 if (pTextObj
->IsFitToSize())
1191 aTextRect
= aAnchorRect
;
1194 aTextEditArea
= aTextRect
;
1196 // add possible GridOffset to up-to-now view-independent EditAreas
1197 basegfx::B2DVector
aGridOffset(0.0, 0.0);
1198 if (getPossibleGridOffsetForSdrObject(aGridOffset
, pTextObj
, pPV
))
1200 const Point
aOffset(basegfx::fround(aGridOffset
.getX()),
1201 basegfx::fround(aGridOffset
.getY()));
1203 aTextEditArea
+= aOffset
;
1204 aMinTextEditArea
+= aOffset
;
1207 Point
aPvOfs(pTextObj
->GetTextEditOffset());
1208 aTextEditArea
.Move(aPvOfs
.X(), aPvOfs
.Y());
1209 aMinTextEditArea
.Move(aPvOfs
.X(), aPvOfs
.Y());
1210 pTextEditCursorBuffer
= pWin
->GetCursor();
1212 maHdlList
.SetMoveOutside(true);
1214 // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
1215 // to call AdjustMarkHdl() always.
1218 pTextEditOutlinerView
= ImpMakeOutlinerView(pWin
, pGivenOutlinerView
);
1220 if (!comphelper::LibreOfficeKit::isActive() && pTextEditOutlinerView
)
1222 // activate visualization of EditView on Overlay, suppress when
1223 // LibreOfficeKit is active
1224 pTextEditOutlinerView
->GetEditView().setEditViewCallbacks(this);
1226 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer
;
1227 const Color
aHilightColor(aSvtOptionsDrawinglayer
.getHilightColor());
1228 const SdrTextObj
* pText
= GetTextEditObject();
1229 const bool bTextFrame(pText
&& pText
->IsTextFrame());
1230 const bool bFitToSize(pTextEditOutliner
->GetControlWord()
1231 & EEControlBits::STRETCHING
);
1232 const bool bVisualizeSurroundingFrame(bTextFrame
&& !bFitToSize
);
1233 SdrPageView
* pPageView
= GetSdrPageView();
1237 for (sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1239 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1241 if (rPageWindow
.GetPaintWindow().OutputToWindow())
1243 const rtl::Reference
<sdr::overlay::OverlayManager
>& xManager
1244 = rPageWindow
.GetOverlayManager();
1247 std::unique_ptr
<TextEditOverlayObject
> pNewTextEditOverlayObject(
1248 new TextEditOverlayObject(aHilightColor
, *pTextEditOutlinerView
,
1249 bVisualizeSurroundingFrame
));
1251 xManager
->add(*pNewTextEditOverlayObject
);
1252 xManager
->add(const_cast<sdr::overlay::OverlaySelection
&>(
1253 *pNewTextEditOverlayObject
->getOverlaySelection()));
1255 maTEOverlayGroup
.append(std::move(pNewTextEditOverlayObject
));
1262 // check if this view is already inserted
1263 size_t i2
, nCount
= pTextEditOutliner
->GetViewCount();
1264 for (i2
= 0; i2
< nCount
; i2
++)
1266 if (pTextEditOutliner
->GetView(i2
) == pTextEditOutlinerView
)
1271 pTextEditOutliner
->InsertView(pTextEditOutlinerView
, 0);
1273 maHdlList
.SetMoveOutside(false);
1274 maHdlList
.SetMoveOutside(true);
1276 // register all windows as OutlinerViews with the Outliner
1279 for (i
= 0; i
< nWinCount
; i
++)
1281 SdrPaintWindow
* pPaintWindow
= GetPaintWindow(i
);
1282 OutputDevice
& rOutDev
= pPaintWindow
->GetOutputDevice();
1284 if (&rOutDev
!= pWin
&& OUTDEV_WINDOW
== rOutDev
.GetOutDevType())
1286 OutlinerView
* pOutlView
1287 = ImpMakeOutlinerView(static_cast<vcl::Window
*>(&rOutDev
), nullptr);
1288 pTextEditOutliner
->InsertView(pOutlView
, static_cast<sal_uInt16
>(i
));
1292 if (comphelper::LibreOfficeKit::isActive())
1294 // Register an outliner view for all other sdr views that
1295 // show the same page, so that when the text edit changes,
1296 // all interested windows get an invalidation.
1297 SdrViewIter
aIter(pObj
->getSdrPageFromSdrObject());
1298 for (SdrView
* pView
= aIter
.FirstView(); pView
; pView
= aIter
.NextView())
1303 for (sal_uInt32 nViewPaintWindow
= 0;
1304 nViewPaintWindow
< pView
->PaintWindowCount(); ++nViewPaintWindow
)
1306 SdrPaintWindow
* pPaintWindow
= pView
->GetPaintWindow(nViewPaintWindow
);
1307 OutputDevice
& rOutDev
= pPaintWindow
->GetOutputDevice();
1309 if (&rOutDev
!= pWin
&& OUTDEV_WINDOW
== rOutDev
.GetOutDevType())
1311 OutlinerView
* pOutlView
= ImpMakeOutlinerView(
1312 static_cast<vcl::Window
*>(&rOutDev
), nullptr);
1313 pOutlView
->HideCursor();
1314 static_cast<vcl::Window
*>(&rOutDev
)->SetCursor(nullptr);
1315 pTextEditOutliner
->InsertView(pOutlView
);
1322 pTextEditOutlinerView
->ShowCursor();
1323 pTextEditOutliner
->SetStatusEventHdl(
1324 LINK(this, SdrObjEditView
, ImpOutlinerStatusEventHdl
));
1325 if (pTextObj
->IsChainable())
1327 pTextEditOutlinerView
->SetEndCutPasteLinkHdl(
1328 LINK(this, SdrObjEditView
, ImpAfterCutOrPasteChainingEventHdl
));
1331 pTextEditOutliner
->ClearModifyFlag();
1333 if (pTextObj
->IsFitToSize())
1335 pWin
->Invalidate(aTextEditArea
);
1340 SdrHint
aHint(SdrHintKind::BeginEdit
, *pTextObj
);
1341 GetModel()->Broadcast(aHint
);
1344 pTextEditOutliner
->setVisualizedPage(nullptr);
1346 if (mxSelectionController
.is())
1347 mxSelectionController
->onSelectionHasChanged();
1349 if (GetModel() && IsUndoEnabled()
1350 && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
1352 SdrUndoManager
* pSdrUndoManager
= getSdrUndoManagerForEnhancedTextEdit();
1354 if (pSdrUndoManager
)
1356 // we have an outliner, undo manager and it's an EditUndoManager, exchange
1357 // the document undo manager and the default one from the outliner and tell
1358 // it that text edit starts by setting a callback if it needs to end text edit mode.
1359 assert(nullptr == mpOldTextEditUndoManager
);
1361 mpOldTextEditUndoManager
= pTextEditOutliner
->SetUndoManager(pSdrUndoManager
);
1362 pSdrUndoManager
->SetEndTextEditHdl(LINK(this, SdrObjEditView
, EndTextEditHdl
));
1367 "The document undo manager is not derived from SdrUndoManager (!)");
1371 return true; // ran fine, let TextEdit run now
1375 pTextEditOutliner
->SetCalcFieldValueHdl(aOldCalcFieldValueLink
);
1376 pTextEditOutliner
->SetBeginPasteOrDropHdl(Link
<PasteOrDropInfos
*, void>());
1377 pTextEditOutliner
->SetEndPasteOrDropHdl(Link
<PasteOrDropInfos
*, void>());
1380 if (pTextEditOutliner
!= nullptr)
1382 pTextEditOutliner
->setVisualizedPage(nullptr);
1385 // something went wrong...
1386 if (!bDontDeleteOutliner
)
1388 delete pGivenOutliner
;
1389 if (pGivenOutlinerView
!= nullptr)
1391 delete pGivenOutlinerView
;
1392 pGivenOutlinerView
= nullptr;
1395 pTextEditOutliner
.reset();
1397 pTextEditOutlinerView
= nullptr;
1398 mxTextEditObj
.reset(nullptr);
1399 pTextEditPV
= nullptr;
1400 pTextEditWin
= nullptr;
1401 maHdlList
.SetMoveOutside(false);
1406 SdrEndTextEditKind
SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally
)
1408 SdrEndTextEditKind eRet
= SdrEndTextEditKind::Unchanged
;
1409 SdrTextObj
* pTEObj
= mxTextEditObj
.get();
1410 vcl::Window
* pTEWin
= pTextEditWin
;
1411 OutlinerView
* pTEOutlinerView
= pTextEditOutlinerView
;
1412 vcl::Cursor
* pTECursorBuffer
= pTextEditCursorBuffer
;
1413 SdrUndoManager
* pUndoEditUndoManager
= nullptr;
1414 bool bNeedToUndoSavedRedoTextEdit(false);
1416 if (GetModel() && IsUndoEnabled() && pTEObj
&& pTextEditOutliner
1417 && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
1419 // change back the UndoManager to the remembered original one
1420 SfxUndoManager
* pOriginal
= pTextEditOutliner
->SetUndoManager(mpOldTextEditUndoManager
);
1421 mpOldTextEditUndoManager
= nullptr;
1425 // check if we got back our document undo manager
1426 SdrUndoManager
* pSdrUndoManager
= getSdrUndoManagerForEnhancedTextEdit();
1428 if (pSdrUndoManager
&& dynamic_cast<SdrUndoManager
*>(pOriginal
) == pSdrUndoManager
)
1430 if (pSdrUndoManager
->isEndTextEditTriggeredFromUndo())
1432 // remember the UndoManager where missing Undos have to be triggered after end
1433 // text edit. When the undo had triggered the end text edit, the original action
1434 // which had to be undone originally is not yet undone.
1435 pUndoEditUndoManager
= pSdrUndoManager
;
1437 // We are ending text edit; if text edit was triggered from undo, execute all redos
1438 // to create a complete text change undo action for the redo buffer. Also mark this
1439 // state when at least one redo was executed; the created extra TextChange needs to
1440 // be undone in addition to the first real undo outside the text edit changes
1441 while (pSdrUndoManager
->GetRedoActionCount()
1442 > pSdrUndoManager
->GetRedoActionCountBeforeTextEdit())
1444 bNeedToUndoSavedRedoTextEdit
= true;
1445 pSdrUndoManager
->Redo();
1449 // reset the callback link and let the undo manager cleanup all text edit
1450 // undo actions to get the stack back to the form before the text edit
1451 pSdrUndoManager
->SetEndTextEditHdl(Link
<SdrUndoManager
*, void>());
1455 OSL_ENSURE(false, "Got UndoManager back in SdrEndTextEdit which is NOT the "
1456 "expected document UndoManager (!)");
1463 assert(nullptr == mpOldTextEditUndoManager
); // cannot be restored!
1466 if (GetModel() && mxTextEditObj
.is())
1468 SdrHint
aHint(SdrHintKind::EndEdit
, *mxTextEditObj
);
1469 GetModel()->Broadcast(aHint
);
1472 // if new mechanism was used, clean it up. At cleanup no need to check
1473 // for LibreOfficeKit
1474 if (pTextEditOutlinerView
)
1476 pTextEditOutlinerView
->GetEditView().setEditViewCallbacks(nullptr);
1477 maTEOverlayGroup
.clear();
1480 mxTextEditObj
.reset(nullptr);
1481 pTextEditPV
= nullptr;
1482 pTextEditWin
= nullptr;
1483 SdrOutliner
* pTEOutliner
= pTextEditOutliner
.release();
1484 pTextEditOutlinerView
= nullptr;
1485 pTextEditCursorBuffer
= nullptr;
1486 aTextEditArea
= tools::Rectangle();
1488 if (pTEOutliner
!= nullptr)
1490 bool bModified
= pTEOutliner
->IsModified();
1491 if (pTEOutlinerView
!= nullptr)
1493 pTEOutlinerView
->HideCursor();
1495 if (pTEObj
!= nullptr)
1497 pTEOutliner
->CompleteOnlineSpelling();
1499 std::unique_ptr
<SdrUndoObjSetText
> pTxtUndo
;
1504 for (nText
= 0; nText
< pTEObj
->getTextCount(); ++nText
)
1505 if (pTEObj
->getText(nText
) == pTEObj
->getActiveText())
1509 dynamic_cast<SdrUndoObjSetText
*>(GetModel()
1510 ->GetSdrUndoFactory()
1511 .CreateUndoObjectSetText(*pTEObj
, nText
)
1514 DBG_ASSERT(!bModified
|| pTxtUndo
,
1515 "svx::SdrObjEditView::EndTextEdit(), could not create undo action!");
1516 // Set old CalcFieldValue-Handler again, this
1517 // has to happen before Obj::EndTextEdit(), as this does UpdateFields().
1518 pTEOutliner
->SetCalcFieldValueHdl(aOldCalcFieldValueLink
);
1519 pTEOutliner
->SetBeginPasteOrDropHdl(Link
<PasteOrDropInfos
*, void>());
1520 pTEOutliner
->SetEndPasteOrDropHdl(Link
<PasteOrDropInfos
*, void>());
1522 const bool bUndo
= IsUndoEnabled();
1525 EndTextEditAllViews();
1526 OUString
aObjName(pTEObj
->TakeObjNameSingul());
1527 BegUndo(SvxResId(STR_UndoObjSetText
), aObjName
);
1530 pTEObj
->EndTextEdit(*pTEOutliner
);
1532 if ((pTEObj
->GetRotateAngle() != 0)
1533 || (dynamic_cast<const SdrTextObj
*>(pTEObj
) != nullptr && pTEObj
->IsFontwork()))
1535 pTEObj
->ActionChanged();
1538 if (pTxtUndo
!= nullptr)
1540 pTxtUndo
->AfterSetText();
1541 if (!pTxtUndo
->IsDifferent())
1546 // check deletion of entire TextObj
1547 std::unique_ptr
<SdrUndoAction
> pDelUndo
;
1548 bool bDelObj
= false;
1549 if (bTextEditNewObj
)
1551 bDelObj
= pTEObj
->IsTextFrame() && !pTEObj
->HasText() && !pTEObj
->IsEmptyPresObj()
1552 && !pTEObj
->HasFill() && !pTEObj
->HasLine();
1554 if (pTEObj
->IsInserted() && bDelObj
1555 && pTEObj
->GetObjInventor() == SdrInventor::Default
&& !bDontDeleteReally
)
1557 SdrObjKind eIdent
= pTEObj
->GetObjIdentifier();
1558 if (eIdent
== OBJ_TEXT
)
1560 pDelUndo
= GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pTEObj
);
1567 AddUndo(std::move(pTxtUndo
));
1568 eRet
= SdrEndTextEditKind::Changed
;
1570 if (pDelUndo
!= nullptr)
1574 AddUndo(std::move(pDelUndo
));
1576 eRet
= SdrEndTextEditKind::Deleted
;
1577 DBG_ASSERT(pTEObj
->getParentSdrObjListFromSdrObject() != nullptr,
1578 "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "
1580 if (pTEObj
->getParentSdrObjListFromSdrObject() != nullptr)
1582 pTEObj
->getParentSdrObjListFromSdrObject()->RemoveObject(pTEObj
->GetOrdNum());
1583 CheckMarked(); // remove selection immediately...
1587 { // for Writer: the app has to do the deletion itself.
1588 eRet
= SdrEndTextEditKind::ShouldBeDeleted
;
1592 EndUndo(); // EndUndo after Remove, in case UndoStack is deleted immediately
1594 // Switch on any TextAnimation again after TextEdit
1595 if (dynamic_cast<const SdrTextObj
*>(pTEObj
) != nullptr)
1597 pTEObj
->SetTextAnimationAllowed(true);
1600 // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
1601 // to call AdjustMarkHdl() always.
1604 // delete all OutlinerViews
1605 for (size_t i
= pTEOutliner
->GetViewCount(); i
> 0;)
1608 OutlinerView
* pOLV
= pTEOutliner
->GetView(i
);
1609 sal_uInt16 nMorePix
= pOLV
->GetInvalidateMore() + 10;
1610 vcl::Window
* pWin
= pOLV
->GetWindow();
1611 tools::Rectangle
aRect(pOLV
->GetOutputArea());
1612 pTEOutliner
->RemoveView(i
);
1613 if (!bTextEditDontDelete
|| i
!= 0)
1615 // may not own the zeroth one
1618 aRect
.Union(aTextEditArea
);
1619 aRect
.Union(aMinTextEditArea
);
1620 aRect
= pWin
->LogicToPixel(aRect
);
1621 aRect
.AdjustLeft(-nMorePix
);
1622 aRect
.AdjustTop(-nMorePix
);
1623 aRect
.AdjustRight(nMorePix
);
1624 aRect
.AdjustBottom(nMorePix
);
1625 aRect
= pWin
->PixelToLogic(aRect
);
1626 InvalidateOneWin(*pWin
, aRect
);
1627 pWin
->SetFillColor();
1628 pWin
->SetLineColor(COL_BLACK
);
1630 // and now the Outliner itself
1631 if (!bTextEditDontDelete
)
1634 pTEOutliner
->Clear();
1635 if (pTEWin
!= nullptr)
1637 pTEWin
->SetCursor(pTECursorBuffer
);
1639 maHdlList
.SetMoveOutside(false);
1640 if (eRet
!= SdrEndTextEditKind::Unchanged
)
1642 GetMarkedObjectListWriteAccess().SetNameDirty();
1646 if (pTEObj
&& !pTEObj
->getSdrModelFromSdrObject().isLocked() && pTEObj
->GetBroadcaster())
1648 SdrHint
aHint(SdrHintKind::EndEdit
, *pTEObj
);
1649 const_cast<SfxBroadcaster
*>(pTEObj
->GetBroadcaster())->Broadcast(aHint
);
1652 if (pUndoEditUndoManager
)
1654 if (bNeedToUndoSavedRedoTextEdit
)
1656 // undo the text edit action since it was created as part of an EndTextEdit
1657 // callback from undo itself. This needs to be done after the call to
1658 // FmFormView::SdrEndTextEdit since it gets created there
1659 pUndoEditUndoManager
->Undo();
1662 // trigger the Undo which was not executed, but lead to this
1664 pUndoEditUndoManager
->Undo();
1670 // info about TextEdit. Default is false.
1671 bool SdrObjEditView::IsTextEdit() const { return mxTextEditObj
.is(); }
1673 // info about TextEditPageView. Default is 0L.
1674 SdrPageView
* SdrObjEditView::GetTextEditPageView() const { return pTextEditPV
; }
1676 OutlinerView
* SdrObjEditView::ImpFindOutlinerView(vcl::Window
const* pWin
) const
1678 if (pWin
== nullptr)
1680 if (pTextEditOutliner
== nullptr)
1682 OutlinerView
* pNewView
= nullptr;
1683 size_t nWinCount
= pTextEditOutliner
->GetViewCount();
1684 for (size_t i
= 0; i
< nWinCount
&& pNewView
== nullptr; i
++)
1686 OutlinerView
* pView
= pTextEditOutliner
->GetView(i
);
1687 if (pView
->GetWindow() == pWin
)
1693 void SdrObjEditView::SetTextEditWin(vcl::Window
* pWin
)
1695 if (!(mxTextEditObj
.is() && pWin
!= nullptr && pWin
!= pTextEditWin
))
1698 OutlinerView
* pNewView
= ImpFindOutlinerView(pWin
);
1699 if (pNewView
!= nullptr && pNewView
!= pTextEditOutlinerView
)
1701 if (pTextEditOutlinerView
!= nullptr)
1703 pTextEditOutlinerView
->HideCursor();
1705 pTextEditOutlinerView
= pNewView
;
1706 pTextEditWin
= pWin
;
1707 pWin
->GrabFocus(); // Make the cursor blink here as well
1708 pNewView
->ShowCursor();
1709 ImpMakeTextCursorAreaVisible();
1713 bool SdrObjEditView::IsTextEditHit(const Point
& rHit
) const
1716 if (mxTextEditObj
.is())
1718 tools::Rectangle aEditArea
;
1719 OutlinerView
* pOLV
= pTextEditOutliner
->GetView(0);
1720 if (pOLV
!= nullptr)
1722 aEditArea
.Union(pOLV
->GetOutputArea());
1724 bOk
= aEditArea
.IsInside(rHit
);
1726 { // check if any characters were actually hit
1728 aPnt
-= aEditArea
.TopLeft();
1729 tools::Long nHitTol
= 2000;
1730 OutputDevice
* pRef
= pTextEditOutliner
->GetRefDevice();
1732 nHitTol
= OutputDevice::LogicToLogic(nHitTol
, MapUnit::Map100thMM
,
1733 pRef
->GetMapMode().GetMapUnit());
1735 bOk
= pTextEditOutliner
->IsTextPos(aPnt
, static_cast<sal_uInt16
>(nHitTol
));
1741 bool SdrObjEditView::IsTextEditFrameHit(const Point
& rHit
) const
1744 if (mxTextEditObj
.is())
1746 SdrTextObj
* pText
= mxTextEditObj
.get();
1747 OutlinerView
* pOLV
= pTextEditOutliner
->GetView(0);
1750 vcl::Window
* pWin
= pOLV
->GetWindow();
1751 if (pText
!= nullptr && pText
->IsTextFrame() && pWin
!= nullptr)
1753 sal_uInt16 nPixSiz
= pOLV
->GetInvalidateMore();
1754 tools::Rectangle
aEditArea(aMinTextEditArea
);
1755 aEditArea
.Union(pOLV
->GetOutputArea());
1756 if (!aEditArea
.IsInside(rHit
))
1758 Size
aSiz(pWin
->PixelToLogic(Size(nPixSiz
, nPixSiz
)));
1759 aEditArea
.AdjustLeft(-(aSiz
.Width()));
1760 aEditArea
.AdjustTop(-(aSiz
.Height()));
1761 aEditArea
.AdjustRight(aSiz
.Width());
1762 aEditArea
.AdjustBottom(aSiz
.Height());
1763 bOk
= aEditArea
.IsInside(rHit
);
1771 TextChainCursorManager
* SdrObjEditView::ImpHandleMotionThroughBoxesKeyInput(const KeyEvent
& rKEvt
,
1774 *bOutHandled
= false;
1776 SdrTextObj
* pTextObj
= mxTextEditObj
.get();
1780 if (!pTextObj
->GetNextLinkInChain() && !pTextObj
->GetPrevLinkInChain())
1783 TextChainCursorManager
* pCursorManager
= new TextChainCursorManager(this, pTextObj
);
1784 if (pCursorManager
->HandleKeyEvent(rKEvt
))
1786 // Possibly do other stuff here if necessary...
1787 // XXX: Careful with the checks below (in KeyInput) for pWin and co. You should do them here I guess.
1788 *bOutHandled
= true;
1791 return pCursorManager
;
1794 bool SdrObjEditView::KeyInput(const KeyEvent
& rKEvt
, vcl::Window
* pWin
)
1796 if (pTextEditOutlinerView
)
1798 /* Start special handling of keys within a chain */
1799 // We possibly move to another box before any handling
1800 bool bHandled
= false;
1801 std::unique_ptr
<TextChainCursorManager
> xCursorManager(
1802 ImpHandleMotionThroughBoxesKeyInput(rKEvt
, &bHandled
));
1805 /* End special handling of keys within a chain */
1807 if (pTextEditOutlinerView
->PostKeyEvent(rKEvt
, pWin
))
1811 if (pTextEditOutliner
&& pTextEditOutliner
->IsModified())
1812 mpModel
->SetChanged();
1815 /* Start chaining processing */
1816 ImpChainingEventHdl();
1817 ImpMoveCursorAfterChainingEvent(xCursorManager
.get());
1818 /* End chaining processing */
1820 if (pWin
!= nullptr && pWin
!= pTextEditWin
)
1821 SetTextEditWin(pWin
);
1822 ImpMakeTextCursorAreaVisible();
1826 return SdrGlueEditView::KeyInput(rKEvt
, pWin
);
1829 bool SdrObjEditView::MouseButtonDown(const MouseEvent
& rMEvt
, OutputDevice
* pWin
)
1831 if (pTextEditOutlinerView
!= nullptr)
1833 bool bPostIt
= pTextEditOutliner
->IsInSelectionMode();
1836 Point
aPt(rMEvt
.GetPosPixel());
1837 if (pWin
!= nullptr)
1838 aPt
= pWin
->PixelToLogic(aPt
);
1839 else if (pTextEditWin
!= nullptr)
1840 aPt
= pTextEditWin
->PixelToLogic(aPt
);
1841 bPostIt
= IsTextEditHit(aPt
);
1845 Point
aPixPos(rMEvt
.GetPosPixel());
1848 tools::Rectangle
aR(pWin
->LogicToPixel(pTextEditOutlinerView
->GetOutputArea()));
1849 if (aPixPos
.X() < aR
.Left())
1850 aPixPos
.setX(aR
.Left());
1851 if (aPixPos
.X() > aR
.Right())
1852 aPixPos
.setX(aR
.Right());
1853 if (aPixPos
.Y() < aR
.Top())
1854 aPixPos
.setY(aR
.Top());
1855 if (aPixPos
.Y() > aR
.Bottom())
1856 aPixPos
.setY(aR
.Bottom());
1858 MouseEvent
aMEvt(aPixPos
, rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(),
1859 rMEvt
.GetModifier());
1860 if (pTextEditOutlinerView
->MouseButtonDown(aMEvt
))
1862 if (pWin
!= nullptr && pWin
!= pTextEditWin
1863 && pWin
->GetOutDevType() == OUTDEV_WINDOW
)
1864 SetTextEditWin(static_cast<vcl::Window
*>(pWin
));
1865 ImpMakeTextCursorAreaVisible();
1870 return SdrGlueEditView::MouseButtonDown(rMEvt
, pWin
);
1873 bool SdrObjEditView::MouseButtonUp(const MouseEvent
& rMEvt
, OutputDevice
* pWin
)
1875 if (pTextEditOutlinerView
!= nullptr)
1877 bool bPostIt
= pTextEditOutliner
->IsInSelectionMode();
1880 Point
aPt(rMEvt
.GetPosPixel());
1881 if (pWin
!= nullptr)
1882 aPt
= pWin
->PixelToLogic(aPt
);
1883 else if (pTextEditWin
!= nullptr)
1884 aPt
= pTextEditWin
->PixelToLogic(aPt
);
1885 bPostIt
= IsTextEditHit(aPt
);
1887 if (bPostIt
&& pWin
)
1889 Point
aPixPos(rMEvt
.GetPosPixel());
1890 tools::Rectangle
aR(pWin
->LogicToPixel(pTextEditOutlinerView
->GetOutputArea()));
1891 if (aPixPos
.X() < aR
.Left())
1892 aPixPos
.setX(aR
.Left());
1893 if (aPixPos
.X() > aR
.Right())
1894 aPixPos
.setX(aR
.Right());
1895 if (aPixPos
.Y() < aR
.Top())
1896 aPixPos
.setY(aR
.Top());
1897 if (aPixPos
.Y() > aR
.Bottom())
1898 aPixPos
.setY(aR
.Bottom());
1899 MouseEvent
aMEvt(aPixPos
, rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(),
1900 rMEvt
.GetModifier());
1901 if (pTextEditOutlinerView
->MouseButtonUp(aMEvt
))
1903 ImpMakeTextCursorAreaVisible();
1908 return SdrGlueEditView::MouseButtonUp(rMEvt
, pWin
);
1911 bool SdrObjEditView::MouseMove(const MouseEvent
& rMEvt
, OutputDevice
* pWin
)
1913 if (pTextEditOutlinerView
!= nullptr)
1915 bool bSelMode
= pTextEditOutliner
->IsInSelectionMode();
1916 bool bPostIt
= bSelMode
;
1919 Point
aPt(rMEvt
.GetPosPixel());
1921 aPt
= pWin
->PixelToLogic(aPt
);
1922 else if (pTextEditWin
)
1923 aPt
= pTextEditWin
->PixelToLogic(aPt
);
1924 bPostIt
= IsTextEditHit(aPt
);
1928 Point
aPixPos(rMEvt
.GetPosPixel());
1929 tools::Rectangle
aR(pTextEditOutlinerView
->GetOutputArea());
1931 aR
= pWin
->LogicToPixel(aR
);
1932 else if (pTextEditWin
)
1933 aR
= pTextEditWin
->LogicToPixel(aR
);
1934 if (aPixPos
.X() < aR
.Left())
1935 aPixPos
.setX(aR
.Left());
1936 if (aPixPos
.X() > aR
.Right())
1937 aPixPos
.setX(aR
.Right());
1938 if (aPixPos
.Y() < aR
.Top())
1939 aPixPos
.setY(aR
.Top());
1940 if (aPixPos
.Y() > aR
.Bottom())
1941 aPixPos
.setY(aR
.Bottom());
1942 MouseEvent
aMEvt(aPixPos
, rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(),
1943 rMEvt
.GetModifier());
1944 if (pTextEditOutlinerView
->MouseMove(aMEvt
) && bSelMode
)
1946 ImpMakeTextCursorAreaVisible();
1951 return SdrGlueEditView::MouseMove(rMEvt
, pWin
);
1954 bool SdrObjEditView::Command(const CommandEvent
& rCEvt
, vcl::Window
* pWin
)
1956 // as long as OutlinerView returns a sal_Bool, it only gets CommandEventId::StartDrag
1957 if (pTextEditOutlinerView
!= nullptr)
1959 if (rCEvt
.GetCommand() == CommandEventId::StartDrag
)
1961 bool bPostIt
= pTextEditOutliner
->IsInSelectionMode() || !rCEvt
.IsMouseEvent();
1962 if (!bPostIt
&& rCEvt
.IsMouseEvent())
1964 Point
aPt(rCEvt
.GetMousePosPixel());
1965 if (pWin
!= nullptr)
1966 aPt
= pWin
->PixelToLogic(aPt
);
1967 else if (pTextEditWin
!= nullptr)
1968 aPt
= pTextEditWin
->PixelToLogic(aPt
);
1969 bPostIt
= IsTextEditHit(aPt
);
1973 Point
aPixPos(rCEvt
.GetMousePosPixel());
1974 if (rCEvt
.IsMouseEvent() && pWin
)
1976 tools::Rectangle
aR(pWin
->LogicToPixel(pTextEditOutlinerView
->GetOutputArea()));
1977 if (aPixPos
.X() < aR
.Left())
1978 aPixPos
.setX(aR
.Left());
1979 if (aPixPos
.X() > aR
.Right())
1980 aPixPos
.setX(aR
.Right());
1981 if (aPixPos
.Y() < aR
.Top())
1982 aPixPos
.setY(aR
.Top());
1983 if (aPixPos
.Y() > aR
.Bottom())
1984 aPixPos
.setY(aR
.Bottom());
1986 CommandEvent
aCEvt(aPixPos
, rCEvt
.GetCommand(), rCEvt
.IsMouseEvent());
1987 // Command is void at the OutlinerView, sadly
1988 pTextEditOutlinerView
->Command(aCEvt
);
1989 if (pWin
!= nullptr && pWin
!= pTextEditWin
)
1990 SetTextEditWin(pWin
);
1991 ImpMakeTextCursorAreaVisible();
1997 pTextEditOutlinerView
->Command(rCEvt
);
1998 if (mpModel
&& comphelper::LibreOfficeKit::isActive())
2000 // It could execute CommandEventId::ExtTextInput, while SdrObjEditView::KeyInput
2002 if (pTextEditOutliner
&& pTextEditOutliner
->IsModified())
2003 mpModel
->SetChanged();
2008 return SdrGlueEditView::Command(rCEvt
, pWin
);
2011 bool SdrObjEditView::ImpIsTextEditAllSelected() const
2014 if (pTextEditOutliner
!= nullptr && pTextEditOutlinerView
!= nullptr)
2016 if (SdrTextObj::HasTextImpl(pTextEditOutliner
.get()))
2018 const sal_Int32 nParaCnt
= pTextEditOutliner
->GetParagraphCount();
2019 Paragraph
* pLastPara
= pTextEditOutliner
->GetParagraph(nParaCnt
> 1 ? nParaCnt
- 1 : 0);
2021 ESelection
aESel(pTextEditOutlinerView
->GetSelection());
2022 if (aESel
.nStartPara
== 0 && aESel
.nStartPos
== 0 && aESel
.nEndPara
== (nParaCnt
- 1))
2024 if (pTextEditOutliner
->GetText(pLastPara
).getLength() == aESel
.nEndPos
)
2027 // in case the selection was done backwards
2028 if (!bRet
&& aESel
.nEndPara
== 0 && aESel
.nEndPos
== 0
2029 && aESel
.nStartPara
== (nParaCnt
- 1))
2031 if (pTextEditOutliner
->GetText(pLastPara
).getLength() == aESel
.nStartPos
)
2043 void SdrObjEditView::ImpMakeTextCursorAreaVisible()
2045 if (pTextEditOutlinerView
!= nullptr && pTextEditWin
!= nullptr)
2047 vcl::Cursor
* pCsr
= pTextEditWin
->GetCursor();
2048 if (pCsr
!= nullptr)
2050 Size
aSiz(pCsr
->GetSize());
2051 if (!aSiz
.IsEmpty())
2053 MakeVisible(tools::Rectangle(pCsr
->GetPos(), aSiz
), *pTextEditWin
);
2059 SvtScriptType
SdrObjEditView::GetScriptType() const
2061 SvtScriptType nScriptType
= SvtScriptType::NONE
;
2065 if (mxTextEditObj
->GetOutlinerParaObject())
2066 nScriptType
= mxTextEditObj
->GetOutlinerParaObject()->GetTextObject().GetScriptType();
2068 if (pTextEditOutlinerView
)
2069 nScriptType
= pTextEditOutlinerView
->GetSelectedScriptType();
2073 const size_t nMarkCount(GetMarkedObjectCount());
2075 for (size_t i
= 0; i
< nMarkCount
; ++i
)
2077 OutlinerParaObject
* pParaObj
= GetMarkedObjectByIndex(i
)->GetOutlinerParaObject();
2081 nScriptType
|= pParaObj
->GetTextObject().GetScriptType();
2086 if (nScriptType
== SvtScriptType::NONE
)
2087 nScriptType
= SvtScriptType::LATIN
;
2092 void SdrObjEditView::GetAttributes(SfxItemSet
& rTargetSet
, bool bOnlyHardAttr
) const
2094 if (mxSelectionController
.is())
2095 if (mxSelectionController
->GetAttributes(rTargetSet
, bOnlyHardAttr
))
2100 DBG_ASSERT(pTextEditOutlinerView
!= nullptr,
2101 "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL");
2102 DBG_ASSERT(pTextEditOutliner
!= nullptr,
2103 "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL");
2105 // take care of bOnlyHardAttr(!)
2106 if (!bOnlyHardAttr
&& mxTextEditObj
->GetStyleSheet())
2107 rTargetSet
.Put(mxTextEditObj
->GetStyleSheet()->GetItemSet());
2109 // add object attributes
2110 rTargetSet
.Put(mxTextEditObj
->GetMergedItemSet());
2112 if (pTextEditOutlinerView
)
2114 // FALSE= regard InvalidItems as "holes," not as Default
2115 rTargetSet
.Put(pTextEditOutlinerView
->GetAttribs(), false);
2118 if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj
.get())
2120 MergeNotPersistAttrFromMarked(rTargetSet
);
2125 SdrGlueEditView::GetAttributes(rTargetSet
, bOnlyHardAttr
);
2129 bool SdrObjEditView::SetAttributes(const SfxItemSet
& rSet
, bool bReplaceAll
)
2132 bool bTextEdit
= pTextEditOutlinerView
!= nullptr && mxTextEditObj
.is();
2133 bool bAllTextSelected
= ImpIsTextEditAllSelected();
2134 const SfxItemSet
* pSet
= &rSet
;
2138 // no TextEdit active -> all Items to drawing object
2139 if (mxSelectionController
.is())
2140 bRet
= mxSelectionController
->SetAttributes(*pSet
, bReplaceAll
);
2144 SdrGlueEditView::SetAttributes(*pSet
, bReplaceAll
);
2152 bool bHasEEFeatureItems
= false;
2153 SfxItemIter
aIter(rSet
);
2154 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); !bHasEEFeatureItems
&& pItem
;
2155 pItem
= aIter
.NextItem())
2157 if (!IsInvalidItem(pItem
))
2159 sal_uInt16 nW
= pItem
->Which();
2160 if (nW
>= EE_FEATURE_START
&& nW
<= EE_FEATURE_END
)
2161 bHasEEFeatureItems
= true;
2165 if (bHasEEFeatureItems
)
2167 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(
2168 nullptr, VclMessageType::Info
, VclButtonsType::Ok
,
2169 "SdrObjEditView::SetAttributes(): Setting EE_FEATURE items "
2170 "at the SdrView does not make sense! It only leads to "
2171 "overhead and unreadable documents."));
2178 bool bNoEEItems
= !SearchOutlinerItems(*pSet
, bReplaceAll
, &bOnlyEEItems
);
2179 // everything selected? -> attributes to the border, too
2180 // if no EEItems, attributes to the border only
2181 if (bAllTextSelected
|| bNoEEItems
)
2183 if (mxSelectionController
.is())
2184 bRet
= mxSelectionController
->SetAttributes(*pSet
, bReplaceAll
);
2188 const bool bUndo
= IsUndoEnabled();
2192 BegUndo(ImpGetDescriptionString(STR_EditSetAttributes
));
2193 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj
));
2195 // If this is a text object also rescue the OutlinerParaObject since
2196 // applying attributes to the object may change text layout when
2197 // multiple portions exist with multiple formats. If an OutlinerParaObject
2198 // really exists and needs to be rescued is evaluated in the undo
2199 // implementation itself.
2200 bool bRescueText
= mxTextEditObj
;
2202 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(
2203 *mxTextEditObj
, false, !bNoEEItems
|| bRescueText
));
2207 mxTextEditObj
->SetMergedItemSetAndBroadcast(*pSet
, bReplaceAll
);
2209 FlushComeBackTimer(); // to set ModeHasChanged immediately
2212 else if (!bOnlyEEItems
)
2214 // Otherwise split Set, if necessary.
2215 // Now we build an ItemSet aSet that doesn't contain EE_Items from
2216 // *pSet (otherwise it would be a copy).
2217 std::unique_ptr
<sal_uInt16
[]> pNewWhichTable
2218 = RemoveWhichRange(pSet
->GetRanges(), EE_ITEMS_START
, EE_ITEMS_END
);
2219 SfxItemSet
aSet(mpModel
->GetItemPool(), pNewWhichTable
.get());
2220 pNewWhichTable
.reset();
2221 SfxWhichIter
aIter(aSet
);
2222 sal_uInt16 nWhich
= aIter
.FirstWhich();
2225 const SfxPoolItem
* pItem
;
2226 SfxItemState eState
= pSet
->GetItemState(nWhich
, false, &pItem
);
2227 if (eState
== SfxItemState::SET
)
2229 nWhich
= aIter
.NextWhich();
2232 if (mxSelectionController
.is())
2233 bRet
= mxSelectionController
->SetAttributes(aSet
, bReplaceAll
);
2237 if (IsUndoEnabled())
2239 BegUndo(ImpGetDescriptionString(STR_EditSetAttributes
));
2240 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxTextEditObj
));
2241 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*mxTextEditObj
));
2245 mxTextEditObj
->SetMergedItemSetAndBroadcast(aSet
, bReplaceAll
);
2247 if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxTextEditObj
.get())
2249 SetNotPersistAttrToMarked(aSet
);
2252 FlushComeBackTimer();
2256 // and now the attributes to the EditEngine
2259 pTextEditOutlinerView
->RemoveAttribs(true);
2261 pTextEditOutlinerView
->SetAttribs(rSet
);
2263 Outliner
* pTEOutliner
= pTextEditOutlinerView
->GetOutliner();
2264 if (mpModel
&& pTEOutliner
&& pTEOutliner
->IsModified())
2265 mpModel
->SetChanged();
2267 ImpMakeTextCursorAreaVisible();
2274 SfxStyleSheet
* SdrObjEditView::GetStyleSheet() const
2276 SfxStyleSheet
* pSheet
= nullptr;
2278 if (mxSelectionController
.is())
2280 if (mxSelectionController
->GetStyleSheet(pSheet
))
2284 if (pTextEditOutlinerView
)
2286 pSheet
= pTextEditOutlinerView
->GetStyleSheet();
2290 pSheet
= SdrGlueEditView::GetStyleSheet();
2295 void SdrObjEditView::SetStyleSheet(SfxStyleSheet
* pStyleSheet
, bool bDontRemoveHardAttr
)
2297 if (mxSelectionController
.is())
2299 if (mxSelectionController
->SetStyleSheet(pStyleSheet
, bDontRemoveHardAttr
))
2303 // if we are currently in edit mode we must also set the stylesheet
2304 // on all paragraphs in the Outliner for the edit view
2305 if (nullptr != pTextEditOutlinerView
)
2307 Outliner
* pOutliner
= pTextEditOutlinerView
->GetOutliner();
2309 const sal_Int32 nParaCount
= pOutliner
->GetParagraphCount();
2310 for (sal_Int32 nPara
= 0; nPara
< nParaCount
; nPara
++)
2312 pOutliner
->SetStyleSheet(nPara
, pStyleSheet
);
2316 SdrGlueEditView::SetStyleSheet(pStyleSheet
, bDontRemoveHardAttr
);
2319 void SdrObjEditView::AddWindowToPaintView(OutputDevice
* pNewWin
, vcl::Window
* pWindow
)
2321 SdrGlueEditView::AddWindowToPaintView(pNewWin
, pWindow
);
2323 if (mxTextEditObj
.is() && !bTextEditOnlyOneView
&& pNewWin
->GetOutDevType() == OUTDEV_WINDOW
)
2325 OutlinerView
* pOutlView
= ImpMakeOutlinerView(static_cast<vcl::Window
*>(pNewWin
), nullptr);
2326 pTextEditOutliner
->InsertView(pOutlView
);
2330 void SdrObjEditView::DeleteWindowFromPaintView(OutputDevice
* pOldWin
)
2332 SdrGlueEditView::DeleteWindowFromPaintView(pOldWin
);
2334 if (mxTextEditObj
.is() && !bTextEditOnlyOneView
&& pOldWin
->GetOutDevType() == OUTDEV_WINDOW
)
2336 for (size_t i
= pTextEditOutliner
->GetViewCount(); i
> 0;)
2339 OutlinerView
* pOLV
= pTextEditOutliner
->GetView(i
);
2340 if (pOLV
&& pOLV
->GetWindow() == static_cast<vcl::Window
*>(pOldWin
))
2342 pTextEditOutliner
->RemoveView(i
);
2347 lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), pOldWin
);
2350 bool SdrObjEditView::IsTextEditInSelectionMode() const
2352 return pTextEditOutliner
!= nullptr && pTextEditOutliner
->IsInSelectionMode();
2357 void SdrObjEditView::BegMacroObj(const Point
& rPnt
, short nTol
, SdrObject
* pObj
, SdrPageView
* pPV
,
2361 if (pObj
!= nullptr && pPV
!= nullptr && pWin
!= nullptr && pObj
->HasMacro())
2363 nTol
= ImpGetHitTolLogic(nTol
, nullptr);
2368 nMacroTol
= sal_uInt16(nTol
);
2369 aMacroDownPos
= rPnt
;
2374 void SdrObjEditView::ImpMacroUp(const Point
& rUpPos
)
2376 if (pMacroObj
!= nullptr && bMacroDown
)
2378 SdrObjMacroHitRec aHitRec
;
2379 aHitRec
.aPos
= rUpPos
;
2380 aHitRec
.nTol
= nMacroTol
;
2381 aHitRec
.pVisiLayer
= &pMacroPV
->GetVisibleLayers();
2382 aHitRec
.pPageView
= pMacroPV
;
2383 pMacroObj
->PaintMacro(*pMacroWin
, tools::Rectangle(), aHitRec
);
2388 void SdrObjEditView::ImpMacroDown(const Point
& rDownPos
)
2390 if (pMacroObj
!= nullptr && !bMacroDown
)
2392 SdrObjMacroHitRec aHitRec
;
2393 aHitRec
.aPos
= rDownPos
;
2394 aHitRec
.nTol
= nMacroTol
;
2395 aHitRec
.pVisiLayer
= &pMacroPV
->GetVisibleLayers();
2396 aHitRec
.pPageView
= pMacroPV
;
2397 pMacroObj
->PaintMacro(*pMacroWin
, tools::Rectangle(), aHitRec
);
2402 void SdrObjEditView::MovMacroObj(const Point
& rPnt
)
2404 if (pMacroObj
== nullptr)
2407 SdrObjMacroHitRec aHitRec
;
2408 aHitRec
.aPos
= rPnt
;
2409 aHitRec
.nTol
= nMacroTol
;
2410 aHitRec
.pVisiLayer
= &pMacroPV
->GetVisibleLayers();
2411 aHitRec
.pPageView
= pMacroPV
;
2412 bool bDown
= pMacroObj
->IsMacroHit(aHitRec
);
2419 void SdrObjEditView::BrkMacroObj()
2421 if (pMacroObj
!= nullptr)
2423 ImpMacroUp(aMacroDownPos
);
2424 pMacroObj
= nullptr;
2426 pMacroWin
= nullptr;
2430 bool SdrObjEditView::EndMacroObj()
2432 if (pMacroObj
!= nullptr && bMacroDown
)
2434 ImpMacroUp(aMacroDownPos
);
2435 SdrObjMacroHitRec aHitRec
;
2436 aHitRec
.aPos
= aMacroDownPos
;
2437 aHitRec
.nTol
= nMacroTol
;
2438 aHitRec
.pVisiLayer
= &pMacroPV
->GetVisibleLayers();
2439 aHitRec
.pPageView
= pMacroPV
;
2440 bool bRet
= pMacroObj
->DoMacro(aHitRec
);
2441 pMacroObj
= nullptr;
2443 pMacroWin
= nullptr;
2453 /** fills the given any with a XTextCursor for the current text selection.
2454 Leaves the any untouched if there currently is no text selected */
2455 void SdrObjEditView::getTextSelection(css::uno::Any
& rSelection
)
2460 OutlinerView
* pOutlinerView
= GetTextEditOutlinerView();
2461 if (!(pOutlinerView
&& pOutlinerView
->HasSelection()))
2464 SdrObject
* pObj
= GetTextEditObject();
2469 css::uno::Reference
<css::text::XText
> xText(pObj
->getUnoShape(), css::uno::UNO_QUERY
);
2472 SvxUnoTextBase
* pRange
= comphelper::getUnoTunnelImplementation
<SvxUnoTextBase
>(xText
);
2475 rSelection
<<= pRange
->createTextCursorBySelection(pOutlinerView
->GetSelection());
2480 /* check if we have a single selection and that single object likes
2481 to handle the mouse and keyboard events itself
2483 TODO: the selection controller should be queried from the
2484 object specific view contact. Currently this method only
2487 void SdrObjEditView::MarkListHasChanged()
2489 SdrGlueEditView::MarkListHasChanged();
2491 if (mxSelectionController
.is())
2493 mxLastSelectionController
= mxSelectionController
;
2494 mxSelectionController
->onSelectionHasChanged();
2497 mxSelectionController
.clear();
2499 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
2500 if (rMarkList
.GetMarkCount() != 1)
2503 const SdrObject
* pObj(rMarkList
.GetMark(0)->GetMarkedSdrObj());
2504 SdrView
* pView(dynamic_cast<SdrView
*>(this));
2507 if (pObj
&& pView
&& (pObj
->GetObjInventor() == SdrInventor::Default
)
2508 && (pObj
->GetObjIdentifier() == OBJ_TABLE
))
2510 mxSelectionController
= sdr::table::CreateTableController(
2511 *pView
, static_cast<const sdr::table::SdrTableObj
&>(*pObj
), mxLastSelectionController
);
2513 if (mxSelectionController
.is())
2515 mxLastSelectionController
.clear();
2516 mxSelectionController
->onSelectionHasChanged();
2521 IMPL_LINK(SdrObjEditView
, EndPasteOrDropHdl
, PasteOrDropInfos
*, pInfo
, void)
2523 OnEndPasteOrDrop(pInfo
);
2526 IMPL_LINK(SdrObjEditView
, BeginPasteOrDropHdl
, PasteOrDropInfos
*, pInfo
, void)
2528 OnBeginPasteOrDrop(pInfo
);
2531 void SdrObjEditView::OnBeginPasteOrDrop(PasteOrDropInfos
*)
2533 // applications can derive from these virtual methods to do something before a drop or paste operation
2536 void SdrObjEditView::OnEndPasteOrDrop(PasteOrDropInfos
*)
2538 // applications can derive from these virtual methods to do something before a drop or paste operation
2541 sal_uInt16
SdrObjEditView::GetSelectionLevel() const
2543 sal_uInt16 nLevel
= 0xFFFF;
2546 DBG_ASSERT(pTextEditOutlinerView
!= nullptr,
2547 "SdrObjEditView::GetAttributes(): pTextEditOutlinerView=NULL");
2548 DBG_ASSERT(pTextEditOutliner
!= nullptr,
2549 "SdrObjEditView::GetAttributes(): pTextEditOutliner=NULL");
2550 if (pTextEditOutlinerView
)
2552 //start and end position
2553 ESelection aSelect
= pTextEditOutlinerView
->GetSelection();
2554 sal_uInt16 nStartPara
= ::std::min(aSelect
.nStartPara
, aSelect
.nEndPara
);
2555 sal_uInt16 nEndPara
= ::std::max(aSelect
.nStartPara
, aSelect
.nEndPara
);
2556 //get level from each paragraph
2558 for (sal_uInt16 nPara
= nStartPara
; nPara
<= nEndPara
; nPara
++)
2560 sal_uInt16 nParaDepth
2561 = 1 << static_cast<sal_uInt16
>(pTextEditOutliner
->GetDepth(nPara
));
2562 if (!(nLevel
& nParaDepth
))
2563 nLevel
+= nParaDepth
;
2565 //reduce one level for Outliner Object
2566 //if( nLevel > 0 && GetTextEditObject()->GetObjIdentifier() == OBJ_OUTLINETEXT )
2567 // nLevel = nLevel >> 1;
2568 //no bullet paragraph selected
2576 bool SdrObjEditView::SupportsFormatPaintbrush(SdrInventor nObjectInventor
,
2577 sal_uInt16 nObjectIdentifier
)
2579 if (nObjectInventor
!= SdrInventor::Default
&& nObjectInventor
!= SdrInventor::E3d
)
2581 switch (nObjectIdentifier
)
2602 case OBJ_OUTLINETEXT
:
2618 case OBJ_CUSTOMSHAPE
:
2625 static const sal_uInt16
* GetFormatRangeImpl(bool bTextOnly
)
2627 static const sal_uInt16 gRanges
[] = { SDRATTR_SHADOW_FIRST
,
2628 SDRATTR_SHADOW_LAST
,
2631 SDRATTR_TABLE_FIRST
,
2638 EE_PARA_END
, // text-only from here on
2642 SDRATTR_MISC_LAST
, // table cell formats
2645 return &gRanges
[bTextOnly
? 10 : 0];
2648 void SdrObjEditView::TakeFormatPaintBrush(std::shared_ptr
<SfxItemSet
>& rFormatSet
)
2650 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
2651 if (rMarkList
.GetMarkCount() <= 0)
2654 OutlinerView
* pOLV
= GetTextEditOutlinerView();
2656 rFormatSet
= std::make_shared
<SfxItemSet
>(GetModel()->GetItemPool(),
2657 GetFormatRangeImpl(pOLV
!= nullptr));
2660 rFormatSet
->Put(pOLV
->GetAttribs());
2664 const bool bOnlyHardAttr
= false;
2665 rFormatSet
->Put(GetAttrFromMarked(bOnlyHardAttr
));
2668 // check for cloning from table cell, in which case we need to copy cell-specific formatting attributes
2669 const SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
2670 if (pObj
&& (pObj
->GetObjInventor() == SdrInventor::Default
)
2671 && (pObj
->GetObjIdentifier() == OBJ_TABLE
))
2673 auto pTable
= static_cast<const sdr::table::SdrTableObj
*>(pObj
);
2674 if (mxSelectionController
.is() && pTable
->getActiveCell().is())
2676 mxSelectionController
->GetAttributes(*rFormatSet
, false);
2681 static SfxItemSet
CreatePaintSet(const sal_uInt16
* pRanges
, SfxItemPool
& rPool
,
2682 const SfxItemSet
& rSourceSet
, const SfxItemSet
& rTargetSet
,
2683 bool bNoCharacterFormats
, bool bNoParagraphFormats
)
2685 SfxItemSet
aPaintSet(rPool
, pRanges
);
2689 sal_uInt16 nWhich
= *pRanges
++;
2690 const sal_uInt16 nLastWhich
= *pRanges
++;
2692 if (bNoCharacterFormats
&& (nWhich
== EE_CHAR_START
))
2695 if (bNoParagraphFormats
&& (nWhich
== EE_PARA_START
))
2698 for (; nWhich
< nLastWhich
; nWhich
++)
2700 const SfxPoolItem
* pSourceItem
= rSourceSet
.GetItem(nWhich
);
2701 const SfxPoolItem
* pTargetItem
= rTargetSet
.GetItem(nWhich
);
2703 if ((pSourceItem
&& !pTargetItem
)
2704 || (pSourceItem
&& pTargetItem
&& *pSourceItem
!= *pTargetItem
))
2706 aPaintSet
.Put(*pSourceItem
);
2713 void SdrObjEditView::ApplyFormatPaintBrushToText(SfxItemSet
const& rFormatSet
, SdrTextObj
& rTextObj
,
2714 SdrText
* pText
, bool bNoCharacterFormats
,
2715 bool bNoParagraphFormats
)
2717 OutlinerParaObject
* pParaObj
= pText
? pText
->GetOutlinerParaObject() : nullptr;
2721 SdrOutliner
& rOutliner
= rTextObj
.ImpGetDrawOutliner();
2722 rOutliner
.SetText(*pParaObj
);
2724 sal_Int32
nParaCount(rOutliner
.GetParagraphCount());
2729 for (sal_Int32 nPara
= 0; nPara
< nParaCount
; nPara
++)
2731 if (!bNoCharacterFormats
)
2732 rOutliner
.RemoveCharAttribs(nPara
);
2734 SfxItemSet
aSet(rOutliner
.GetParaAttribs(nPara
));
2735 aSet
.Put(CreatePaintSet(GetFormatRangeImpl(true), *aSet
.GetPool(), rFormatSet
, aSet
,
2736 bNoCharacterFormats
, bNoParagraphFormats
));
2737 rOutliner
.SetParaAttribs(nPara
, aSet
);
2740 std::unique_ptr
<OutlinerParaObject
> pTemp
= rOutliner
.CreateParaObject(0, nParaCount
);
2743 rTextObj
.NbcSetOutlinerParaObjectForText(std::move(pTemp
), pText
);
2746 void SdrObjEditView::ApplyFormatPaintBrush(SfxItemSet
& rFormatSet
, bool bNoCharacterFormats
,
2747 bool bNoParagraphFormats
)
2749 if (mxSelectionController
.is()
2750 && mxSelectionController
->ApplyFormatPaintBrush(rFormatSet
, bNoCharacterFormats
,
2751 bNoParagraphFormats
))
2756 OutlinerView
* pOLV
= GetTextEditOutlinerView();
2757 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
2760 SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
2761 const SfxItemSet
& rShapeSet
= pObj
->GetMergedItemSet();
2763 // if not in text edit mode (aka the user selected text or clicked on a word)
2764 // apply formatting attributes to selected shape
2765 // All formatting items (see ranges above) that are unequal in selected shape and
2766 // the format paintbrush are hard set on the selected shape.
2768 const sal_uInt16
* pRanges
= rFormatSet
.GetRanges();
2769 bool bTextOnly
= true;
2773 if ((*pRanges
!= EE_PARA_START
) && (*pRanges
!= EE_CHAR_START
))
2783 SfxItemSet
aPaintSet(CreatePaintSet(GetFormatRangeImpl(false), *rShapeSet
.GetPool(),
2784 rFormatSet
, rShapeSet
, bNoCharacterFormats
,
2785 bNoParagraphFormats
));
2786 SetAttrToMarked(aPaintSet
, false /*bReplaceAll*/);
2789 // now apply character and paragraph formatting to text, if the shape has any
2790 SdrTextObj
* pTextObj
= dynamic_cast<SdrTextObj
*>(pObj
);
2793 sal_Int32 nText
= pTextObj
->getTextCount();
2795 while (--nText
>= 0)
2797 SdrText
* pText
= pTextObj
->getText(nText
);
2798 ApplyFormatPaintBrushToText(rFormatSet
, *pTextObj
, pText
, bNoCharacterFormats
,
2799 bNoParagraphFormats
);
2805 ::Outliner
* pOutliner
= pOLV
->GetOutliner();
2808 const EditEngine
& rEditEngine
= pOutliner
->GetEditEngine();
2810 ESelection
aSel(pOLV
->GetSelection());
2811 if (!aSel
.HasRange())
2812 pOLV
->SetSelection(rEditEngine
.GetWord(aSel
, css::i18n::WordType::DICTIONARY_WORD
));
2814 const bool bRemoveParaAttribs
= !bNoParagraphFormats
;
2815 pOLV
->RemoveAttribsKeepLanguages(bRemoveParaAttribs
);
2816 SfxItemSet
aSet(pOLV
->GetAttribs());
2817 SfxItemSet
aPaintSet(CreatePaintSet(GetFormatRangeImpl(true), *aSet
.GetPool(),
2818 rFormatSet
, aSet
, bNoCharacterFormats
,
2819 bNoParagraphFormats
));
2820 pOLV
->SetAttribs(aPaintSet
);
2824 // check for cloning to table cell, in which case we need to copy cell-specific formatting attributes
2825 SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
2826 if (pObj
&& (pObj
->GetObjInventor() == SdrInventor::Default
)
2827 && (pObj
->GetObjIdentifier() == OBJ_TABLE
))
2829 auto pTable
= static_cast<sdr::table::SdrTableObj
*>(pObj
);
2830 if (pTable
->getActiveCell().is() && mxSelectionController
.is())
2832 mxSelectionController
->SetAttributes(rFormatSet
, false);
2837 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */