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/overflowingtxt.hxx>
28 #include <editeng/editstat.hxx>
29 #include <svl/itemset.hxx>
30 #include <editeng/eeitem.hxx>
31 #include <svx/sdtfchim.hxx>
32 #include <svx/textchain.hxx>
35 bool SdrTextObj::HasTextEdit() const
37 // linked text objects may be changed (no automatic reload)
41 bool SdrTextObj::BegTextEdit(SdrOutliner
& rOutl
)
43 if (pEdtOutl
!=nullptr) return false; // Textedit might already run in another View!
48 OutlinerMode nOutlinerMode
= OutlinerMode::OutlineObject
;
50 nOutlinerMode
= OutlinerMode::TextObject
;
51 rOutl
.Init( nOutlinerMode
);
52 rOutl
.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
54 bool bFitToSize(IsFitToSize());
55 bool bContourFrame
=IsContourTextFrame();
56 ImpSetTextEditParams();
59 EEControlBits nStat
=rOutl
.GetControlWord();
60 nStat
|=EEControlBits::AUTOPAGESIZE
;
61 if (bFitToSize
|| IsAutoFit())
62 nStat
|=EEControlBits::STRETCHING
;
64 nStat
&=~EEControlBits::STRETCHING
;
65 rOutl
.SetControlWord(nStat
);
68 // disable AUTOPAGESIZE if IsChainable (might be required for overflow check)
69 if ( IsChainable() ) {
70 EEControlBits nStat1
=rOutl
.GetControlWord();
71 nStat1
&=~EEControlBits::AUTOPAGESIZE
;
72 rOutl
.SetControlWord(nStat1
);
76 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
77 if(pOutlinerParaObject
!=nullptr)
79 rOutl
.SetText(*GetOutlinerParaObject());
80 rOutl
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
83 // if necessary, set frame attributes for the first (new) paragraph of the
85 if( !HasTextImpl( &rOutl
) )
87 // Outliner has no text so we must set some
88 // empty text so the outliner initialise itself
89 rOutl
.SetText( "", rOutl
.GetParagraph( 0 ) );
92 rOutl
.SetStyleSheet( 0, GetStyleSheet());
94 // When setting the "hard" attributes for first paragraph, the Parent
95 // pOutlAttr (i. e. the template) has to be removed temporarily. Else,
96 // at SetParaAttribs(), all attributes contained in the parent become
97 // attributed hard to the paragraph.
98 const SfxItemSet
& rSet
= GetObjectItemSet();
99 SfxItemSet
aFilteredSet(*rSet
.GetPool(), svl::Items
<EE_ITEMS_START
, EE_ITEMS_END
>{});
100 aFilteredSet
.Put(rSet
);
101 rOutl
.SetParaAttribs(0, aFilteredSet
);
105 tools::Rectangle aAnchorRect
;
106 tools::Rectangle aTextRect
;
107 TakeTextRect(rOutl
, aTextRect
, false,
109 Fraction
aFitXCorrection(1,1);
110 ImpSetCharStretching(rOutl
,aTextRect
.GetSize(),aAnchorRect
.GetSize(),aFitXCorrection
);
112 else if (IsAutoFit())
114 ImpAutoFitText(rOutl
);
117 if(pOutlinerParaObject
)
119 if(aGeo
.nRotationAngle
|| IsFontwork())
121 // only repaint here, no real objectchange
122 BroadcastObjectChange();
126 rOutl
.UpdateFields();
127 rOutl
.ClearModifyFlag();
132 void SdrTextObj::TakeTextEditArea(Size
* pPaperMin
, Size
* pPaperMax
, tools::Rectangle
* pViewInit
, tools::Rectangle
* pViewMin
) const
134 bool bFitToSize(IsFitToSize());
135 Size aPaperMin
,aPaperMax
;
136 tools::Rectangle aViewInit
;
137 TakeTextAnchorRect(aViewInit
);
138 if (aGeo
.nRotationAngle
!=0) {
139 Point
aCenter(aViewInit
.Center());
140 aCenter
-=aViewInit
.TopLeft();
141 Point
aCenter0(aCenter
);
142 RotatePoint(aCenter
,Point(),aGeo
.nSin
,aGeo
.nCos
);
144 aViewInit
.Move(aCenter
.X(),aCenter
.Y());
146 Size
aAnkSiz(aViewInit
.GetSize());
147 aAnkSiz
.AdjustWidth( -1 ); aAnkSiz
.AdjustHeight( -1 ); // because GetSize() adds 1
148 Size
aMaxSiz(1000000,1000000);
149 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
150 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
151 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
153 // Done earlier since used in else tree below
154 SdrTextHorzAdjust
eHAdj(GetTextHorizontalAdjust());
155 SdrTextVertAdjust
eVAdj(GetTextVerticalAdjust());
159 long nMinWdt
=GetMinTextFrameWidth();
160 long nMinHgt
=GetMinTextFrameHeight();
161 long nMaxWdt
=GetMaxTextFrameWidth();
162 long nMaxHgt
=GetMaxTextFrameHeight();
163 if (nMinWdt
<1) nMinWdt
=1;
164 if (nMinHgt
<1) nMinHgt
=1;
166 if (nMaxWdt
==0 || nMaxWdt
>aMaxSiz
.Width()) nMaxWdt
=aMaxSiz
.Width();
167 if (nMaxHgt
==0 || nMaxHgt
>aMaxSiz
.Height()) nMaxHgt
=aMaxSiz
.Height();
169 if (!IsAutoGrowWidth() )
171 nMinWdt
= aAnkSiz
.Width();
175 if (!IsAutoGrowHeight())
177 nMinHgt
= aAnkSiz
.Height();
181 SdrTextAniKind eAniKind
=GetTextAniKind();
182 SdrTextAniDirection eAniDirection
=GetTextAniDirection();
184 bool bInEditMode
= IsInEditMode();
186 if (!bInEditMode
&& (eAniKind
==SdrTextAniKind::Scroll
|| eAniKind
==SdrTextAniKind::Alternate
|| eAniKind
==SdrTextAniKind::Slide
))
188 // ticker text uses an unlimited paper size
189 if (eAniDirection
==SdrTextAniDirection::Left
|| eAniDirection
==SdrTextAniDirection::Right
) nMaxWdt
=1000000;
190 if (eAniDirection
==SdrTextAniDirection::Up
|| eAniDirection
==SdrTextAniDirection::Down
) nMaxHgt
=1000000;
193 bool bChainedFrame
= IsChainable();
194 // Might be required for overflow check working: do limit height to frame if box is chainable.
195 if (!bChainedFrame
) {
196 // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
197 if(IsVerticalWriting())
207 aPaperMax
.setWidth(nMaxWdt
);
208 aPaperMax
.setHeight(nMaxHgt
);
214 aPaperMin
.setWidth(nMinWdt
);
215 aPaperMin
.setHeight(nMinHgt
);
219 // aPaperMin needs to be set to object's size if full width is activated
220 // for hor or ver writing respectively
221 if((SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !IsVerticalWriting())
222 || (SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& IsVerticalWriting()))
230 if (pViewMin
!=nullptr) {
233 long nXFree
=aAnkSiz
.Width()-aPaperMin
.Width();
234 if (eHAdj
==SDRTEXTHORZADJUST_LEFT
) pViewMin
->AdjustRight( -nXFree
);
235 else if (eHAdj
==SDRTEXTHORZADJUST_RIGHT
) pViewMin
->AdjustLeft(nXFree
);
236 else { pViewMin
->AdjustLeft(nXFree
/2 ); pViewMin
->SetRight(pViewMin
->Left()+aPaperMin
.Width() ); }
238 long nYFree
=aAnkSiz
.Height()-aPaperMin
.Height();
239 if (eVAdj
==SDRTEXTVERTADJUST_TOP
) pViewMin
->AdjustBottom( -nYFree
);
240 else if (eVAdj
==SDRTEXTVERTADJUST_BOTTOM
) pViewMin
->AdjustTop(nYFree
);
241 else { pViewMin
->AdjustTop(nYFree
/2 ); pViewMin
->SetBottom(pViewMin
->Top()+aPaperMin
.Height() ); }
244 // PaperSize should grow automatically in most cases
245 if(IsVerticalWriting())
246 aPaperMin
.setWidth( 0 );
248 aPaperMin
.setHeight( 0 );
250 if(eHAdj
!=SDRTEXTHORZADJUST_BLOCK
|| bFitToSize
) {
251 aPaperMin
.setWidth(0 );
254 // For complete vertical adjustment support, set paper min height to 0, here.
255 if(SDRTEXTVERTADJUST_BLOCK
!= eVAdj
|| bFitToSize
)
257 aPaperMin
.setHeight( 0 );
260 if (pPaperMin
!=nullptr) *pPaperMin
=aPaperMin
;
261 if (pPaperMax
!=nullptr) *pPaperMax
=aPaperMax
;
262 if (pViewInit
!=nullptr) *pViewInit
=aViewInit
;
265 void SdrTextObj::EndTextEdit(SdrOutliner
& rOutl
)
267 if(rOutl
.IsModified())
270 // to make the gray field background vanish again
271 rOutl
.UpdateFields();
273 std::unique_ptr
<OutlinerParaObject
> pNewText
= rOutl
.CreateParaObject( 0, rOutl
.GetParagraphCount() );
275 // need to end edit mode early since SetOutlinerParaObject already
276 // uses GetCurrentBoundRect() which needs to take the text into account
278 mbInEditMode
= false;
280 // We don't want broadcasting if we are merely trying to move to next box (this prevents infinite loops)
281 if (IsChainable() && GetTextChain()->GetSwitchingToNextBox(this)) {
282 GetTextChain()->SetSwitchingToNextBox(this, false);
283 if( getActiveText() )
285 getActiveText()->SetOutlinerParaObject( std::move(pNewText
) );
287 } else { // If we are not doing in-chaining switching just set the ParaObject
288 SetOutlinerParaObject(std::move(pNewText
));
292 /* Chaining-related code */
293 rOutl
.ClearOverflowingParaNum();
297 EEControlBits nStat
= rOutl
.GetControlWord();
298 nStat
&= ~EEControlBits::AUTOPAGESIZE
;
299 rOutl
.SetControlWord(nStat
);
301 mbInEditMode
= false;
304 EEAnchorMode
SdrTextObj::GetOutlinerViewAnchorMode() const
306 SdrTextHorzAdjust eH
=GetTextHorizontalAdjust();
307 SdrTextVertAdjust eV
=GetTextVerticalAdjust();
308 EEAnchorMode eRet
=EEAnchorMode::TopLeft
;
309 if (IsContourTextFrame()) return eRet
;
310 if (eH
==SDRTEXTHORZADJUST_LEFT
) {
311 if (eV
==SDRTEXTVERTADJUST_TOP
) {
312 eRet
=EEAnchorMode::TopLeft
;
313 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
314 eRet
=EEAnchorMode::BottomLeft
;
316 eRet
=EEAnchorMode::VCenterLeft
;
318 } else if (eH
==SDRTEXTHORZADJUST_RIGHT
) {
319 if (eV
==SDRTEXTVERTADJUST_TOP
) {
320 eRet
=EEAnchorMode::TopRight
;
321 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
322 eRet
=EEAnchorMode::BottomRight
;
324 eRet
=EEAnchorMode::VCenterRight
;
327 if (eV
==SDRTEXTVERTADJUST_TOP
) {
328 eRet
=EEAnchorMode::TopHCenter
;
329 } else if (eV
==SDRTEXTVERTADJUST_BOTTOM
) {
330 eRet
=EEAnchorMode::BottomHCenter
;
332 eRet
=EEAnchorMode::VCenterHCenter
;
338 void SdrTextObj::ImpSetTextEditParams() const
340 if (pEdtOutl
==nullptr)
343 bool bUpdBuf
=pEdtOutl
->GetUpdateMode();
344 if (bUpdBuf
) pEdtOutl
->SetUpdateMode(false);
347 tools::Rectangle aEditArea
;
348 TakeTextEditArea(&aPaperMin
,&aPaperMax
,&aEditArea
,nullptr);
349 bool bContourFrame
=IsContourTextFrame();
350 pEdtOutl
->SetMinAutoPaperSize(aPaperMin
);
351 pEdtOutl
->SetMaxAutoPaperSize(aPaperMax
);
352 pEdtOutl
->SetPaperSize(Size());
354 tools::Rectangle aAnchorRect
;
355 TakeTextAnchorRect(aAnchorRect
);
356 ImpSetContourPolygon(*pEdtOutl
,aAnchorRect
, true);
358 if (bUpdBuf
) pEdtOutl
->SetUpdateMode(true);
361 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */