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 <svl/style.hxx>
22 #include <svx/svdotext.hxx>
23 #include <svx/svdmodel.hxx>
24 #include <svx/svdoutl.hxx>
25 #include <svx/svdorect.hxx>
26 #include <svx/svdocapt.hxx>
27 #include <editeng/editdata.hxx>
28 #include <svx/sdtfchim.hxx>
31 #include <editeng/outlobj.hxx>
32 #include <editeng/outliner.hxx>
33 #include <editeng/editobj.hxx>
36 // The style family which is appended to the style names is padded to this many characters.
37 const short PADDING_LENGTH_FOR_STYLE_FAMILY
= 5;
38 // this character will be used to pad the style families when they are appended to the style names
39 const char PADDING_CHARACTER_FOR_STYLE_FAMILY
= ' ';
42 bool SdrTextObj::AdjustTextFrameWidthAndHeight( tools::Rectangle
& rR
, bool bHgt
, bool bWdt
) const
45 // Not a text frame. Bail out.
52 bool bFitToSize
= IsFitToSize();
56 bool bWdtGrow
= bWdt
&& IsAutoGrowWidth();
57 bool bHgtGrow
= bHgt
&& IsAutoGrowHeight();
58 if (!bWdtGrow
&& !bHgtGrow
)
59 // Not supposed to auto-adjust width or height.
62 SdrTextAniKind eAniKind
= GetTextAniKind();
63 SdrTextAniDirection eAniDir
= GetTextAniDirection();
65 bool bScroll
= eAniKind
== SdrTextAniKind::Scroll
|| eAniKind
== SdrTextAniKind::Alternate
|| eAniKind
== SdrTextAniKind::Slide
;
66 bool bHScroll
= bScroll
&& (eAniDir
== SdrTextAniDirection::Left
|| eAniDir
== SdrTextAniDirection::Right
);
67 bool bVScroll
= bScroll
&& (eAniDir
== SdrTextAniDirection::Up
|| eAniDir
== SdrTextAniDirection::Down
);
69 tools::Rectangle aOldRect
= rR
;
70 tools::Long nHgt
= 0, nMinHgt
= 0, nMaxHgt
= 0;
71 tools::Long nWdt
= 0, nMinWdt
= 0, nMaxWdt
= 0;
73 Size aNewSize
= rR
.GetSize();
74 aNewSize
.AdjustWidth( -1 ); aNewSize
.AdjustHeight( -1 );
76 Size
aMaxSiz(100000, 100000);
77 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
80 aMaxSiz
.setWidth( aTmpSiz
.Width() );
82 aMaxSiz
.setHeight( aTmpSiz
.Height() );
86 nMinWdt
= GetMinTextFrameWidth();
87 nMaxWdt
= GetMaxTextFrameWidth();
88 if (nMaxWdt
== 0 || nMaxWdt
> aMaxSiz
.Width())
89 nMaxWdt
= aMaxSiz
.Width();
93 aNewSize
.setWidth( nMaxWdt
);
98 nMinHgt
= GetMinTextFrameHeight();
99 nMaxHgt
= GetMaxTextFrameHeight();
100 if (nMaxHgt
== 0 || nMaxHgt
> aMaxSiz
.Height())
101 nMaxHgt
= aMaxSiz
.Height();
105 aNewSize
.setHeight( nMaxHgt
);
108 tools::Long nHDist
= GetTextLeftDistance() + GetTextRightDistance();
109 tools::Long nVDist
= GetTextUpperDistance() + GetTextLowerDistance();
110 aNewSize
.AdjustWidth( -nHDist
);
111 aNewSize
.AdjustHeight( -nVDist
);
113 if (aNewSize
.Width() < 2)
114 aNewSize
.setWidth( 2 );
115 if (aNewSize
.Height() < 2)
116 aNewSize
.setHeight( 2 );
121 aNewSize
.setWidth( 0x0FFFFFFF ); // don't break ticker text
123 aNewSize
.setHeight( 0x0FFFFFFF );
128 pEdtOutl
->SetMaxAutoPaperSize(aNewSize
);
131 Size
aSiz2(pEdtOutl
->CalcTextSize());
132 nWdt
= aSiz2
.Width() + 1; // a little tolerance
134 nHgt
= aSiz2
.Height() + 1; // a little tolerance
138 nHgt
= pEdtOutl
->GetTextHeight() + 1; // a little tolerance
143 Outliner
& rOutliner
= ImpGetDrawOutliner();
144 rOutliner
.SetPaperSize(aNewSize
);
145 rOutliner
.SetUpdateMode(true);
146 // TODO: add the optimization with bPortionInfoChecked etc. here
147 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
148 if (pOutlinerParaObject
)
150 rOutliner
.SetText(*pOutlinerParaObject
);
151 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
156 Size
aSiz2(rOutliner
.CalcTextSize());
157 nWdt
= aSiz2
.Width() + 1; // a little tolerance
159 nHgt
= aSiz2
.Height() + 1; // a little tolerance
163 nHgt
= rOutliner
.GetTextHeight() + 1; // a little tolerance
174 nWdt
= 1; // nHDist may be negative
181 nHgt
= 1; // nVDist may be negative
182 tools::Long nWdtGrow
= nWdt
- (rR
.Right() - rR
.Left());
183 tools::Long nHgtGrow
= nHgt
- (rR
.Bottom() - rR
.Top());
190 if (!bWdtGrow
&& !bHgtGrow
)
195 SdrTextHorzAdjust eHAdj
= GetTextHorizontalAdjust();
197 if (eHAdj
== SDRTEXTHORZADJUST_LEFT
)
198 rR
.AdjustRight(nWdtGrow
);
199 else if (eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
200 rR
.AdjustLeft( -nWdtGrow
);
203 tools::Long nWdtGrow2
= nWdtGrow
/ 2;
204 rR
.AdjustLeft( -nWdtGrow2
);
205 rR
.SetRight( rR
.Left() + nWdt
);
211 SdrTextVertAdjust eVAdj
= GetTextVerticalAdjust();
213 if (eVAdj
== SDRTEXTVERTADJUST_TOP
)
214 rR
.AdjustBottom(nHgtGrow
);
215 else if (eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
216 rR
.AdjustTop( -nHgtGrow
);
219 tools::Long nHgtGrow2
= nHgtGrow
/ 2;
220 rR
.AdjustTop( -nHgtGrow2
);
221 rR
.SetBottom( rR
.Top() + nHgt
);
225 if (aGeo
.nRotationAngle
)
227 // Object is rotated.
228 Point
aD1(rR
.TopLeft());
229 aD1
-= aOldRect
.TopLeft();
231 RotatePoint(aD2
, Point(), aGeo
.nSin
, aGeo
.nCos
);
233 rR
.Move(aD2
.X(), aD2
.Y());
239 bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt
, bool bWdt
)
241 bool bRet
= AdjustTextFrameWidthAndHeight(maRect
,bHgt
,bWdt
);
245 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) { // this is a hack
246 pRectObj
->SetXPolyDirty();
248 if (auto pCaptionObj
= dynamic_cast<SdrCaptionObj
*>(this)) { // this is a hack
249 pCaptionObj
->ImpRecalcTail();
255 bool SdrTextObj::AdjustTextFrameWidthAndHeight()
257 tools::Rectangle
aNewRect(maRect
);
258 bool bRet
=AdjustTextFrameWidthAndHeight(aNewRect
);
260 tools::Rectangle aBoundRect0
; if (pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
263 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) { // this is a hack
264 pRectObj
->SetXPolyDirty();
266 bool bScPostIt
= false;
267 if (auto pCaptionObj
= dynamic_cast<SdrCaptionObj
*>(this)) { // this is a hack
268 pCaptionObj
->ImpRecalcTail();
269 // tdf#114956, tdf#138549 use GetSpecialTextBoxShadow to recognize
270 // that this SdrCaption is for a ScPostit
271 bScPostIt
= pCaptionObj
->GetSpecialTextBoxShadow();
274 // to not slow down EditView visualization on Overlay (see
275 // TextEditOverlayObject) it is necessary to suppress the
276 // Invalidates for the deep repaint when the size of the
277 // TextFrame changed (AdjustTextFrameWidthAndHeight returned
278 // true). The ObjectChanges are valid, invalidate will be
279 // done on EndTextEdit anyways
280 const bool bSuppressChangeWhenEditOnOverlay(
282 GetTextEditOutliner() &&
283 GetTextEditOutliner()->hasEditViewCallbacks());
285 if (!bSuppressChangeWhenEditOnOverlay
|| bScPostIt
)
288 BroadcastObjectChange();
291 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
296 void SdrTextObj::ImpSetTextStyleSheetListeners()
298 SfxStyleSheetBasePool
* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
299 if (pStylePool
==nullptr)
302 std::vector
<OUString
> aStyleNames
;
303 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
304 if (pOutlinerParaObject
!=nullptr)
306 // First, we collect all stylesheets contained in the ParaObject in
307 // the container aStyles. The Family is always appended to the name
308 // of the stylesheet.
309 const EditTextObject
& rTextObj
=pOutlinerParaObject
->GetTextObject();
311 SfxStyleFamily eStyleFam
;
312 sal_Int32 nParaCnt
=rTextObj
.GetParagraphCount();
315 for(sal_Int32
nParaNum(0); nParaNum
< nParaCnt
; nParaNum
++)
317 rTextObj
.GetStyleSheet(nParaNum
, aStyleName
, eStyleFam
);
319 if (!aStyleName
.isEmpty())
321 AppendFamilyToStyleName(aStyleName
, eStyleFam
);
324 sal_uInt32
nNum(aStyleNames
.size());
326 while(!bFnd
&& nNum
> 0)
328 // we don't want duplicate stylesheets
330 bFnd
= aStyleName
== aStyleNames
[nNum
];
335 aStyleNames
.push_back(aStyleName
);
341 // now convert the strings in the vector from names to StyleSheet*
342 o3tl::sorted_vector
<SfxStyleSheet
*> aStyleSheets
;
343 while (!aStyleNames
.empty()) {
344 OUString aName
= aStyleNames
.back();
345 aStyleNames
.pop_back();
347 SfxStyleFamily eFam
= ReadFamilyFromStyleName(aName
);
348 SfxStyleSheetBase
* pStyleBase
= pStylePool
->Find(aName
,eFam
);
349 SfxStyleSheet
* pStyle
= dynamic_cast<SfxStyleSheet
*>( pStyleBase
);
350 if (pStyle
!=nullptr && pStyle
!=GetStyleSheet()) {
351 aStyleSheets
.insert(pStyle
);
354 // now remove all superfluous stylesheets
355 sal_uInt16 nNum
=GetBroadcasterCount();
358 SfxBroadcaster
* pBroadcast
=GetBroadcasterJOE(nNum
);
359 SfxStyleSheet
* pStyle
=dynamic_cast<SfxStyleSheet
*>( pBroadcast
);
360 if (pStyle
!=nullptr && pStyle
!=GetStyleSheet()) { // special case for stylesheet of the object
361 if (aStyleSheets
.find(pStyle
)==aStyleSheets
.end()) {
362 EndListening(*pStyle
);
366 // and finally, merge all stylesheets that are contained in aStyles with previous broadcasters
367 for(SfxStyleSheet
* pStyle
: aStyleSheets
) {
368 // let StartListening see for itself if there's already a listener registered
369 StartListening(*pStyle
, DuplicateHandling::Prevent
);
373 /** iterates over the paragraphs of a given SdrObject and removes all
374 hard set character attributes with the which ids contained in the
377 void SdrTextObj::RemoveOutlinerCharacterAttribs( const std::vector
<sal_uInt16
>& rCharWhichIds
)
379 sal_Int32 nText
= getTextCount();
381 while( --nText
>= 0 )
383 SdrText
* pText
= getText( nText
);
384 OutlinerParaObject
* pOutlinerParaObject
= pText
? pText
->GetOutlinerParaObject() : nullptr;
386 if(pOutlinerParaObject
)
388 Outliner
* pOutliner
= nullptr;
390 if( pEdtOutl
|| (pText
== getActiveText()) )
391 pOutliner
= pEdtOutl
;
395 pOutliner
= &ImpGetDrawOutliner();
396 pOutliner
->SetText(*pOutlinerParaObject
);
399 ESelection
aSelAll( 0, 0, EE_PARA_ALL
, EE_TEXTPOS_ALL
);
400 for( const auto& rWhichId
: rCharWhichIds
)
402 pOutliner
->RemoveAttribs( aSelAll
, false, rWhichId
);
405 if(!pEdtOutl
|| (pText
!= getActiveText()) )
407 const sal_Int32 nParaCount
= pOutliner
->GetParagraphCount();
408 std::unique_ptr
<OutlinerParaObject
> pTemp
= pOutliner
->CreateParaObject(0, nParaCount
);
410 NbcSetOutlinerParaObjectForText(std::move(pTemp
), pText
);
416 bool SdrTextObj::HasText() const
419 return HasTextImpl(pEdtOutl
);
421 OutlinerParaObject
* pOPO
= GetOutlinerParaObject();
423 bool bHasText
= false;
426 const EditTextObject
& rETO
= pOPO
->GetTextObject();
427 sal_Int32 nParaCount
= rETO
.GetParagraphCount();
430 bHasText
= (nParaCount
> 1) || (!rETO
.GetText( 0 ).isEmpty());
436 void SdrTextObj::AppendFamilyToStyleName(OUString
& styleName
, SfxStyleFamily family
)
439 aFam
.append(static_cast<sal_Int32
>(family
));
440 comphelper::string::padToLength(aFam
, PADDING_LENGTH_FOR_STYLE_FAMILY
, PADDING_CHARACTER_FOR_STYLE_FAMILY
);
442 styleName
+= "|" + aFam
.makeStringAndClear();
445 SfxStyleFamily
SdrTextObj::ReadFamilyFromStyleName(const OUString
& styleName
)
447 OUString familyString
= styleName
.copy(styleName
.getLength() - PADDING_LENGTH_FOR_STYLE_FAMILY
);
448 familyString
= comphelper::string::stripEnd(familyString
, PADDING_CHARACTER_FOR_STYLE_FAMILY
);
449 sal_uInt16 nFam
= static_cast<sal_uInt16
>(familyString
.toInt32());
451 return static_cast<SfxStyleFamily
>(nFam
);
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */