Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / svdraw / svdotxat.cxx
blob5ba5ec6a82cc5501272de00a794c0dfde22806e9
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 <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>
35 namespace {
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
44 if (!bTextFrame)
45 // Not a text frame. Bail out.
46 return false;
48 if (rR.IsEmpty())
49 // Empty rectangle.
50 return false;
52 bool bFitToSize = IsFitToSize();
53 if (bFitToSize)
54 return false;
56 bool bWdtGrow = bWdt && IsAutoGrowWidth();
57 bool bHgtGrow = bHgt && IsAutoGrowHeight();
58 if (!bWdtGrow && !bHgtGrow)
59 // Not supposed to auto-adjust width or height.
60 return false;
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());
79 if (aTmpSiz.Width())
80 aMaxSiz.setWidth( aTmpSiz.Width() );
81 if (aTmpSiz.Height())
82 aMaxSiz.setHeight( aTmpSiz.Height() );
84 if (bWdtGrow)
86 nMinWdt = GetMinTextFrameWidth();
87 nMaxWdt = GetMaxTextFrameWidth();
88 if (nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width())
89 nMaxWdt = aMaxSiz.Width();
90 if (nMinWdt <= 0)
91 nMinWdt = 1;
93 aNewSize.setWidth( nMaxWdt );
96 if (bHgtGrow)
98 nMinHgt = GetMinTextFrameHeight();
99 nMaxHgt = GetMaxTextFrameHeight();
100 if (nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height())
101 nMaxHgt = aMaxSiz.Height();
102 if (nMinHgt <= 0)
103 nMinHgt = 1;
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 );
118 if (!IsInEditMode())
120 if (bHScroll)
121 aNewSize.setWidth( 0x0FFFFFFF ); // don't break ticker text
122 if (bVScroll)
123 aNewSize.setHeight( 0x0FFFFFFF );
126 if (pEdtOutl)
128 pEdtOutl->SetMaxAutoPaperSize(aNewSize);
129 if (bWdtGrow)
131 Size aSiz2(pEdtOutl->CalcTextSize());
132 nWdt = aSiz2.Width() + 1; // a little tolerance
133 if (bHgtGrow)
134 nHgt = aSiz2.Height() + 1; // a little tolerance
136 else
138 nHgt = pEdtOutl->GetTextHeight() + 1; // a little tolerance
141 else
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());
154 if (bWdtGrow)
156 Size aSiz2(rOutliner.CalcTextSize());
157 nWdt = aSiz2.Width() + 1; // a little tolerance
158 if (bHgtGrow)
159 nHgt = aSiz2.Height() + 1; // a little tolerance
161 else
163 nHgt = rOutliner.GetTextHeight() + 1; // a little tolerance
165 rOutliner.Clear();
168 if (nWdt < nMinWdt)
169 nWdt = nMinWdt;
170 if (nWdt > nMaxWdt)
171 nWdt = nMaxWdt;
172 nWdt += nHDist;
173 if (nWdt < 1)
174 nWdt = 1; // nHDist may be negative
175 if (nHgt < nMinHgt)
176 nHgt = nMinHgt;
177 if (nHgt > nMaxHgt)
178 nHgt = nMaxHgt;
179 nHgt += nVDist;
180 if (nHgt < 1)
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());
185 if (nWdtGrow == 0)
186 bWdtGrow = false;
187 if (nHgtGrow == 0)
188 bHgtGrow = false;
190 if (!bWdtGrow && !bHgtGrow)
191 return false;
193 if (bWdtGrow)
195 SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust();
197 if (eHAdj == SDRTEXTHORZADJUST_LEFT)
198 rR.AdjustRight(nWdtGrow );
199 else if (eHAdj == SDRTEXTHORZADJUST_RIGHT)
200 rR.AdjustLeft( -nWdtGrow );
201 else
203 tools::Long nWdtGrow2 = nWdtGrow / 2;
204 rR.AdjustLeft( -nWdtGrow2 );
205 rR.SetRight( rR.Left() + nWdt );
209 if (bHgtGrow)
211 SdrTextVertAdjust eVAdj = GetTextVerticalAdjust();
213 if (eVAdj == SDRTEXTVERTADJUST_TOP)
214 rR.AdjustBottom(nHgtGrow );
215 else if (eVAdj == SDRTEXTVERTADJUST_BOTTOM)
216 rR.AdjustTop( -nHgtGrow );
217 else
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();
230 Point aD2(aD1);
231 RotatePoint(aD2, Point(), aGeo.nSin, aGeo.nCos);
232 aD2 -= aD1;
233 rR.Move(aD2.X(), aD2.Y());
236 return true;
239 bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
241 bool bRet = AdjustTextFrameWidthAndHeight(maRect,bHgt,bWdt);
242 if (bRet)
244 SetRectsDirty();
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();
252 return bRet;
255 bool SdrTextObj::AdjustTextFrameWidthAndHeight()
257 tools::Rectangle aNewRect(maRect);
258 bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
259 if (bRet) {
260 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
261 maRect = aNewRect;
262 SetRectsDirty();
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(
281 IsInEditMode() &&
282 GetTextEditOutliner() &&
283 GetTextEditOutliner()->hasEditViewCallbacks());
285 if (!bSuppressChangeWhenEditOnOverlay || bScPostIt)
287 SetChanged();
288 BroadcastObjectChange();
291 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
293 return bRet;
296 void SdrTextObj::ImpSetTextStyleSheetListeners()
298 SfxStyleSheetBasePool* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
299 if (pStylePool==nullptr)
300 return;
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();
310 OUString aStyleName;
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);
323 bool bFnd(false);
324 sal_uInt32 nNum(aStyleNames.size());
326 while(!bFnd && nNum > 0)
328 // we don't want duplicate stylesheets
329 nNum--;
330 bFnd = aStyleName == aStyleNames[nNum];
333 if(!bFnd)
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();
356 while (nNum>0) {
357 nNum--;
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
375 given vector
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;
393 if(!pOutliner)
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);
409 pOutliner->Clear();
410 NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
416 bool SdrTextObj::HasText() const
418 if( pEdtOutl )
419 return HasTextImpl(pEdtOutl);
421 OutlinerParaObject* pOPO = GetOutlinerParaObject();
423 bool bHasText = false;
424 if( pOPO )
426 const EditTextObject& rETO = pOPO->GetTextObject();
427 sal_Int32 nParaCount = rETO.GetParagraphCount();
429 if( nParaCount > 0 )
430 bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty());
433 return bHasText;
436 void SdrTextObj::AppendFamilyToStyleName(OUString& styleName, SfxStyleFamily family)
438 OUStringBuffer aFam;
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());
450 assert(nFam != 0);
451 return static_cast<SfxStyleFamily>(nFam);
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */