Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / svdotxat.cxx
blob4957a4fe98065e232f9809c3b9f9cc7b3d927405
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
37 namespace {
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
46 if (!mbTextFrame)
47 // Not a text frame. Bail out.
48 return false;
50 if (rR.IsEmpty())
51 // Empty rectangle.
52 return false;
54 bool bFitToSize = IsFitToSize();
55 if (bFitToSize)
56 return false;
58 bool bWdtGrow = bWdt && IsAutoGrowWidth();
59 bool bHgtGrow = bHgt && IsAutoGrowHeight();
60 if (!bWdtGrow && !bHgtGrow)
61 // Not supposed to auto-adjust width or height.
62 return false;
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());
81 if (aTmpSiz.Width())
82 aMaxSiz.setWidth( aTmpSiz.Width() );
83 if (aTmpSiz.Height())
84 aMaxSiz.setHeight( aTmpSiz.Height() );
86 if (bWdtGrow)
88 nMinWdt = GetMinTextFrameWidth();
89 nMaxWdt = GetMaxTextFrameWidth();
90 if (nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width())
91 nMaxWdt = aMaxSiz.Width();
92 if (nMinWdt <= 0)
93 nMinWdt = 1;
95 aNewSize.setWidth( nMaxWdt );
98 if (bHgtGrow)
100 nMinHgt = GetMinTextFrameHeight();
101 nMaxHgt = GetMaxTextFrameHeight();
102 if (nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height())
103 nMaxHgt = aMaxSiz.Height();
104 if (nMinHgt <= 0)
105 nMinHgt = 1;
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 );
120 if (!IsInEditMode())
122 if (bHScroll)
123 aNewSize.setWidth( 0x0FFFFFFF ); // don't break ticker text
124 if (bVScroll)
125 aNewSize.setHeight( 0x0FFFFFFF );
128 if (mpEditingOutliner)
130 mpEditingOutliner->SetMaxAutoPaperSize(aNewSize);
131 if (bWdtGrow)
133 Size aSiz2(mpEditingOutliner->CalcTextSize());
134 nWdt = aSiz2.Width() + 1; // a little tolerance
135 if (bHgtGrow)
136 nHgt = aSiz2.Height() + 1; // a little tolerance
138 else
140 nHgt = mpEditingOutliner->GetTextHeight() + 1; // a little tolerance
143 else
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());
156 if (bWdtGrow)
158 Size aSiz2(rOutliner.CalcTextSize());
159 nWdt = aSiz2.Width() + 1; // a little tolerance
160 if (bHgtGrow)
161 nHgt = aSiz2.Height() + 1; // a little tolerance
163 else
165 nHgt = rOutliner.GetTextHeight() + 1; // a little tolerance
167 rOutliner.Clear();
170 if (nWdt < nMinWdt)
171 nWdt = nMinWdt;
172 if (nWdt > nMaxWdt)
173 nWdt = nMaxWdt;
174 nWdt += nHDist;
175 if (nWdt < 1)
176 nWdt = 1; // nHDist may be negative
177 if (nHgt < nMinHgt)
178 nHgt = nMinHgt;
179 if (nHgt > nMaxHgt)
180 nHgt = nMaxHgt;
181 nHgt += nVDist;
182 if (nHgt < 1)
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());
187 if (nWdtGrow == 0)
188 bWdtGrow = false;
189 if (nHgtGrow == 0)
190 bHgtGrow = false;
192 if (!bWdtGrow && !bHgtGrow)
193 return false;
195 if (bWdtGrow)
197 SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust();
199 if (eHAdj == SDRTEXTHORZADJUST_LEFT)
200 rR.AdjustRight(nWdtGrow );
201 else if (eHAdj == SDRTEXTHORZADJUST_RIGHT)
202 rR.AdjustLeft( -nWdtGrow );
203 else
205 tools::Long nWdtGrow2 = nWdtGrow / 2;
206 rR.AdjustLeft( -nWdtGrow2 );
207 rR.SetRight( rR.Left() + nWdt );
211 if (bHgtGrow)
213 SdrTextVertAdjust eVAdj = GetTextVerticalAdjust();
215 if (eVAdj == SDRTEXTVERTADJUST_TOP)
216 rR.AdjustBottom(nHgtGrow );
217 else if (eVAdj == SDRTEXTVERTADJUST_BOTTOM)
218 rR.AdjustTop( -nHgtGrow );
219 else
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();
232 Point aD2(aD1);
233 RotatePoint(aD2, Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
234 aD2 -= aD1;
235 rR.Move(aD2.X(), aD2.Y());
238 return true;
241 bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
243 tools::Rectangle aRectangle(getRectangle());
244 bool bRet = AdjustTextFrameWidthAndHeight(aRectangle, bHgt, bWdt);
245 setRectangle(aRectangle);
246 if (bRet)
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();
256 return bRet;
259 bool SdrTextObj::AdjustTextFrameWidthAndHeight()
261 tools::Rectangle aNewRect(getRectangle());
262 bool bRet = AdjustTextFrameWidthAndHeight(aNewRect);
263 if (bRet) {
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(
285 IsInEditMode() &&
286 GetTextEditOutliner() &&
287 GetTextEditOutliner()->hasEditViewCallbacks());
289 if (!bSuppressChangeWhenEditOnOverlay || bScPostIt)
291 SetChanged();
292 BroadcastObjectChange();
295 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
297 return bRet;
300 void SdrTextObj::ImpSetTextStyleSheetListeners()
302 SfxStyleSheetBasePool* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
303 if (pStylePool==nullptr)
304 return;
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();
314 OUString aStyleName;
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);
327 bool bFnd(false);
328 sal_uInt32 nNum(aStyleNames.size());
330 while(!bFnd && nNum > 0)
332 // we don't want duplicate stylesheets
333 nNum--;
334 bFnd = aStyleName == aStyleNames[nNum];
337 if(!bFnd)
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();
360 while (nNum>0) {
361 nNum--;
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
379 given vector
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;
397 if(!pOutliner)
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);
413 pOutliner->Clear();
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;
428 if( pOPO )
430 const EditTextObject& rETO = pOPO->GetTextObject();
431 sal_Int32 nParaCount = rETO.GetParagraphCount();
433 if( nParaCount > 0 )
434 bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty());
437 return bHasText;
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));
453 assert(nFam != 0);
454 return static_cast<SfxStyleFamily>(nFam);
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */