1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdmodel.hxx>
23 #include <svx/svdoutl.hxx>
24 #include <editeng/editdata.hxx>
25 #include <editeng/outliner.hxx>
26 #include <editeng/outlobj.hxx>
27 #include <editeng/editstat.hxx>
28 #include <svl/itemset.hxx>
29 #include <editeng/eeitem.hxx>
30 #include <svx/sdtfchim.hxx>
31 #include <textchain.hxx>
34 bool SdrTextObj::HasTextEdit() const
36 // linked text objects may be changed (no automatic reload)
40 bool SdrTextObj::BegTextEdit(SdrOutliner
& rOutl
)
42 if (mpEditingOutliner
!=nullptr) return false; // Textedit might already run in another View!
43 mpEditingOutliner
=&rOutl
;
47 OutlinerMode nOutlinerMode
= OutlinerMode::OutlineObject
;
49 nOutlinerMode
= OutlinerMode::TextObject
;
50 rOutl
.Init( nOutlinerMode
);
51 rOutl
.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
53 bool bFitToSize(IsFitToSize());
54 bool bContourFrame
=IsContourTextFrame();
55 ImpSetTextEditParams();
58 EEControlBits nStat
=rOutl
.GetControlWord();
59 nStat
|=EEControlBits::AUTOPAGESIZE
;
60 if (bFitToSize
|| IsAutoFit())
61 nStat
|=EEControlBits::STRETCHING
;
63 nStat
&=~EEControlBits::STRETCHING
;
64 rOutl
.SetControlWord(nStat
);
67 // disable AUTOPAGESIZE if IsChainable (might be required for overflow check)
68 if ( IsChainable() ) {
69 EEControlBits nStat1
=rOutl
.GetControlWord();
70 nStat1
&=~EEControlBits::AUTOPAGESIZE
;
71 rOutl
.SetControlWord(nStat1
);
75 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
76 if(pOutlinerParaObject
!=nullptr)
78 rOutl
.SetText(*GetOutlinerParaObject());
79 rOutl
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
82 // if necessary, set frame attributes for the first (new) paragraph of the
84 if( !HasTextImpl( &rOutl
) )
86 // Outliner has no text so we must set some
87 // empty text so the outliner initialise itself
88 rOutl
.SetText( "", rOutl
.GetParagraph( 0 ) );
91 rOutl
.SetStyleSheet( 0, GetStyleSheet());
93 // When setting the "hard" attributes for first paragraph, the Parent
94 // pOutlAttr (i. e. the template) has to be removed temporarily. Else,
95 // at SetParaAttribs(), all attributes contained in the parent become
96 // attributed hard to the paragraph.
97 const SfxItemSet
& rSet
= GetObjectItemSet();
98 SfxItemSetFixed
<EE_ITEMS_START
, EE_ITEMS_END
> aFilteredSet(*rSet
.GetPool());
99 aFilteredSet
.Put(rSet
);
100 rOutl
.SetParaAttribs(0, aFilteredSet
);
104 tools::Rectangle aAnchorRect
;
105 tools::Rectangle aTextRect
;
106 TakeTextRect(rOutl
, aTextRect
, false,
108 Fraction
aFitXCorrection(1,1);
109 ImpSetCharStretching(rOutl
,aTextRect
.GetSize(),aAnchorRect
.GetSize(),aFitXCorrection
);
111 else if (IsAutoFit())
113 ImpAutoFitText(rOutl
);
116 if(pOutlinerParaObject
)
118 if (maGeo
.nRotationAngle
|| IsFontwork())
120 // only repaint here, no real objectchange
121 BroadcastObjectChange();
125 rOutl
.UpdateFields();
126 rOutl
.ClearModifyFlag();
131 void SdrTextObj::TakeTextEditArea(Size
* pPaperMin
, Size
* pPaperMax
, tools::Rectangle
* pViewInit
, tools::Rectangle
* pViewMin
) const
133 bool bFitToSize(IsFitToSize());
134 Size aPaperMin
,aPaperMax
;
135 tools::Rectangle aViewInit
;
136 TakeTextAnchorRect(aViewInit
);
137 if (maGeo
.nRotationAngle
) {
138 Point
aCenter(aViewInit
.Center());
139 aCenter
-=aViewInit
.TopLeft();
140 Point
aCenter0(aCenter
);
141 RotatePoint(aCenter
,Point(),maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
143 aViewInit
.Move(aCenter
.X(),aCenter
.Y());
145 Size
aAnkSiz(aViewInit
.GetSize());
146 aAnkSiz
.AdjustWidth( -1 ); aAnkSiz
.AdjustHeight( -1 ); // because GetSize() adds 1
147 Size
aMaxSiz(1000000,1000000);
148 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
149 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
150 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
152 // Done earlier since used in else tree below
153 SdrTextHorzAdjust
eHAdj(GetTextHorizontalAdjust());
154 SdrTextVertAdjust
eVAdj(GetTextVerticalAdjust());
158 tools::Long nMinWdt
=GetMinTextFrameWidth();
159 tools::Long nMinHgt
=GetMinTextFrameHeight();
160 tools::Long nMaxWdt
=GetMaxTextFrameWidth();
161 tools::Long nMaxHgt
=GetMaxTextFrameHeight();
162 if (nMinWdt
<1) nMinWdt
=1;
163 if (nMinHgt
<1) nMinHgt
=1;
165 if (nMaxWdt
==0 || nMaxWdt
>aMaxSiz
.Width()) nMaxWdt
=aMaxSiz
.Width();
166 if (nMaxHgt
==0 || nMaxHgt
>aMaxSiz
.Height()) nMaxHgt
=aMaxSiz
.Height();
168 if (!IsAutoGrowWidth() )
170 nMinWdt
= aAnkSiz
.Width();
174 if (!IsAutoGrowHeight())
176 nMinHgt
= aAnkSiz
.Height();
180 SdrTextAniKind eAniKind
=GetTextAniKind();
181 SdrTextAniDirection eAniDirection
=GetTextAniDirection();
183 bool bInEditMode
= IsInEditMode();
185 if (!bInEditMode
&& (eAniKind
==SdrTextAniKind::Scroll
|| eAniKind
==SdrTextAniKind::Alternate
|| eAniKind
==SdrTextAniKind::Slide
))
187 // ticker text uses an unlimited paper size
188 if (eAniDirection
==SdrTextAniDirection::Left
|| eAniDirection
==SdrTextAniDirection::Right
) nMaxWdt
=1000000;
189 if (eAniDirection
==SdrTextAniDirection::Up
|| eAniDirection
==SdrTextAniDirection::Down
) nMaxHgt
=1000000;
192 bool bChainedFrame
= IsChainable();
193 // Might be required for overflow check working: do limit height to frame if box is chainable.
194 if (!bChainedFrame
) {
195 // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
196 if(IsVerticalWriting())
206 aPaperMax
.setWidth(nMaxWdt
);
207 aPaperMax
.setHeight(nMaxHgt
);
213 aPaperMin
.setWidth(nMinWdt
);
214 aPaperMin
.setHeight(nMinHgt
);
218 // aPaperMin needs to be set to object's size if full width is activated
219 // for hor or ver writing respectively
220 if((SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !IsVerticalWriting())
221 || (SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& IsVerticalWriting()))
229 if (pViewMin
!=nullptr) {
232 tools::Long nXFree
=aAnkSiz
.Width()-aPaperMin
.Width();
233 if (eHAdj
==SDRTEXTHORZADJUST_LEFT
) pViewMin
->AdjustRight( -nXFree
);
234 else if (eHAdj
==SDRTEXTHORZADJUST_RIGHT
) pViewMin
->AdjustLeft(nXFree
);
235 else { pViewMin
->AdjustLeft(nXFree
/2 ); pViewMin
->SetRight(pViewMin
->Left()+aPaperMin
.Width() ); }
237 tools::Long nYFree
=aAnkSiz
.Height()-aPaperMin
.Height();
238 if (eVAdj
==SDRTEXTVERTADJUST_TOP
) pViewMin
->AdjustBottom( -nYFree
);
239 else if (eVAdj
==SDRTEXTVERTADJUST_BOTTOM
) pViewMin
->AdjustTop(nYFree
);
240 else { pViewMin
->AdjustTop(nYFree
/2 ); pViewMin
->SetBottom(pViewMin
->Top()+aPaperMin
.Height() ); }
243 // PaperSize should grow automatically in most cases
244 if(IsVerticalWriting())
245 aPaperMin
.setWidth( 0 );
247 aPaperMin
.setHeight( 0 );
249 if(eHAdj
!=SDRTEXTHORZADJUST_BLOCK
|| bFitToSize
) {
250 aPaperMin
.setWidth(0 );
253 // For complete vertical adjustment support, set paper min height to 0, here.
254 if(SDRTEXTVERTADJUST_BLOCK
!= eVAdj
|| bFitToSize
)
256 aPaperMin
.setHeight( 0 );
259 if (pPaperMin
!=nullptr) *pPaperMin
=aPaperMin
;
260 if (pPaperMax
!=nullptr) *pPaperMax
=aPaperMax
;
261 if (pViewInit
!=nullptr) *pViewInit
=aViewInit
;
264 void SdrTextObj::EndTextEdit(SdrOutliner
& rOutl
)
266 if(rOutl
.IsModified())
269 // to make the gray field background vanish again
270 rOutl
.UpdateFields();
272 std::optional
<OutlinerParaObject
> pNewText
= rOutl
.CreateParaObject( 0, rOutl
.GetParagraphCount() );
274 // need to end edit mode early since SetOutlinerParaObject already
275 // uses GetCurrentBoundRect() which needs to take the text into account
277 mbInEditMode
= false;
279 // We don't want broadcasting if we are merely trying to move to next box (this prevents infinite loops)
280 if (IsChainable() && GetTextChain()->GetSwitchingToNextBox(this)) {
281 GetTextChain()->SetSwitchingToNextBox(this, false);
282 if( getActiveText() )
284 getActiveText()->SetOutlinerParaObject( std::move(pNewText
) );
286 } else { // If we are not doing in-chaining switching just set the ParaObject
287 SetOutlinerParaObject(std::move(pNewText
));
291 /* Chaining-related code */
292 rOutl
.ClearOverflowingParaNum();
294 mpEditingOutliner
= nullptr;
296 EEControlBits nStat
= rOutl
.GetControlWord();
297 nStat
&= ~EEControlBits::AUTOPAGESIZE
;
298 rOutl
.SetControlWord(nStat
);
300 mbInEditMode
= false;
303 EEAnchorMode
SdrTextObj::GetOutlinerViewAnchorMode() const
305 SdrTextHorzAdjust eH
=GetTextHorizontalAdjust();
306 SdrTextVertAdjust eV
=GetTextVerticalAdjust();
307 EEAnchorMode eRet
=EEAnchorMode::TopLeft
;
308 if (IsContourTextFrame()) return eRet
;
309 if (eH
==SDRTEXTHORZADJUST_LEFT
) {
310 if (eV
==SDRTEXTVERTADJUST_TOP
) {
311 eRet
=EEAnchorMode::TopLeft
;
312 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
313 eRet
=EEAnchorMode::BottomLeft
;
315 eRet
=EEAnchorMode::VCenterLeft
;
317 } else if (eH
==SDRTEXTHORZADJUST_RIGHT
) {
318 if (eV
==SDRTEXTVERTADJUST_TOP
) {
319 eRet
=EEAnchorMode::TopRight
;
320 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
321 eRet
=EEAnchorMode::BottomRight
;
323 eRet
=EEAnchorMode::VCenterRight
;
326 if (eV
==SDRTEXTVERTADJUST_TOP
) {
327 eRet
=EEAnchorMode::TopHCenter
;
328 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
329 eRet
=EEAnchorMode::BottomHCenter
;
331 eRet
=EEAnchorMode::VCenterHCenter
;
337 void SdrTextObj::ImpSetTextEditParams() const
339 if (mpEditingOutliner
==nullptr)
342 bool bUpdBuf
=mpEditingOutliner
->SetUpdateLayout(false);
345 tools::Rectangle aEditArea
;
346 TakeTextEditArea(&aPaperMin
,&aPaperMax
,&aEditArea
,nullptr);
347 bool bContourFrame
=IsContourTextFrame();
348 mpEditingOutliner
->SetMinAutoPaperSize(aPaperMin
);
349 mpEditingOutliner
->SetMaxAutoPaperSize(aPaperMax
);
350 mpEditingOutliner
->SetPaperSize(Size());
351 mpEditingOutliner
->SetTextColumns(GetTextColumnsNumber(), GetTextColumnsSpacing());
353 tools::Rectangle aAnchorRect
;
354 TakeTextAnchorRect(aAnchorRect
);
355 ImpSetContourPolygon(*mpEditingOutliner
,aAnchorRect
, true);
357 if (bUpdBuf
) mpEditingOutliner
->SetUpdateLayout(true);
360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */