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 <comphelper/string.hxx>
21 #include <o3tl/sorted_vector.hxx>
22 #include <o3tl/string_view.hxx>
23 #include <svl/style.hxx>
24 #include <svx/svdotext.hxx>
25 #include <svx/svdmodel.hxx>
26 #include <svx/svdoutl.hxx>
27 #include <svx/svdorect.hxx>
28 #include <svx/svdocapt.hxx>
29 #include <editeng/editdata.hxx>
30 #include <svx/sdtfchim.hxx>
33 #include <editeng/outlobj.hxx>
34 #include <editeng/outliner.hxx>
35 #include <editeng/editobj.hxx>
38 // The style family which is appended to the style names is padded to this many characters.
39 const short PADDING_LENGTH_FOR_STYLE_FAMILY
= 5;
40 // this character will be used to pad the style families when they are appended to the style names
41 const char PADDING_CHARACTER_FOR_STYLE_FAMILY
= ' ';
44 bool SdrTextObj::AdjustTextFrameWidthAndHeight( tools::Rectangle
& rR
, bool bHgt
, bool bWdt
) const
47 // Not a text frame. Bail out.
54 bool bFitToSize
= IsFitToSize();
58 bool bWdtGrow
= bWdt
&& IsAutoGrowWidth();
59 bool bHgtGrow
= bHgt
&& IsAutoGrowHeight();
60 if (!bWdtGrow
&& !bHgtGrow
)
61 // Not supposed to auto-adjust width or height.
64 SdrTextAniKind eAniKind
= GetTextAniKind();
65 SdrTextAniDirection eAniDir
= GetTextAniDirection();
67 bool bScroll
= eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
;
68 bool bHScroll
= bScroll
&& (eAniDir
== SdrTextAniDirection::Left
|| eAniDir
== SdrTextAniDirection::Right
);
69 bool bVScroll
= bScroll
&& (eAniDir
== SdrTextAniDirection::Up
|| eAniDir
== SdrTextAniDirection::Down
);
71 tools::Rectangle aOldRect
= rR
;
72 tools::Long nHgt
= 0, nMinHgt
= 0, nMaxHgt
= 0;
73 tools::Long nWdt
= 0, nMinWdt
= 0, nMaxWdt
= 0;
75 Size aNewSize
= rR
.GetSize();
76 aNewSize
.AdjustWidth( -1 ); aNewSize
.AdjustHeight( -1 );
78 Size
aMaxSiz(100000, 100000);
79 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
82 aMaxSiz
.setWidth( aTmpSiz
.Width() );
84 aMaxSiz
.setHeight( aTmpSiz
.Height() );
88 nMinWdt
= GetMinTextFrameWidth();
89 nMaxWdt
= GetMaxTextFrameWidth();
90 if (nMaxWdt
== 0 || nMaxWdt
> aMaxSiz
.Width())
91 nMaxWdt
= aMaxSiz
.Width();
95 aNewSize
.setWidth( nMaxWdt
);
100 nMinHgt
= GetMinTextFrameHeight();
101 nMaxHgt
= GetMaxTextFrameHeight();
102 if (nMaxHgt
== 0 || nMaxHgt
> aMaxSiz
.Height())
103 nMaxHgt
= aMaxSiz
.Height();
107 aNewSize
.setHeight( nMaxHgt
);
110 tools::Long nHDist
= GetTextLeftDistance() + GetTextRightDistance();
111 tools::Long nVDist
= GetTextUpperDistance() + GetTextLowerDistance();
112 aNewSize
.AdjustWidth( -nHDist
);
113 aNewSize
.AdjustHeight( -nVDist
);
115 if (aNewSize
.Width() < 2)
116 aNewSize
.setWidth( 2 );
117 if (aNewSize
.Height() < 2)
118 aNewSize
.setHeight( 2 );
123 aNewSize
.setWidth( 0x0FFFFFFF ); // don't break ticker text
125 aNewSize
.setHeight( 0x0FFFFFFF );
128 if (mpEditingOutliner
)
130 mpEditingOutliner
->SetMaxAutoPaperSize(aNewSize
);
133 Size
aSiz2(mpEditingOutliner
->CalcTextSize());
134 nWdt
= aSiz2
.Width() + 1; // a little tolerance
136 nHgt
= aSiz2
.Height() + 1; // a little tolerance
140 nHgt
= mpEditingOutliner
->GetTextHeight() + 1; // a little tolerance
145 Outliner
& rOutliner
= ImpGetDrawOutliner();
146 rOutliner
.SetPaperSize(aNewSize
);
147 rOutliner
.SetUpdateLayout(true);
148 // TODO: add the optimization with bPortionInfoChecked etc. here
149 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
150 if (pOutlinerParaObject
)
152 rOutliner
.SetText(*pOutlinerParaObject
);
153 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
158 Size
aSiz2(rOutliner
.CalcTextSize());
159 nWdt
= aSiz2
.Width() + 1; // a little tolerance
161 nHgt
= aSiz2
.Height() + 1; // a little tolerance
165 nHgt
= rOutliner
.GetTextHeight() + 1; // a little tolerance
176 nWdt
= 1; // nHDist may be negative
183 nHgt
= 1; // nVDist may be negative
184 tools::Long nWdtGrow
= nWdt
- (rR
.Right() - rR
.Left());
185 tools::Long nHgtGrow
= nHgt
- (rR
.Bottom() - rR
.Top());
192 if (!bWdtGrow
&& !bHgtGrow
)
197 SdrTextHorzAdjust eHAdj
= GetTextHorizontalAdjust();
199 if (eHAdj
== SDRTEXTHORZADJUST_LEFT
)
200 rR
.AdjustRight(nWdtGrow
);
201 else if (eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
202 rR
.AdjustLeft( -nWdtGrow
);
205 tools::Long nWdtGrow2
= nWdtGrow
/ 2;
206 rR
.AdjustLeft( -nWdtGrow2
);
207 rR
.SetRight( rR
.Left() + nWdt
);
213 SdrTextVertAdjust eVAdj
= GetTextVerticalAdjust();
215 if (eVAdj
== SDRTEXTVERTADJUST_TOP
)
216 rR
.AdjustBottom(nHgtGrow
);
217 else if (eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
218 rR
.AdjustTop( -nHgtGrow
);
221 tools::Long nHgtGrow2
= nHgtGrow
/ 2;
222 rR
.AdjustTop( -nHgtGrow2
);
223 rR
.SetBottom( rR
.Top() + nHgt
);
227 if (maGeo
.m_nRotationAngle
)
229 // Object is rotated.
230 Point
aD1(rR
.TopLeft());
231 aD1
-= aOldRect
.TopLeft();
233 RotatePoint(aD2
, Point(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
235 rR
.Move(aD2
.X(), aD2
.Y());
241 bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt
, bool bWdt
)
243 tools::Rectangle
aRectangle(getRectangle());
244 bool bRet
= AdjustTextFrameWidthAndHeight(aRectangle
, bHgt
, bWdt
);
245 setRectangle(aRectangle
);
248 SetBoundAndSnapRectsDirty();
249 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) { // this is a hack
250 pRectObj
->SetXPolyDirty();
252 if (auto pCaptionObj
= dynamic_cast<SdrCaptionObj
*>(this)) { // this is a hack
253 pCaptionObj
->ImpRecalcTail();
259 bool SdrTextObj::AdjustTextFrameWidthAndHeight()
261 tools::Rectangle
aNewRect(getRectangle());
262 bool bRet
= AdjustTextFrameWidthAndHeight(aNewRect
);
264 tools::Rectangle aBoundRect0
; if (m_pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
265 setRectangle(aNewRect
);
266 SetBoundAndSnapRectsDirty();
267 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) { // this is a hack
268 pRectObj
->SetXPolyDirty();
270 bool bScPostIt
= false;
271 if (auto pCaptionObj
= dynamic_cast<SdrCaptionObj
*>(this)) { // this is a hack
272 pCaptionObj
->ImpRecalcTail();
273 // tdf#114956, tdf#138549 use GetSpecialTextBoxShadow to recognize
274 // that this SdrCaption is for a ScPostit
275 bScPostIt
= pCaptionObj
->GetSpecialTextBoxShadow();
278 // to not slow down EditView visualization on Overlay (see
279 // TextEditOverlayObject) it is necessary to suppress the
280 // Invalidates for the deep repaint when the size of the
281 // TextFrame changed (AdjustTextFrameWidthAndHeight returned
282 // true). The ObjectChanges are valid, invalidate will be
283 // done on EndTextEdit anyways
284 const bool bSuppressChangeWhenEditOnOverlay(
286 GetTextEditOutliner() &&
287 GetTextEditOutliner()->hasEditViewCallbacks());
289 if (!bSuppressChangeWhenEditOnOverlay
|| bScPostIt
)
292 BroadcastObjectChange();
295 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
300 void SdrTextObj::ImpSetTextStyleSheetListeners()
302 SfxStyleSheetBasePool
* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
303 if (pStylePool
==nullptr)
306 std::vector
<OUString
> aStyleNames
;
307 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
308 if (pOutlinerParaObject
!=nullptr)
310 // First, we collect all stylesheets contained in the ParaObject in
311 // the container aStyles. The Family is always appended to the name
312 // of the stylesheet.
313 const EditTextObject
& rTextObj
=pOutlinerParaObject
->GetTextObject();
315 SfxStyleFamily eStyleFam
;
316 sal_Int32 nParaCnt
=rTextObj
.GetParagraphCount();
319 for(sal_Int32
nParaNum(0); nParaNum
< nParaCnt
; nParaNum
++)
321 rTextObj
.GetStyleSheet(nParaNum
, aStyleName
, eStyleFam
);
323 if (!aStyleName
.isEmpty())
325 AppendFamilyToStyleName(aStyleName
, eStyleFam
);
328 sal_uInt32
nNum(aStyleNames
.size());
330 while(!bFnd
&& nNum
> 0)
332 // we don't want duplicate stylesheets
334 bFnd
= aStyleName
== aStyleNames
[nNum
];
339 aStyleNames
.push_back(aStyleName
);
345 // now convert the strings in the vector from names to StyleSheet*
346 o3tl::sorted_vector
<SfxStyleSheet
*> aStyleSheets
;
347 while (!aStyleNames
.empty()) {
348 OUString aName
= aStyleNames
.back();
349 aStyleNames
.pop_back();
351 SfxStyleFamily eFam
= ReadFamilyFromStyleName(aName
);
352 SfxStyleSheetBase
* pStyleBase
= pStylePool
->Find(aName
,eFam
);
353 SfxStyleSheet
* pStyle
= dynamic_cast<SfxStyleSheet
*>( pStyleBase
);
354 if (pStyle
!=nullptr && pStyle
!=GetStyleSheet()) {
355 aStyleSheets
.insert(pStyle
);
358 // now remove all superfluous stylesheets
359 sal_uInt16 nNum
=GetBroadcasterCount();
362 SfxBroadcaster
* pBroadcast
=GetBroadcasterJOE(nNum
);
363 SfxStyleSheet
* pStyle
=dynamic_cast<SfxStyleSheet
*>( pBroadcast
);
364 if (pStyle
!=nullptr && pStyle
!=GetStyleSheet()) { // special case for stylesheet of the object
365 if (aStyleSheets
.find(pStyle
)==aStyleSheets
.end()) {
366 EndListening(*pStyle
);
370 // and finally, merge all stylesheets that are contained in aStyles with previous broadcasters
371 for(SfxStyleSheet
* pStyle
: aStyleSheets
) {
372 // let StartListening see for itself if there's already a listener registered
373 StartListening(*pStyle
, DuplicateHandling::Prevent
);
377 /** iterates over the paragraphs of a given SdrObject and removes all
378 hard set character attributes with the which ids contained in the
381 void SdrTextObj::RemoveOutlinerCharacterAttribs( const std::vector
<sal_uInt16
>& rCharWhichIds
)
383 sal_Int32 nText
= getTextCount();
385 while( --nText
>= 0 )
387 SdrText
* pText
= getText( nText
);
388 OutlinerParaObject
* pOutlinerParaObject
= pText
? pText
->GetOutlinerParaObject() : nullptr;
390 if(pOutlinerParaObject
)
392 Outliner
* pOutliner
= nullptr;
394 if( mpEditingOutliner
|| (pText
== getActiveText()) )
395 pOutliner
= mpEditingOutliner
;
399 pOutliner
= &ImpGetDrawOutliner();
400 pOutliner
->SetText(*pOutlinerParaObject
);
403 ESelection
aSelAll( 0, 0, EE_PARA_ALL
, EE_TEXTPOS_ALL
);
404 for( const auto& rWhichId
: rCharWhichIds
)
406 pOutliner
->RemoveAttribs( aSelAll
, false, rWhichId
);
409 if(!mpEditingOutliner
|| (pText
!= getActiveText()) )
411 const sal_Int32 nParaCount
= pOutliner
->GetParagraphCount();
412 std::optional
<OutlinerParaObject
> pTemp
= pOutliner
->CreateParaObject(0, nParaCount
);
414 NbcSetOutlinerParaObjectForText(std::move(pTemp
), pText
);
420 bool SdrTextObj::HasText() const
422 if (mpEditingOutliner
)
423 return HasTextImpl(mpEditingOutliner
);
425 OutlinerParaObject
* pOPO
= GetOutlinerParaObject();
427 bool bHasText
= false;
430 const EditTextObject
& rETO
= pOPO
->GetTextObject();
431 sal_Int32 nParaCount
= rETO
.GetParagraphCount();
434 bHasText
= (nParaCount
> 1) || (!rETO
.GetText( 0 ).isEmpty());
440 void SdrTextObj::AppendFamilyToStyleName(OUString
& styleName
, SfxStyleFamily family
)
442 OUStringBuffer aFam
= OUString::number(static_cast<sal_Int32
>(family
));
443 comphelper::string::padToLength(aFam
, PADDING_LENGTH_FOR_STYLE_FAMILY
, PADDING_CHARACTER_FOR_STYLE_FAMILY
);
445 styleName
+= "|" + aFam
;
448 SfxStyleFamily
SdrTextObj::ReadFamilyFromStyleName(std::u16string_view styleName
)
450 std::u16string_view familyString
= styleName
.substr(styleName
.size() - PADDING_LENGTH_FOR_STYLE_FAMILY
);
451 familyString
= comphelper::string::stripEnd(familyString
, PADDING_CHARACTER_FOR_STYLE_FAMILY
);
452 sal_uInt16 nFam
= static_cast<sal_uInt16
>(o3tl::toInt32(familyString
));
454 return static_cast<SfxStyleFamily
>(nFam
);
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */