File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
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/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
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 . | |||
18 | */ | |||
19 | ||||
20 | ||||
21 | #include <comphelper/string.hxx> | |||
22 | #include <svl/stritem.hxx> | |||
23 | #include <svx/svdotext.hxx> | |||
24 | #include <svx/svdpage.hxx> | |||
25 | #include <svx/svdoutl.hxx> | |||
26 | #include <svx/svdmodel.hxx> | |||
27 | #include <svx/dialmgr.hxx> | |||
28 | #include <svx/strings.hrc> | |||
29 | #include <editeng/writingmodeitem.hxx> | |||
30 | #include <svx/sdtfchim.hxx> | |||
31 | #include <editeng/editdata.hxx> | |||
32 | #include <editeng/editstat.hxx> | |||
33 | #include <editeng/outlobj.hxx> | |||
34 | #include <editeng/editobj.hxx> | |||
35 | #include <editeng/outliner.hxx> | |||
36 | #include <textchain.hxx> | |||
37 | #include <textchainflow.hxx> | |||
38 | #include <tools/helpers.hxx> | |||
39 | #include <svx/sderitm.hxx> | |||
40 | #include <svx/sdooitm.hxx> | |||
41 | #include <svx/sdshitm.hxx> | |||
42 | #include <svx/sdtagitm.hxx> | |||
43 | #include <svx/sdtfsitm.hxx> | |||
44 | #include <svx/sdtmfitm.hxx> | |||
45 | #include <svx/xtextit0.hxx> | |||
46 | #include <sdr/properties/textproperties.hxx> | |||
47 | #include <sdr/contact/viewcontactoftextobj.hxx> | |||
48 | #include <basegfx/tuple/b2dtuple.hxx> | |||
49 | #include <basegfx/matrix/b2dhommatrix.hxx> | |||
50 | #include <vcl/gdimtf.hxx> | |||
51 | #include <vcl/virdev.hxx> | |||
52 | #include <basegfx/matrix/b2dhommatrixtools.hxx> | |||
53 | #include <sal/log.hxx> | |||
54 | ||||
55 | using namespace com::sun::star; | |||
56 | ||||
57 | // BaseProperties section | |||
58 | std::unique_ptr<sdr::properties::BaseProperties> SdrTextObj::CreateObjectSpecificProperties() | |||
59 | { | |||
60 | return std::make_unique<sdr::properties::TextProperties>(*this); | |||
61 | } | |||
62 | ||||
63 | // DrawContact section | |||
64 | std::unique_ptr<sdr::contact::ViewContact> SdrTextObj::CreateObjectSpecificViewContact() | |||
65 | { | |||
66 | return std::make_unique<sdr::contact::ViewContactOfTextObj>(*this); | |||
67 | } | |||
68 | ||||
69 | SdrTextObj::SdrTextObj(SdrModel& rSdrModel) | |||
70 | : SdrAttrObj(rSdrModel), | |||
71 | pEdtOutl(nullptr), | |||
72 | eTextKind(OBJ_TEXT) | |||
73 | { | |||
74 | bTextSizeDirty=false; | |||
75 | bTextFrame=false; | |||
76 | bNoShear=false; | |||
77 | bDisableAutoWidthOnDragging=false; | |||
78 | ||||
79 | mbInEditMode = false; | |||
80 | mbTextAnimationAllowed = true; | |||
81 | maTextEditOffset = Point(0, 0); | |||
82 | ||||
83 | // #i25616# | |||
84 | mbSupportTextIndentingOnLineWidthChange = true; | |||
85 | mbInDownScale = false; | |||
86 | } | |||
87 | ||||
88 | SdrTextObj::SdrTextObj( | |||
89 | SdrModel& rSdrModel, | |||
90 | const tools::Rectangle& rNewRect) | |||
91 | : SdrAttrObj(rSdrModel), | |||
92 | maRect(rNewRect), | |||
93 | pEdtOutl(nullptr), | |||
94 | eTextKind(OBJ_TEXT) | |||
95 | { | |||
96 | bTextSizeDirty=false; | |||
97 | bTextFrame=false; | |||
98 | bNoShear=false; | |||
99 | bDisableAutoWidthOnDragging=false; | |||
100 | ImpJustifyRect(maRect); | |||
101 | ||||
102 | mbInEditMode = false; | |||
103 | mbTextAnimationAllowed = true; | |||
104 | mbInDownScale = false; | |||
105 | maTextEditOffset = Point(0, 0); | |||
106 | ||||
107 | // #i25616# | |||
108 | mbSupportTextIndentingOnLineWidthChange = true; | |||
109 | } | |||
110 | ||||
111 | SdrTextObj::SdrTextObj( | |||
112 | SdrModel& rSdrModel, | |||
113 | SdrObjKind eNewTextKind) | |||
114 | : SdrAttrObj(rSdrModel), | |||
115 | pEdtOutl(nullptr), | |||
116 | eTextKind(eNewTextKind) | |||
117 | { | |||
118 | bTextSizeDirty=false; | |||
119 | bTextFrame=true; | |||
120 | bNoShear=true; | |||
121 | bDisableAutoWidthOnDragging=false; | |||
122 | ||||
123 | mbInEditMode = false; | |||
124 | mbTextAnimationAllowed = true; | |||
125 | mbInDownScale = false; | |||
126 | maTextEditOffset = Point(0, 0); | |||
127 | ||||
128 | // #i25616# | |||
129 | mbSupportTextIndentingOnLineWidthChange = true; | |||
130 | } | |||
131 | ||||
132 | SdrTextObj::SdrTextObj( | |||
133 | SdrModel& rSdrModel, | |||
134 | SdrObjKind eNewTextKind, | |||
135 | const tools::Rectangle& rNewRect) | |||
136 | : SdrAttrObj(rSdrModel), | |||
137 | maRect(rNewRect), | |||
138 | pEdtOutl(nullptr), | |||
139 | eTextKind(eNewTextKind) | |||
140 | { | |||
141 | bTextSizeDirty=false; | |||
142 | bTextFrame=true; | |||
143 | bNoShear=true; | |||
144 | bDisableAutoWidthOnDragging=false; | |||
145 | ImpJustifyRect(maRect); | |||
146 | ||||
147 | mbInEditMode = false; | |||
148 | mbTextAnimationAllowed = true; | |||
149 | mbInDownScale = false; | |||
150 | maTextEditOffset = Point(0, 0); | |||
151 | ||||
152 | // #i25616# | |||
153 | mbSupportTextIndentingOnLineWidthChange = true; | |||
154 | } | |||
155 | ||||
156 | SdrTextObj::~SdrTextObj() | |||
157 | { | |||
158 | SdrOutliner& rOutl(getSdrModelFromSdrObject().GetHitTestOutliner()); | |||
159 | if( rOutl.GetTextObj() == this ) | |||
160 | rOutl.SetTextObj( nullptr ); | |||
161 | mpText.reset(); | |||
162 | ImpDeregisterLink(); | |||
163 | } | |||
164 | ||||
165 | void SdrTextObj::FitFrameToTextSize() | |||
166 | { | |||
167 | ImpJustifyRect(maRect); | |||
168 | ||||
169 | SdrText* pText = getActiveText(); | |||
170 | if(pText==nullptr || !pText->GetOutlinerParaObject()) | |||
171 | return; | |||
172 | ||||
173 | SdrOutliner& rOutliner=ImpGetDrawOutliner(); | |||
174 | rOutliner.SetPaperSize(Size(maRect.Right()-maRect.Left(),maRect.Bottom()-maRect.Top())); | |||
175 | rOutliner.SetUpdateMode(true); | |||
176 | rOutliner.SetText(*pText->GetOutlinerParaObject()); | |||
177 | Size aNewSize(rOutliner.CalcTextSize()); | |||
178 | rOutliner.Clear(); | |||
179 | aNewSize.AdjustWidth( 1 ); // because of possible rounding errors | |||
180 | aNewSize.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() ); | |||
181 | aNewSize.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() ); | |||
182 | tools::Rectangle aNewRect(maRect); | |||
183 | aNewRect.SetSize(aNewSize); | |||
184 | ImpJustifyRect(aNewRect); | |||
185 | if (aNewRect!=maRect) { | |||
186 | SetLogicRect(aNewRect); | |||
187 | } | |||
188 | } | |||
189 | ||||
190 | void SdrTextObj::NbcSetText(const OUString& rStr) | |||
191 | { | |||
192 | SdrOutliner& rOutliner=ImpGetDrawOutliner(); | |||
193 | rOutliner.SetStyleSheet( 0, GetStyleSheet()); | |||
194 | rOutliner.SetUpdateMode(true); | |||
195 | rOutliner.SetText(rStr,rOutliner.GetParagraph( 0 )); | |||
196 | std::unique_ptr<OutlinerParaObject> pNewText=rOutliner.CreateParaObject(); | |||
197 | Size aSiz(rOutliner.CalcTextSize()); | |||
198 | rOutliner.Clear(); | |||
199 | NbcSetOutlinerParaObject(std::move(pNewText)); | |||
200 | aTextSize=aSiz; | |||
201 | bTextSizeDirty=false; | |||
202 | } | |||
203 | ||||
204 | void SdrTextObj::SetText(const OUString& rStr) | |||
205 | { | |||
206 | tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); | |||
207 | NbcSetText(rStr); | |||
208 | SetChanged(); | |||
209 | BroadcastObjectChange(); | |||
210 | SendUserCall(SdrUserCallType::Resize,aBoundRect0); | |||
211 | } | |||
212 | ||||
213 | void SdrTextObj::NbcSetText(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat) | |||
214 | { | |||
215 | SdrOutliner& rOutliner=ImpGetDrawOutliner(); | |||
216 | rOutliner.SetStyleSheet( 0, GetStyleSheet()); | |||
217 | rOutliner.Read(rInput,rBaseURL,eFormat); | |||
218 | std::unique_ptr<OutlinerParaObject> pNewText=rOutliner.CreateParaObject(); | |||
219 | rOutliner.SetUpdateMode(true); | |||
220 | Size aSiz(rOutliner.CalcTextSize()); | |||
221 | rOutliner.Clear(); | |||
222 | NbcSetOutlinerParaObject(std::move(pNewText)); | |||
223 | aTextSize=aSiz; | |||
224 | bTextSizeDirty=false; | |||
225 | } | |||
226 | ||||
227 | void SdrTextObj::SetText(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat) | |||
228 | { | |||
229 | tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); | |||
230 | NbcSetText(rInput,rBaseURL,eFormat); | |||
231 | SetChanged(); | |||
232 | BroadcastObjectChange(); | |||
233 | SendUserCall(SdrUserCallType::Resize,aBoundRect0); | |||
234 | } | |||
235 | ||||
236 | const Size& SdrTextObj::GetTextSize() const | |||
237 | { | |||
238 | if (bTextSizeDirty) | |||
239 | { | |||
240 | Size aSiz; | |||
241 | SdrText* pText = getActiveText(); | |||
242 | if( pText && pText->GetOutlinerParaObject ()) | |||
243 | { | |||
244 | SdrOutliner& rOutliner=ImpGetDrawOutliner(); | |||
245 | rOutliner.SetText(*pText->GetOutlinerParaObject()); | |||
246 | rOutliner.SetUpdateMode(true); | |||
247 | aSiz=rOutliner.CalcTextSize(); | |||
248 | rOutliner.Clear(); | |||
249 | } | |||
250 | // casting to nonconst twice | |||
251 | const_cast<SdrTextObj*>(this)->aTextSize=aSiz; | |||
252 | const_cast<SdrTextObj*>(this)->bTextSizeDirty=false; | |||
253 | } | |||
254 | return aTextSize; | |||
255 | } | |||
256 | ||||
257 | bool SdrTextObj::IsAutoGrowHeight() const | |||
258 | { | |||
259 | if(!bTextFrame) | |||
260 | return false; // AutoGrow only together with TextFrames | |||
261 | ||||
262 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
263 | bool bRet = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue(); | |||
264 | ||||
265 | if(bRet) | |||
266 | { | |||
267 | SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue(); | |||
268 | ||||
269 | if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide) | |||
270 | { | |||
271 | SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
272 | ||||
273 | if(eDirection == SdrTextAniDirection::Up || eDirection == SdrTextAniDirection::Down) | |||
274 | { | |||
275 | bRet = false; | |||
276 | } | |||
277 | } | |||
278 | } | |||
279 | return bRet; | |||
280 | } | |||
281 | ||||
282 | bool SdrTextObj::IsAutoGrowWidth() const | |||
283 | { | |||
284 | if(!bTextFrame) | |||
285 | return false; // AutoGrow only together with TextFrames | |||
286 | ||||
287 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
288 | bool bRet = rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue(); | |||
289 | ||||
290 | bool bInEditMOde = IsInEditMode(); | |||
291 | ||||
292 | if(!bInEditMOde && bRet) | |||
293 | { | |||
294 | SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue(); | |||
295 | ||||
296 | if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide) | |||
297 | { | |||
298 | SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
299 | ||||
300 | if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right) | |||
301 | { | |||
302 | bRet = false; | |||
303 | } | |||
304 | } | |||
305 | } | |||
306 | return bRet; | |||
307 | } | |||
308 | ||||
309 | SdrTextHorzAdjust SdrTextObj::GetTextHorizontalAdjust() const | |||
310 | { | |||
311 | return GetTextHorizontalAdjust(GetObjectItemSet()); | |||
312 | } | |||
313 | ||||
314 | SdrTextHorzAdjust SdrTextObj::GetTextHorizontalAdjust(const SfxItemSet& rSet) const | |||
315 | { | |||
316 | if(IsContourTextFrame()) | |||
317 | return SDRTEXTHORZADJUST_BLOCK; | |||
318 | ||||
319 | SdrTextHorzAdjust eRet = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue(); | |||
320 | ||||
321 | bool bInEditMode = IsInEditMode(); | |||
322 | ||||
323 | if(!bInEditMode && eRet == SDRTEXTHORZADJUST_BLOCK) | |||
324 | { | |||
325 | SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue(); | |||
326 | ||||
327 | if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide) | |||
328 | { | |||
329 | SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
330 | ||||
331 | if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right) | |||
332 | { | |||
333 | eRet = SDRTEXTHORZADJUST_LEFT; | |||
334 | } | |||
335 | } | |||
336 | } | |||
337 | ||||
338 | return eRet; | |||
339 | } // defaults: BLOCK (justify) for text frame, CENTER for captions of drawing objects | |||
340 | ||||
341 | SdrTextVertAdjust SdrTextObj::GetTextVerticalAdjust() const | |||
342 | { | |||
343 | return GetTextVerticalAdjust(GetObjectItemSet()); | |||
344 | } | |||
345 | ||||
346 | SdrTextVertAdjust SdrTextObj::GetTextVerticalAdjust(const SfxItemSet& rSet) const | |||
347 | { | |||
348 | if(IsContourTextFrame()) | |||
349 | return SDRTEXTVERTADJUST_TOP; | |||
350 | ||||
351 | // Take care for vertical text animation here | |||
352 | SdrTextVertAdjust eRet = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue(); | |||
353 | bool bInEditMode = IsInEditMode(); | |||
354 | ||||
355 | // Take care for vertical text animation here | |||
356 | if(!bInEditMode && eRet == SDRTEXTVERTADJUST_BLOCK) | |||
357 | { | |||
358 | SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue(); | |||
359 | ||||
360 | if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide) | |||
361 | { | |||
362 | SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
363 | ||||
364 | if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right) | |||
365 | { | |||
366 | eRet = SDRTEXTVERTADJUST_TOP; | |||
367 | } | |||
368 | } | |||
369 | } | |||
370 | ||||
371 | return eRet; | |||
372 | } // defaults: TOP for text frame, CENTER for captions of drawing objects | |||
373 | ||||
374 | void SdrTextObj::ImpJustifyRect(tools::Rectangle& rRect) | |||
375 | { | |||
376 | if (!rRect.IsEmpty()) { | |||
377 | rRect.Justify(); | |||
378 | if (rRect.Left()==rRect.Right()) rRect.AdjustRight( 1 ); | |||
379 | if (rRect.Top()==rRect.Bottom()) rRect.AdjustBottom( 1 ); | |||
380 | } | |||
381 | } | |||
382 | ||||
383 | void SdrTextObj::ImpCheckShear() | |||
384 | { | |||
385 | if (bNoShear && aGeo.nShearAngle!=0) { | |||
386 | aGeo.nShearAngle=0; | |||
387 | aGeo.nTan=0; | |||
388 | } | |||
389 | } | |||
390 | ||||
391 | void SdrTextObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const | |||
392 | { | |||
393 | bool bNoTextFrame=!IsTextFrame(); | |||
394 | rInfo.bResizeFreeAllowed=bNoTextFrame || aGeo.nRotationAngle%9000==0; | |||
395 | rInfo.bResizePropAllowed=true; | |||
396 | rInfo.bRotateFreeAllowed=true; | |||
397 | rInfo.bRotate90Allowed =true; | |||
398 | rInfo.bMirrorFreeAllowed=bNoTextFrame; | |||
399 | rInfo.bMirror45Allowed =bNoTextFrame; | |||
400 | rInfo.bMirror90Allowed =bNoTextFrame; | |||
401 | ||||
402 | // allow transparency | |||
403 | rInfo.bTransparenceAllowed = true; | |||
404 | ||||
405 | rInfo.bShearAllowed =bNoTextFrame; | |||
406 | rInfo.bEdgeRadiusAllowed=true; | |||
407 | bool bCanConv=ImpCanConvTextToCurve(); | |||
408 | rInfo.bCanConvToPath =bCanConv; | |||
409 | rInfo.bCanConvToPoly =bCanConv; | |||
410 | rInfo.bCanConvToPathLineToArea=bCanConv; | |||
411 | rInfo.bCanConvToPolyLineToArea=bCanConv; | |||
412 | rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary()); | |||
413 | } | |||
414 | ||||
415 | sal_uInt16 SdrTextObj::GetObjIdentifier() const | |||
416 | { | |||
417 | return sal_uInt16(eTextKind); | |||
418 | } | |||
419 | ||||
420 | bool SdrTextObj::HasTextImpl( SdrOutliner const * pOutliner ) | |||
421 | { | |||
422 | bool bRet=false; | |||
423 | if(pOutliner) | |||
424 | { | |||
425 | Paragraph* p1stPara=pOutliner->GetParagraph( 0 ); | |||
426 | sal_Int32 nParaCount=pOutliner->GetParagraphCount(); | |||
427 | if(p1stPara==nullptr) | |||
428 | nParaCount=0; | |||
429 | ||||
430 | if(nParaCount==1) | |||
431 | { | |||
432 | // if it is only one paragraph, check if that paragraph is empty | |||
433 | if( pOutliner->GetText(p1stPara).isEmpty() ) | |||
434 | nParaCount = 0; | |||
435 | } | |||
436 | ||||
437 | bRet= nParaCount!=0; | |||
438 | } | |||
439 | return bRet; | |||
440 | } | |||
441 | ||||
442 | void SdrTextObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) | |||
443 | { | |||
444 | const bool bRemove(pNewPage == nullptr && pOldPage != nullptr); | |||
445 | const bool bInsert(pNewPage != nullptr && pOldPage == nullptr); | |||
446 | const bool bLinked(IsLinkedText()); | |||
447 | ||||
448 | if (bLinked && bRemove) | |||
449 | { | |||
450 | ImpDeregisterLink(); | |||
451 | } | |||
452 | ||||
453 | // call parent | |||
454 | SdrAttrObj::handlePageChange(pOldPage, pNewPage); | |||
455 | ||||
456 | if (bLinked && bInsert) | |||
457 | { | |||
458 | ImpRegisterLink(); | |||
459 | } | |||
460 | } | |||
461 | ||||
462 | void SdrTextObj::NbcSetEckenradius(long nRad) | |||
463 | { | |||
464 | SetObjectItem(makeSdrEckenradiusItem(nRad)); | |||
465 | } | |||
466 | ||||
467 | // #115391# This implementation is based on the object size (aRect) and the | |||
468 | // states of IsAutoGrowWidth/Height to correctly set TextMinFrameWidth/Height | |||
469 | void SdrTextObj::AdaptTextMinSize() | |||
470 | { | |||
471 | if (!bTextFrame) | |||
472 | // Only do this for text frame. | |||
473 | return; | |||
474 | ||||
475 | if (getSdrModelFromSdrObject().IsPasteResize()) | |||
476 | // Don't do this during paste resize. | |||
477 | return; | |||
478 | ||||
479 | const bool bW = IsAutoGrowWidth(); | |||
480 | const bool bH = IsAutoGrowHeight(); | |||
481 | ||||
482 | if (!bW && !bH) | |||
483 | // No auto grow requested. Bail out. | |||
484 | return; | |||
485 | ||||
486 | SfxItemSet aSet( | |||
487 | *GetObjectItemSet().GetPool(), | |||
488 | svl::Items<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT, | |||
489 | SDRATTR_TEXT_MINFRAMEWIDTH, SDRATTR_TEXT_AUTOGROWWIDTH>{}); // contains SDRATTR_TEXT_MAXFRAMEWIDTH | |||
490 | ||||
491 | if(bW) | |||
492 | { | |||
493 | // Set minimum width. | |||
494 | const long nDist = GetTextLeftDistance() + GetTextRightDistance(); | |||
495 | const long nW = std::max<long>(0, maRect.GetWidth() - 1 - nDist); // text width without margins | |||
496 | ||||
497 | aSet.Put(makeSdrTextMinFrameWidthItem(nW)); | |||
498 | ||||
499 | if(!IsVerticalWriting() && bDisableAutoWidthOnDragging) | |||
500 | { | |||
501 | bDisableAutoWidthOnDragging = true; | |||
502 | aSet.Put(makeSdrTextAutoGrowWidthItem(false)); | |||
503 | } | |||
504 | } | |||
505 | ||||
506 | if(bH) | |||
507 | { | |||
508 | // Set Minimum height. | |||
509 | const long nDist = GetTextUpperDistance() + GetTextLowerDistance(); | |||
510 | const long nH = std::max<long>(0, maRect.GetHeight() - 1 - nDist); // text height without margins | |||
511 | ||||
512 | aSet.Put(makeSdrTextMinFrameHeightItem(nH)); | |||
513 | ||||
514 | if(IsVerticalWriting() && bDisableAutoWidthOnDragging) | |||
515 | { | |||
516 | bDisableAutoWidthOnDragging = false; | |||
517 | aSet.Put(makeSdrTextAutoGrowHeightItem(false)); | |||
518 | } | |||
519 | } | |||
520 | ||||
521 | SetObjectItemSet(aSet); | |||
522 | } | |||
523 | ||||
524 | void SdrTextObj::ImpSetContourPolygon( SdrOutliner& rOutliner, tools::Rectangle const & rAnchorRect, bool bLineWidth ) const | |||
525 | { | |||
526 | basegfx::B2DPolyPolygon aXorPolyPolygon(TakeXorPoly()); | |||
527 | std::unique_ptr<basegfx::B2DPolyPolygon> pContourPolyPolygon; | |||
528 | basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix( | |||
529 | -rAnchorRect.Left(), -rAnchorRect.Top())); | |||
530 | ||||
531 | if(aGeo.nRotationAngle) | |||
532 | { | |||
533 | // Unrotate! | |||
534 | aMatrix.rotate(-aGeo.nRotationAngle * F_PI18000(3.14159265358979323846/18000.0)); | |||
535 | } | |||
536 | ||||
537 | aXorPolyPolygon.transform(aMatrix); | |||
538 | ||||
539 | if( bLineWidth ) | |||
540 | { | |||
541 | // Take line width into account. | |||
542 | // When doing the hit test, avoid this. (Performance!) | |||
543 | pContourPolyPolygon.reset(new basegfx::B2DPolyPolygon()); | |||
544 | ||||
545 | // test if shadow needs to be avoided for TakeContour() | |||
546 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
547 | bool bShadowOn = rSet.Get(SDRATTR_SHADOW).GetValue(); | |||
548 | ||||
549 | // #i33696# | |||
550 | // Remember TextObject currently set at the DrawOutliner, it WILL be | |||
551 | // replaced during calculating the outline since it uses an own paint | |||
552 | // and that one uses the DrawOutliner, too. | |||
553 | const SdrTextObj* pLastTextObject = rOutliner.GetTextObj(); | |||
554 | ||||
555 | if(bShadowOn) | |||
556 | { | |||
557 | // force shadow off | |||
558 | SdrObject* pCopy(CloneSdrObject(getSdrModelFromSdrObject())); | |||
559 | pCopy->SetMergedItem(makeSdrShadowItem(false)); | |||
560 | *pContourPolyPolygon = pCopy->TakeContour(); | |||
561 | SdrObject::Free( pCopy ); | |||
562 | } | |||
563 | else | |||
564 | { | |||
565 | *pContourPolyPolygon = TakeContour(); | |||
566 | } | |||
567 | ||||
568 | // #i33696# | |||
569 | // restore remembered text object | |||
570 | if(pLastTextObject != rOutliner.GetTextObj()) | |||
571 | { | |||
572 | rOutliner.SetTextObj(pLastTextObject); | |||
573 | } | |||
574 | ||||
575 | pContourPolyPolygon->transform(aMatrix); | |||
576 | } | |||
577 | ||||
578 | rOutliner.SetPolygon(aXorPolyPolygon, pContourPolyPolygon.get()); | |||
579 | } | |||
580 | ||||
581 | void SdrTextObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const | |||
582 | { | |||
583 | rRect=maRect; | |||
584 | } | |||
585 | ||||
586 | void SdrTextObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const | |||
587 | { | |||
588 | long nLeftDist=GetTextLeftDistance(); | |||
589 | long nRightDist=GetTextRightDistance(); | |||
590 | long nUpperDist=GetTextUpperDistance(); | |||
591 | long nLowerDist=GetTextLowerDistance(); | |||
592 | tools::Rectangle aAnkRect(maRect); // the rectangle in which we anchor | |||
593 | bool bFrame=IsTextFrame(); | |||
594 | if (!bFrame) { | |||
595 | TakeUnrotatedSnapRect(aAnkRect); | |||
596 | } | |||
597 | Point aRotateRef(aAnkRect.TopLeft()); | |||
598 | aAnkRect.AdjustLeft(nLeftDist ); | |||
599 | aAnkRect.AdjustTop(nUpperDist ); | |||
600 | aAnkRect.AdjustRight( -nRightDist ); | |||
601 | aAnkRect.AdjustBottom( -nLowerDist ); | |||
602 | ||||
603 | // Since sizes may be bigger than the object bounds it is necessary to | |||
604 | // justify the rect now. | |||
605 | ImpJustifyRect(aAnkRect); | |||
606 | ||||
607 | if (bFrame) { | |||
608 | // TODO: Optimize this. | |||
609 | if (aAnkRect.GetWidth()<2) aAnkRect.SetRight(aAnkRect.Left()+1 ); // minimum size h and v: 2 px | |||
610 | if (aAnkRect.GetHeight()<2) aAnkRect.SetBottom(aAnkRect.Top()+1 ); | |||
611 | } | |||
612 | if (aGeo.nRotationAngle!=0) { | |||
613 | Point aTmpPt(aAnkRect.TopLeft()); | |||
614 | RotatePoint(aTmpPt,aRotateRef,aGeo.nSin,aGeo.nCos); | |||
615 | aTmpPt-=aAnkRect.TopLeft(); | |||
616 | aAnkRect.Move(aTmpPt.X(),aTmpPt.Y()); | |||
617 | } | |||
618 | rAnchorRect=aAnkRect; | |||
619 | } | |||
620 | ||||
621 | void SdrTextObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, | |||
622 | tools::Rectangle* pAnchorRect, bool bLineWidth ) const | |||
623 | { | |||
624 | tools::Rectangle aAnkRect; // the rectangle in which we anchor | |||
625 | TakeTextAnchorRect(aAnkRect); | |||
626 | SdrTextVertAdjust eVAdj=GetTextVerticalAdjust(); | |||
627 | SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust(); | |||
628 | SdrTextAniKind eAniKind=GetTextAniKind(); | |||
629 | SdrTextAniDirection eAniDirection=GetTextAniDirection(); | |||
630 | ||||
631 | bool bFitToSize(IsFitToSize()); | |||
632 | bool bContourFrame=IsContourTextFrame(); | |||
633 | ||||
634 | bool bFrame=IsTextFrame(); | |||
635 | EEControlBits nStat0=rOutliner.GetControlWord(); | |||
636 | Size aNullSize; | |||
637 | if (!bContourFrame) | |||
638 | { | |||
639 | rOutliner.SetControlWord(nStat0|EEControlBits::AUTOPAGESIZE); | |||
640 | rOutliner.SetMinAutoPaperSize(aNullSize); | |||
641 | rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000)); | |||
642 | } | |||
643 | ||||
644 | if (!bFitToSize && !bContourFrame) | |||
645 | { | |||
646 | long nAnkWdt=aAnkRect.GetWidth(); | |||
647 | long nAnkHgt=aAnkRect.GetHeight(); | |||
648 | if (bFrame) | |||
649 | { | |||
650 | long nWdt=nAnkWdt; | |||
651 | long nHgt=nAnkHgt; | |||
652 | ||||
653 | bool bInEditMode = IsInEditMode(); | |||
654 | ||||
655 | if (!bInEditMode && (eAniKind==SdrTextAniKind::Scroll || eAniKind==SdrTextAniKind::Alternate || eAniKind==SdrTextAniKind::Slide)) | |||
656 | { | |||
657 | // unlimited paper size for ticker text | |||
658 | if (eAniDirection==SdrTextAniDirection::Left || eAniDirection==SdrTextAniDirection::Right) nWdt=1000000; | |||
659 | if (eAniDirection==SdrTextAniDirection::Up || eAniDirection==SdrTextAniDirection::Down) nHgt=1000000; | |||
660 | } | |||
661 | ||||
662 | bool bChainedFrame = IsChainable(); | |||
663 | // Might be required for overflow check working: do limit height to frame if box is chainable. | |||
664 | if (!bChainedFrame) { | |||
665 | // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing) | |||
666 | ||||
667 | if(IsVerticalWriting()) | |||
668 | { | |||
669 | nWdt = 1000000; | |||
670 | } | |||
671 | else | |||
672 | { | |||
673 | nHgt = 1000000; | |||
674 | } | |||
675 | } | |||
676 | ||||
677 | rOutliner.SetMaxAutoPaperSize(Size(nWdt,nHgt)); | |||
678 | } | |||
679 | ||||
680 | // New try with _BLOCK for hor and ver after completely | |||
681 | // supporting full width for vertical text. | |||
682 | if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting()) | |||
683 | { | |||
684 | rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0)); | |||
685 | } | |||
686 | ||||
687 | if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting()) | |||
688 | { | |||
689 | rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt)); | |||
690 | } | |||
691 | } | |||
692 | ||||
693 | rOutliner.SetPaperSize(aNullSize); | |||
694 | if (bContourFrame) | |||
695 | ImpSetContourPolygon( rOutliner, aAnkRect, bLineWidth ); | |||
696 | ||||
697 | // put text into the outliner, if available from the edit outliner | |||
698 | SdrText* pText = getActiveText(); | |||
699 | OutlinerParaObject* pOutlinerParaObject = pText ? pText->GetOutlinerParaObject() : nullptr; | |||
700 | OutlinerParaObject* pPara = (pEdtOutl && !bNoEditText) ? pEdtOutl->CreateParaObject().release() : pOutlinerParaObject; | |||
701 | ||||
702 | if (pPara) | |||
703 | { | |||
704 | const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner); | |||
705 | const SdrTextObj* pTestObj = rOutliner.GetTextObj(); | |||
706 | ||||
707 | if( !pTestObj || !bHitTest || pTestObj != this || | |||
708 | pTestObj->GetOutlinerParaObject() != pOutlinerParaObject ) | |||
709 | { | |||
710 | if( bHitTest ) // #i33696# take back fix #i27510# | |||
711 | { | |||
712 | rOutliner.SetTextObj( this ); | |||
713 | rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue()); | |||
714 | } | |||
715 | ||||
716 | rOutliner.SetUpdateMode(true); | |||
717 | rOutliner.SetText(*pPara); | |||
718 | } | |||
719 | } | |||
720 | else | |||
721 | { | |||
722 | rOutliner.SetTextObj( nullptr ); | |||
723 | } | |||
724 | ||||
725 | if (pEdtOutl && !bNoEditText && pPara) | |||
726 | delete pPara; | |||
727 | ||||
728 | rOutliner.SetUpdateMode(true); | |||
729 | rOutliner.SetControlWord(nStat0); | |||
730 | ||||
731 | if( pText ) | |||
732 | pText->CheckPortionInfo(rOutliner); | |||
733 | ||||
734 | Point aTextPos(aAnkRect.TopLeft()); | |||
735 | Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() adds a little tolerance, right? | |||
736 | ||||
737 | // For draw objects containing text correct hor/ver alignment if text is bigger | |||
738 | // than the object itself. Without that correction, the text would always be | |||
739 | // formatted to the left edge (or top edge when vertical) of the draw object. | |||
740 | if(!IsTextFrame()) | |||
741 | { | |||
742 | if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting()) | |||
743 | { | |||
744 | // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK, | |||
745 | // else the alignment is wanted. | |||
746 | if(SDRTEXTHORZADJUST_BLOCK == eHAdj) | |||
747 | { | |||
748 | eHAdj = SDRTEXTHORZADJUST_CENTER; | |||
749 | } | |||
750 | } | |||
751 | ||||
752 | if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting()) | |||
753 | { | |||
754 | // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK, | |||
755 | // else the alignment is wanted. | |||
756 | if(SDRTEXTVERTADJUST_BLOCK == eVAdj) | |||
757 | { | |||
758 | eVAdj = SDRTEXTVERTADJUST_CENTER; | |||
759 | } | |||
760 | } | |||
761 | } | |||
762 | ||||
763 | if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT) | |||
764 | { | |||
765 | long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width(); | |||
766 | if (eHAdj==SDRTEXTHORZADJUST_CENTER) | |||
767 | aTextPos.AdjustX(nFreeWdt/2 ); | |||
768 | if (eHAdj==SDRTEXTHORZADJUST_RIGHT) | |||
769 | aTextPos.AdjustX(nFreeWdt ); | |||
770 | } | |||
771 | if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM) | |||
772 | { | |||
773 | long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height(); | |||
774 | if (eVAdj==SDRTEXTVERTADJUST_CENTER) | |||
775 | aTextPos.AdjustY(nFreeHgt/2 ); | |||
776 | if (eVAdj==SDRTEXTVERTADJUST_BOTTOM) | |||
777 | aTextPos.AdjustY(nFreeHgt ); | |||
778 | } | |||
779 | if (aGeo.nRotationAngle!=0) | |||
780 | RotatePoint(aTextPos,aAnkRect.TopLeft(),aGeo.nSin,aGeo.nCos); | |||
781 | ||||
782 | if (pAnchorRect) | |||
783 | *pAnchorRect=aAnkRect; | |||
784 | ||||
785 | // rTextRect might not be correct in some cases at ContourFrame | |||
786 | rTextRect=tools::Rectangle(aTextPos,aTextSiz); | |||
787 | if (bContourFrame) | |||
788 | rTextRect=aAnkRect; | |||
789 | } | |||
790 | ||||
791 | bool SdrTextObj::CanCreateEditOutlinerParaObject() const | |||
792 | { | |||
793 | if( HasTextImpl( pEdtOutl ) ) | |||
794 | { | |||
795 | return pEdtOutl->GetParagraphCount() > 0; | |||
796 | } | |||
797 | return false; | |||
798 | } | |||
799 | ||||
800 | std::unique_ptr<OutlinerParaObject> SdrTextObj::CreateEditOutlinerParaObject() const | |||
801 | { | |||
802 | std::unique_ptr<OutlinerParaObject> pPara; | |||
803 | if( HasTextImpl( pEdtOutl ) ) | |||
804 | { | |||
805 | sal_Int32 nParaCount = pEdtOutl->GetParagraphCount(); | |||
806 | pPara = pEdtOutl->CreateParaObject(0, nParaCount); | |||
807 | } | |||
808 | return pPara; | |||
809 | } | |||
810 | ||||
811 | void SdrTextObj::ImpSetCharStretching(SdrOutliner& rOutliner, const Size& rTextSize, const Size& rShapeSize, Fraction& rFitXCorrection) | |||
812 | { | |||
813 | OutputDevice* pOut = rOutliner.GetRefDevice(); | |||
814 | bool bNoStretching(false); | |||
815 | ||||
816 | if(pOut && pOut->GetOutDevType() == OUTDEV_PRINTER) | |||
817 | { | |||
818 | // check whether CharStretching is possible at all | |||
819 | GDIMetaFile* pMtf = pOut->GetConnectMetaFile(); | |||
820 | OUString aTestString(u'J'); | |||
821 | ||||
822 | if(pMtf && (!pMtf->IsRecord() || pMtf->IsPause())) | |||
823 | pMtf = nullptr; | |||
824 | ||||
825 | if(pMtf) | |||
826 | pMtf->Pause(true); | |||
827 | ||||
828 | vcl::Font aOriginalFont(pOut->GetFont()); | |||
829 | vcl::Font aTmpFont( OutputDevice::GetDefaultFont( DefaultFontType::SERIF, LANGUAGE_SYSTEMLanguageType(0x0000), GetDefaultFontFlags::OnlyOne ) ); | |||
830 | ||||
831 | aTmpFont.SetFontSize(Size(0,100)); | |||
832 | pOut->SetFont(aTmpFont); | |||
833 | Size aSize1(pOut->GetTextWidth(aTestString), pOut->GetTextHeight()); | |||
834 | aTmpFont.SetFontSize(Size(800,100)); | |||
835 | pOut->SetFont(aTmpFont); | |||
836 | Size aSize2(pOut->GetTextWidth(aTestString), pOut->GetTextHeight()); | |||
837 | pOut->SetFont(aOriginalFont); | |||
838 | ||||
839 | if(pMtf) | |||
840 | pMtf->Pause(false); | |||
841 | ||||
842 | bNoStretching = (aSize1 == aSize2); | |||
843 | ||||
844 | #ifdef _WIN32 | |||
845 | // Windows zooms the font proportionally when using Size(100,500), | |||
846 | // we don't like that. | |||
847 | if(aSize2.Height() >= aSize1.Height() * 2) | |||
848 | { | |||
849 | bNoStretching = true; | |||
850 | } | |||
851 | #endif | |||
852 | } | |||
853 | unsigned nLoopCount=0; | |||
854 | bool bNoMoreLoop = false; | |||
855 | long nXDiff0=0x7FFFFFFF; | |||
856 | long nWantWdt=rShapeSize.Width(); | |||
857 | long nIsWdt=rTextSize.Width(); | |||
858 | if (nIsWdt==0) nIsWdt=1; | |||
859 | ||||
860 | long nWantHgt=rShapeSize.Height(); | |||
861 | long nIsHgt=rTextSize.Height(); | |||
862 | if (nIsHgt==0) nIsHgt=1; | |||
863 | ||||
864 | long nXTolPl=nWantWdt/100; // tolerance: +1% | |||
865 | long nXTolMi=nWantWdt/25; // tolerance: -4% | |||
866 | long nXCorr =nWantWdt/20; // correction scale: 5% | |||
867 | ||||
868 | long nX=(nWantWdt*100) /nIsWdt; // calculate X stretching | |||
869 | long nY=(nWantHgt*100) /nIsHgt; // calculate Y stretching | |||
870 | bool bChkX = true; | |||
871 | if (bNoStretching) { // might only be possible proportionally | |||
872 | if (nX>nY) { nX=nY; bChkX=false; } | |||
873 | else { nY=nX; } | |||
874 | } | |||
875 | ||||
876 | while (nLoopCount<5 && !bNoMoreLoop) { | |||
877 | if (nX<0) nX=-nX; | |||
878 | if (nX<1) { nX=1; bNoMoreLoop = true; } | |||
879 | if (nX>65535) { nX=65535; bNoMoreLoop = true; } | |||
880 | ||||
881 | if (nY<0) nY=-nY; | |||
882 | if (nY<1) { nY=1; bNoMoreLoop = true; } | |||
883 | if (nY>65535) { nY=65535; bNoMoreLoop = true; } | |||
884 | ||||
885 | // exception, there is no text yet (horizontal case) | |||
886 | if(nIsWdt <= 1) | |||
887 | { | |||
888 | nX = nY; | |||
889 | bNoMoreLoop = true; | |||
890 | } | |||
891 | ||||
892 | // exception, there is no text yet (vertical case) | |||
893 | if(nIsHgt <= 1) | |||
894 | { | |||
895 | nY = nX; | |||
896 | bNoMoreLoop = true; | |||
897 | } | |||
898 | ||||
899 | rOutliner.SetGlobalCharStretching(static_cast<sal_uInt16>(nX),static_cast<sal_uInt16>(nY)); | |||
900 | nLoopCount++; | |||
901 | Size aSiz(rOutliner.CalcTextSize()); | |||
902 | long nXDiff=aSiz.Width()-nWantWdt; | |||
903 | rFitXCorrection=Fraction(nWantWdt,aSiz.Width()); | |||
904 | if (((nXDiff>=nXTolMi || !bChkX) && nXDiff<=nXTolPl) || nXDiff==nXDiff0) { | |||
905 | bNoMoreLoop = true; | |||
906 | } else { | |||
907 | // correct stretching factors | |||
908 | long nMul=nWantWdt; | |||
909 | long nDiv=aSiz.Width(); | |||
910 | if (std::abs(nXDiff)<=2*nXCorr) { | |||
911 | if (nMul>nDiv) nDiv+=(nMul-nDiv)/2; // but only add half of what we calculated, | |||
912 | else nMul+=(nDiv-nMul)/2; // because the EditEngine calculates wrongly later on | |||
913 | } | |||
914 | nX=nX*nMul/nDiv; | |||
915 | if (bNoStretching) nY=nX; | |||
916 | } | |||
917 | nXDiff0=nXDiff; | |||
918 | } | |||
919 | } | |||
920 | ||||
921 | OUString SdrTextObj::TakeObjNameSingul() const | |||
922 | { | |||
923 | OUString aStr; | |||
924 | ||||
925 | switch(eTextKind) | |||
926 | { | |||
927 | case OBJ_OUTLINETEXT: | |||
928 | { | |||
929 | aStr = SvxResId(STR_ObjNameSingulOUTLINETEXTreinterpret_cast<char const *>("STR_ObjNameSingulOUTLINETEXT" "\004" u8"Outline Text")); | |||
930 | break; | |||
931 | } | |||
932 | ||||
933 | case OBJ_TITLETEXT : | |||
934 | { | |||
935 | aStr = SvxResId(STR_ObjNameSingulTITLETEXTreinterpret_cast<char const *>("STR_ObjNameSingulTITLETEXT" "\004" u8"Title text")); | |||
936 | break; | |||
937 | } | |||
938 | ||||
939 | default: | |||
940 | { | |||
941 | if(IsLinkedText()) | |||
942 | aStr = SvxResId(STR_ObjNameSingulTEXTLNKreinterpret_cast<char const *>("STR_ObjNameSingulTEXTLNK" "\004" u8"Linked text frame")); | |||
943 | else | |||
944 | aStr = SvxResId(STR_ObjNameSingulTEXTreinterpret_cast<char const *>("STR_ObjNameSingulTEXT" "\004" u8"Text Frame")); | |||
945 | break; | |||
946 | } | |||
947 | } | |||
948 | ||||
949 | OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject(); | |||
950 | if(pOutlinerParaObject && eTextKind != OBJ_OUTLINETEXT) | |||
951 | { | |||
952 | // shouldn't currently cause any problems at OUTLINETEXT | |||
953 | OUString aStr2(comphelper::string::stripStart(pOutlinerParaObject->GetTextObject().GetText(0), ' ')); | |||
954 | ||||
955 | // avoid non expanded text portions in object name | |||
956 | // (second condition is new) | |||
957 | if(!aStr2.isEmpty() && aStr2.indexOf(u'\x00FF') == -1) | |||
958 | { | |||
959 | // space between ResStr and content text | |||
960 | aStr += " \'"; | |||
961 | ||||
962 | if(aStr2.getLength() > 10) | |||
963 | { | |||
964 | aStr2 = aStr2.copy(0, 8) + "..."; | |||
965 | } | |||
966 | ||||
967 | aStr += aStr2 + "\'"; | |||
968 | } | |||
969 | } | |||
970 | ||||
971 | OUStringBuffer sName(aStr); | |||
972 | ||||
973 | OUString aName(GetName()); | |||
974 | if (!aName.isEmpty()) | |||
975 | { | |||
976 | sName.append(' '); | |||
977 | sName.append('\''); | |||
978 | sName.append(aName); | |||
979 | sName.append('\''); | |||
980 | } | |||
981 | ||||
982 | return sName.makeStringAndClear(); | |||
983 | } | |||
984 | ||||
985 | OUString SdrTextObj::TakeObjNamePlural() const | |||
986 | { | |||
987 | OUString sName; | |||
988 | switch (eTextKind) { | |||
989 | case OBJ_OUTLINETEXT: sName=SvxResId(STR_ObjNamePluralOUTLINETEXTreinterpret_cast<char const *>("STR_ObjNamePluralOUTLINETEXT" "\004" u8"Outline Texts")); break; | |||
990 | case OBJ_TITLETEXT : sName=SvxResId(STR_ObjNamePluralTITLETEXTreinterpret_cast<char const *>("STR_ObjNamePluralTITLETEXT" "\004" u8"Title texts")); break; | |||
991 | default: { | |||
992 | if (IsLinkedText()) { | |||
993 | sName=SvxResId(STR_ObjNamePluralTEXTLNKreinterpret_cast<char const *>("STR_ObjNamePluralTEXTLNK" "\004" u8"Linked text frames")); | |||
994 | } else { | |||
995 | sName=SvxResId(STR_ObjNamePluralTEXTreinterpret_cast<char const *>("STR_ObjNamePluralTEXT" "\004" u8"Text Frame")); | |||
996 | } | |||
997 | } break; | |||
998 | } // switch | |||
999 | return sName; | |||
1000 | } | |||
1001 | ||||
1002 | SdrTextObj* SdrTextObj::CloneSdrObject(SdrModel& rTargetModel) const | |||
1003 | { | |||
1004 | return CloneHelper< SdrTextObj >(rTargetModel); | |||
1005 | } | |||
1006 | ||||
1007 | SdrTextObj& SdrTextObj::operator=(const SdrTextObj& rObj) | |||
1008 | { | |||
1009 | if( this == &rObj ) | |||
1010 | return *this; | |||
1011 | ||||
1012 | // call parent. tdf#116979: use the correct parent class | |||
1013 | SdrAttrObj::operator=(rObj); | |||
1014 | ||||
1015 | maRect = rObj.maRect; | |||
1016 | aGeo =rObj.aGeo; | |||
1017 | eTextKind =rObj.eTextKind; | |||
1018 | bTextFrame=rObj.bTextFrame; | |||
1019 | aTextSize=rObj.aTextSize; | |||
1020 | bTextSizeDirty=rObj.bTextSizeDirty; | |||
1021 | ||||
1022 | // Not all of the necessary parameters were copied yet. | |||
1023 | bNoShear = rObj.bNoShear; | |||
1024 | bDisableAutoWidthOnDragging = rObj.bDisableAutoWidthOnDragging; | |||
1025 | SdrText* pText = getActiveText(); | |||
1026 | ||||
1027 | if( pText && rObj.HasText() ) | |||
1028 | { | |||
1029 | // before pNewOutlinerParaObject was created the same, but | |||
1030 | // set at mpText (outside this scope), but mpText might be | |||
1031 | // empty (this operator== seems not prepared for MultiText | |||
1032 | // objects). In the current form it makes only sense to | |||
1033 | // create locally and use locally on a known existing SdrText | |||
1034 | const Outliner* pEO=rObj.pEdtOutl; | |||
1035 | std::unique_ptr<OutlinerParaObject> pNewOutlinerParaObject; | |||
1036 | ||||
1037 | if (pEO!=nullptr) | |||
1038 | { | |||
1039 | pNewOutlinerParaObject = pEO->CreateParaObject(); | |||
1040 | } | |||
1041 | else if (nullptr != rObj.getActiveText()->GetOutlinerParaObject()) | |||
1042 | { | |||
1043 | pNewOutlinerParaObject.reset( new OutlinerParaObject(*rObj.getActiveText()->GetOutlinerParaObject()) ); | |||
1044 | } | |||
1045 | ||||
1046 | pText->SetOutlinerParaObject( std::move(pNewOutlinerParaObject) ); | |||
1047 | } | |||
1048 | ||||
1049 | ImpSetTextStyleSheetListeners(); | |||
1050 | return *this; | |||
1051 | } | |||
1052 | ||||
1053 | basegfx::B2DPolyPolygon SdrTextObj::TakeXorPoly() const | |||
1054 | { | |||
1055 | tools::Polygon aPol(maRect); | |||
1056 | if (aGeo.nShearAngle!=0) ShearPoly(aPol,maRect.TopLeft(),aGeo.nTan); | |||
1057 | if (aGeo.nRotationAngle!=0) RotatePoly(aPol,maRect.TopLeft(),aGeo.nSin,aGeo.nCos); | |||
1058 | ||||
1059 | basegfx::B2DPolyPolygon aRetval; | |||
1060 | aRetval.append(aPol.getB2DPolygon()); | |||
1061 | return aRetval; | |||
1062 | } | |||
1063 | ||||
1064 | basegfx::B2DPolyPolygon SdrTextObj::TakeContour() const | |||
1065 | { | |||
1066 | basegfx::B2DPolyPolygon aRetval(SdrAttrObj::TakeContour()); | |||
1067 | ||||
1068 | // and now add the BoundRect of the text, if necessary | |||
1069 | if ( GetOutlinerParaObject() && !IsFontwork() && !IsContourTextFrame() ) | |||
1070 | { | |||
1071 | // using Clone()-Paint() strategy inside TakeContour() leaves a destroyed | |||
1072 | // SdrObject as pointer in DrawOutliner. Set *this again in fetching the outliner | |||
1073 | // in every case | |||
1074 | SdrOutliner& rOutliner=ImpGetDrawOutliner(); | |||
1075 | ||||
1076 | tools::Rectangle aAnchor2; | |||
1077 | tools::Rectangle aR; | |||
1078 | TakeTextRect(rOutliner,aR,false,&aAnchor2); | |||
1079 | rOutliner.Clear(); | |||
1080 | bool bFitToSize(IsFitToSize()); | |||
1081 | if (bFitToSize) aR=aAnchor2; | |||
1082 | tools::Polygon aPol(aR); | |||
1083 | if (aGeo.nRotationAngle!=0) RotatePoly(aPol,aR.TopLeft(),aGeo.nSin,aGeo.nCos); | |||
1084 | ||||
1085 | aRetval.append(aPol.getB2DPolygon()); | |||
1086 | } | |||
1087 | ||||
1088 | return aRetval; | |||
1089 | } | |||
1090 | ||||
1091 | void SdrTextObj::RecalcSnapRect() | |||
1092 | { | |||
1093 | if (aGeo.nRotationAngle!=0 || aGeo.nShearAngle!=0) | |||
1094 | { | |||
1095 | tools::Polygon aPol(maRect); | |||
1096 | if (aGeo.nShearAngle!=0) ShearPoly(aPol,maRect.TopLeft(),aGeo.nTan); | |||
1097 | if (aGeo.nRotationAngle!=0) RotatePoly(aPol,maRect.TopLeft(),aGeo.nSin,aGeo.nCos); | |||
1098 | maSnapRect=aPol.GetBoundRect(); | |||
1099 | } else { | |||
1100 | maSnapRect = maRect; | |||
1101 | } | |||
1102 | } | |||
1103 | ||||
1104 | sal_uInt32 SdrTextObj::GetSnapPointCount() const | |||
1105 | { | |||
1106 | return 4; | |||
1107 | } | |||
1108 | ||||
1109 | Point SdrTextObj::GetSnapPoint(sal_uInt32 i) const | |||
1110 | { | |||
1111 | Point aP; | |||
1112 | switch (i) { | |||
1113 | case 0: aP=maRect.TopLeft(); break; | |||
1114 | case 1: aP=maRect.TopRight(); break; | |||
1115 | case 2: aP=maRect.BottomLeft(); break; | |||
1116 | case 3: aP=maRect.BottomRight(); break; | |||
1117 | default: aP=maRect.Center(); break; | |||
1118 | } | |||
1119 | if (aGeo.nShearAngle!=0) ShearPoint(aP,maRect.TopLeft(),aGeo.nTan); | |||
1120 | if (aGeo.nRotationAngle!=0) RotatePoint(aP,maRect.TopLeft(),aGeo.nSin,aGeo.nCos); | |||
1121 | return aP; | |||
1122 | } | |||
1123 | ||||
1124 | // Extracted from ImpGetDrawOutliner() | |||
1125 | void SdrTextObj::ImpInitDrawOutliner( SdrOutliner& rOutl ) const | |||
1126 | { | |||
1127 | rOutl.SetUpdateMode(false); | |||
1128 | OutlinerMode nOutlinerMode = OutlinerMode::OutlineObject; | |||
1129 | if ( !IsOutlText() ) | |||
1130 | nOutlinerMode = OutlinerMode::TextObject; | |||
1131 | rOutl.Init( nOutlinerMode ); | |||
1132 | ||||
1133 | rOutl.SetGlobalCharStretching(); | |||
1134 | EEControlBits nStat=rOutl.GetControlWord(); | |||
1135 | nStat &= ~EEControlBits(EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE); | |||
1136 | rOutl.SetControlWord(nStat); | |||
1137 | Size aMaxSize(100000,100000); | |||
1138 | rOutl.SetMinAutoPaperSize(Size()); | |||
1139 | rOutl.SetMaxAutoPaperSize(aMaxSize); | |||
1140 | rOutl.SetPaperSize(aMaxSize); | |||
1141 | rOutl.ClearPolygon(); | |||
1142 | } | |||
1143 | ||||
1144 | SdrOutliner& SdrTextObj::ImpGetDrawOutliner() const | |||
1145 | { | |||
1146 | SdrOutliner& rOutl(getSdrModelFromSdrObject().GetDrawOutliner(this)); | |||
1147 | ||||
1148 | // Code extracted to ImpInitDrawOutliner() | |||
1149 | ImpInitDrawOutliner( rOutl ); | |||
1150 | ||||
1151 | return rOutl; | |||
1152 | } | |||
1153 | ||||
1154 | // Extracted from Paint() | |||
1155 | void SdrTextObj::ImpSetupDrawOutlinerForPaint( bool bContourFrame, | |||
1156 | SdrOutliner& rOutliner, | |||
1157 | tools::Rectangle& rTextRect, | |||
1158 | tools::Rectangle& rAnchorRect, | |||
1159 | tools::Rectangle& rPaintRect, | |||
1160 | Fraction& rFitXCorrection ) const | |||
1161 | { | |||
1162 | if (!bContourFrame) | |||
1163 | { | |||
1164 | // FitToSize can't be used together with ContourFrame for now | |||
1165 | if (IsFitToSize() || IsAutoFit()) | |||
1166 | { | |||
1167 | EEControlBits nStat=rOutliner.GetControlWord(); | |||
1168 | nStat|=EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE; | |||
1169 | rOutliner.SetControlWord(nStat); | |||
1170 | } | |||
1171 | } | |||
1172 | rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue()); | |||
1173 | TakeTextRect(rOutliner, rTextRect, false, &rAnchorRect); | |||
1174 | rPaintRect = rTextRect; | |||
1175 | ||||
1176 | if (bContourFrame) | |||
1177 | return; | |||
1178 | ||||
1179 | // FitToSize can't be used together with ContourFrame for now | |||
1180 | if (IsFitToSize()) | |||
1181 | { | |||
1182 | ImpSetCharStretching(rOutliner,rTextRect.GetSize(),rAnchorRect.GetSize(),rFitXCorrection); | |||
1183 | rPaintRect=rAnchorRect; | |||
1184 | } | |||
1185 | else if (IsAutoFit()) | |||
1186 | { | |||
1187 | ImpAutoFitText(rOutliner); | |||
1188 | } | |||
1189 | } | |||
1190 | ||||
1191 | double SdrTextObj::GetFontScaleY() const | |||
1192 | { | |||
1193 | SdrText* pText = getActiveText(); | |||
1194 | if (pText == nullptr || !pText->GetOutlinerParaObject()) | |||
1195 | return 1.0; | |||
1196 | ||||
1197 | SdrOutliner& rOutliner = ImpGetDrawOutliner(); | |||
1198 | const Size aShapeSize = GetSnapRect().GetSize(); | |||
1199 | const Size aSize(aShapeSize.Width() - GetTextLeftDistance() - GetTextRightDistance(), | |||
1200 | aShapeSize.Height() - GetTextUpperDistance() - GetTextLowerDistance()); | |||
1201 | ||||
1202 | rOutliner.SetPaperSize(aSize); | |||
1203 | rOutliner.SetUpdateMode(true); | |||
1204 | rOutliner.SetText(*pText->GetOutlinerParaObject()); | |||
1205 | bool bIsVerticalWriting = IsVerticalWriting(); | |||
1206 | ||||
1207 | // Algorithm from SdrTextObj::ImpAutoFitText | |||
1208 | ||||
1209 | sal_uInt16 nMinStretchX = 0, nMinStretchY = 0; | |||
1210 | sal_uInt16 nCurrStretchX = 100, nCurrStretchY = 100; | |||
1211 | sal_uInt16 aOldStretchXVals[] = { 0,0,0 }; | |||
1212 | const size_t aStretchArySize = SAL_N_ELEMENTS(aOldStretchXVals)(sizeof(sal_n_array_size(aOldStretchXVals))); | |||
1213 | for (unsigned int i = 0; i<aStretchArySize; ++i) | |||
1214 | { | |||
1215 | const Size aCurrTextSize = rOutliner.CalcTextSizeNTP(); | |||
1216 | double fFactor(1.0); | |||
1217 | if (bIsVerticalWriting) | |||
1218 | { | |||
1219 | if (aCurrTextSize.Width() != 0) | |||
1220 | { | |||
1221 | fFactor = double(aSize.Width()) / aCurrTextSize.Width(); | |||
1222 | } | |||
1223 | } | |||
1224 | else if (aCurrTextSize.Height() != 0) | |||
1225 | { | |||
1226 | fFactor = double(aSize.Height()) / aCurrTextSize.Height(); | |||
1227 | } | |||
1228 | fFactor = std::sqrt(fFactor); | |||
1229 | ||||
1230 | rOutliner.GetGlobalCharStretching(nCurrStretchX, nCurrStretchY); | |||
1231 | ||||
1232 | if (fFactor >= 1.0) | |||
1233 | { | |||
1234 | nMinStretchX = std::max(nMinStretchX, nCurrStretchX); | |||
1235 | nMinStretchY = std::max(nMinStretchY, nCurrStretchY); | |||
1236 | } | |||
1237 | ||||
1238 | aOldStretchXVals[i] = nCurrStretchX; | |||
1239 | if (std::find(aOldStretchXVals, aOldStretchXVals + i, nCurrStretchX) != aOldStretchXVals + i) | |||
1240 | break; // same value already attained once; algo is looping, exit | |||
1241 | ||||
1242 | if (fFactor < 1.0 || nCurrStretchX != 100) | |||
1243 | { | |||
1244 | nCurrStretchX = sal::static_int_cast<sal_uInt16>(nCurrStretchX*fFactor); | |||
1245 | nCurrStretchY = sal::static_int_cast<sal_uInt16>(nCurrStretchY*fFactor); | |||
1246 | rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100), nCurrStretchX), | |||
1247 | std::min(sal_uInt16(100), nCurrStretchY)); | |||
1248 | } | |||
1249 | } | |||
1250 | ||||
1251 | return std::min(sal_uInt16(100), nCurrStretchY) / 100.0; | |||
1252 | } | |||
1253 | ||||
1254 | void SdrTextObj::ImpAutoFitText( SdrOutliner& rOutliner ) const | |||
1255 | { | |||
1256 | const Size aShapeSize=GetSnapRect().GetSize(); | |||
1257 | ImpAutoFitText( rOutliner, | |||
1258 | Size(aShapeSize.Width()-GetTextLeftDistance()-GetTextRightDistance(), | |||
1259 | aShapeSize.Height()-GetTextUpperDistance()-GetTextLowerDistance()), | |||
1260 | IsVerticalWriting() ); | |||
1261 | } | |||
1262 | ||||
1263 | void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize, | |||
1264 | bool bIsVerticalWriting) const | |||
1265 | { | |||
1266 | // EditEngine formatting is unstable enough for | |||
1267 | // line-breaking text that we need some more samples | |||
1268 | ||||
1269 | // loop early-exits if we detect an already attained value | |||
1270 | sal_uInt16 nMinStretchX=0, nMinStretchY=0; | |||
1271 | sal_uInt16 aOldStretchXVals[]={0,0,0,0,0,0,0,0,0,0}; | |||
1272 | const size_t aStretchArySize=SAL_N_ELEMENTS(aOldStretchXVals)(sizeof(sal_n_array_size(aOldStretchXVals))); | |||
1273 | for(unsigned int i=0; i<aStretchArySize; ++i) | |||
1274 | { | |||
1275 | const Size aCurrTextSize = rOutliner.CalcTextSizeNTP(); | |||
1276 | double fFactor(1.0); | |||
1277 | if( bIsVerticalWriting ) | |||
1278 | { | |||
1279 | if (aCurrTextSize.Width() != 0) | |||
1280 | { | |||
1281 | fFactor = double(rTextSize.Width())/aCurrTextSize.Width(); | |||
1282 | } | |||
1283 | } | |||
1284 | else if (aCurrTextSize.Height() != 0) | |||
1285 | { | |||
1286 | fFactor = double(rTextSize.Height())/aCurrTextSize.Height(); | |||
1287 | } | |||
1288 | // fFactor scales in both x and y directions | |||
1289 | // - this is fine for bulleted words | |||
1290 | // - but it scales too much for a long paragraph | |||
1291 | // - taking sqrt scales long paragraphs the best | |||
1292 | // - bulleted words will have to go through more iterations | |||
1293 | fFactor = std::sqrt(fFactor); | |||
1294 | ||||
1295 | sal_uInt16 nCurrStretchX, nCurrStretchY; | |||
1296 | rOutliner.GetGlobalCharStretching(nCurrStretchX, nCurrStretchY); | |||
1297 | ||||
1298 | if (fFactor >= 1.0 ) | |||
1299 | { | |||
1300 | // resulting text area fits into available shape rect - | |||
1301 | // err on the larger stretching, to optimally fill area | |||
1302 | nMinStretchX = std::max(nMinStretchX,nCurrStretchX); | |||
1303 | nMinStretchY = std::max(nMinStretchY,nCurrStretchY); | |||
1304 | } | |||
1305 | ||||
1306 | aOldStretchXVals[i] = nCurrStretchX; | |||
1307 | if( std::find(aOldStretchXVals, aOldStretchXVals+i, nCurrStretchX) != aOldStretchXVals+i ) | |||
1308 | break; // same value already attained once; algo is looping, exit | |||
1309 | ||||
1310 | if (fFactor < 1.0 || nCurrStretchX != 100) | |||
1311 | { | |||
1312 | nCurrStretchX = sal::static_int_cast<sal_uInt16>(nCurrStretchX*fFactor); | |||
1313 | nCurrStretchY = sal::static_int_cast<sal_uInt16>(nCurrStretchY*fFactor); | |||
1314 | rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100),nCurrStretchX), | |||
1315 | std::min(sal_uInt16(100),nCurrStretchY)); | |||
1316 | SAL_INFO("svx", "zoom is " << nCurrStretchX)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "zoom is " << nCurrStretchX) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1316" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "zoom is " << nCurrStretchX), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "zoom is " << nCurrStretchX; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1316" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "zoom is " << nCurrStretchX) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1316" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "zoom is " << nCurrStretchX), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "zoom is " << nCurrStretchX; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1316" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1317 | } | |||
1318 | } | |||
1319 | ||||
1320 | const SdrTextFitToSizeTypeItem& rItem = GetObjectItem(SDRATTR_TEXT_FITTOSIZE); | |||
1321 | if (rItem.GetMaxScale() > 0) | |||
1322 | { | |||
1323 | nMinStretchX = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchX); | |||
1324 | nMinStretchY = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchY); | |||
1325 | } | |||
1326 | ||||
1327 | SAL_INFO("svx", "final zoom is " << nMinStretchX)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "final zoom is " << nMinStretchX) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1327" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "final zoom is " << nMinStretchX ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "final zoom is " << nMinStretchX; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1327" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "final zoom is " << nMinStretchX) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1327" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "final zoom is " << nMinStretchX ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "final zoom is " << nMinStretchX; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1327" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1328 | rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100),nMinStretchX), | |||
1329 | std::min(sal_uInt16(100),nMinStretchY)); | |||
1330 | } | |||
1331 | ||||
1332 | void SdrTextObj::SetupOutlinerFormatting( SdrOutliner& rOutl, tools::Rectangle& rPaintRect ) const | |||
1333 | { | |||
1334 | ImpInitDrawOutliner( rOutl ); | |||
1335 | UpdateOutlinerFormatting( rOutl, rPaintRect ); | |||
1336 | } | |||
1337 | ||||
1338 | void SdrTextObj::UpdateOutlinerFormatting( SdrOutliner& rOutl, tools::Rectangle& rPaintRect ) const | |||
1339 | { | |||
1340 | tools::Rectangle aTextRect; | |||
1341 | tools::Rectangle aAnchorRect; | |||
1342 | Fraction aFitXCorrection(1,1); | |||
1343 | ||||
1344 | const bool bContourFrame(IsContourTextFrame()); | |||
1345 | const MapMode aMapMode( | |||
1346 | getSdrModelFromSdrObject().GetScaleUnit(), | |||
1347 | Point(0,0), | |||
1348 | getSdrModelFromSdrObject().GetScaleFraction(), | |||
1349 | getSdrModelFromSdrObject().GetScaleFraction()); | |||
1350 | ||||
1351 | rOutl.SetRefMapMode(aMapMode); | |||
1352 | ImpSetupDrawOutlinerForPaint( | |||
1353 | bContourFrame, | |||
1354 | rOutl, | |||
1355 | aTextRect, | |||
1356 | aAnchorRect, | |||
1357 | rPaintRect, | |||
1358 | aFitXCorrection); | |||
1359 | } | |||
1360 | ||||
1361 | ||||
1362 | OutlinerParaObject* SdrTextObj::GetOutlinerParaObject() const | |||
1363 | { | |||
1364 | SdrText* pText = getActiveText(); | |||
1365 | if( pText ) | |||
1366 | return pText->GetOutlinerParaObject(); | |||
1367 | else | |||
1368 | return nullptr; | |||
1369 | } | |||
1370 | ||||
1371 | void SdrTextObj::NbcSetOutlinerParaObject(std::unique_ptr<OutlinerParaObject> pTextObject) | |||
1372 | { | |||
1373 | NbcSetOutlinerParaObjectForText( std::move(pTextObject), getActiveText() ); | |||
1374 | } | |||
1375 | ||||
1376 | void SdrTextObj::NbcSetOutlinerParaObjectForText( std::unique_ptr<OutlinerParaObject> pTextObject, SdrText* pText ) | |||
1377 | { | |||
1378 | if( pText ) | |||
1379 | pText->SetOutlinerParaObject( std::move(pTextObject) ); | |||
1380 | ||||
1381 | if (pText && pText->GetOutlinerParaObject()) | |||
1382 | { | |||
1383 | SvxWritingModeItem aWritingMode(pText->GetOutlinerParaObject()->IsVertical() && pText->GetOutlinerParaObject()->IsTopToBottom() | |||
1384 | ? css::text::WritingMode_TB_RL | |||
1385 | : css::text::WritingMode_LR_TB, | |||
1386 | SDRATTR_TEXTDIRECTION); | |||
1387 | GetProperties().SetObjectItemDirect(aWritingMode); | |||
1388 | } | |||
1389 | ||||
1390 | SetTextSizeDirty(); | |||
1391 | if (IsTextFrame() && (IsAutoGrowHeight() || IsAutoGrowWidth())) | |||
1392 | { // adapt text frame! | |||
1393 | NbcAdjustTextFrameWidthAndHeight(); | |||
1394 | } | |||
1395 | if (!IsTextFrame()) | |||
1396 | { | |||
1397 | // the SnapRect keeps its size | |||
1398 | SetRectsDirty(true); | |||
1399 | } | |||
1400 | ||||
1401 | // always invalidate BoundRect on change | |||
1402 | SetBoundRectDirty(); | |||
1403 | ActionChanged(); | |||
1404 | ||||
1405 | ImpSetTextStyleSheetListeners(); | |||
1406 | } | |||
1407 | ||||
1408 | void SdrTextObj::NbcReformatText() | |||
1409 | { | |||
1410 | SdrText* pText = getActiveText(); | |||
1411 | if( !(pText && pText->GetOutlinerParaObject()) ) | |||
1412 | return; | |||
1413 | ||||
1414 | pText->ReformatText(); | |||
1415 | if (bTextFrame) | |||
1416 | { | |||
1417 | NbcAdjustTextFrameWidthAndHeight(); | |||
1418 | } | |||
1419 | else | |||
1420 | { | |||
1421 | // the SnapRect keeps its size | |||
1422 | SetBoundRectDirty(); | |||
1423 | SetRectsDirty(true); | |||
1424 | } | |||
1425 | SetTextSizeDirty(); | |||
1426 | ActionChanged(); | |||
1427 | // i22396 | |||
1428 | // Necessary here since we have no compare operator at the outliner | |||
1429 | // para object which may detect changes regarding the combination | |||
1430 | // of outliner para data and configuration (e.g., change of | |||
1431 | // formatting of text numerals) | |||
1432 | GetViewContact().flushViewObjectContacts(false); | |||
1433 | } | |||
1434 | ||||
1435 | SdrObjGeoData* SdrTextObj::NewGeoData() const | |||
1436 | { | |||
1437 | return new SdrTextObjGeoData; | |||
1438 | } | |||
1439 | ||||
1440 | void SdrTextObj::SaveGeoData(SdrObjGeoData& rGeo) const | |||
1441 | { | |||
1442 | SdrAttrObj::SaveGeoData(rGeo); | |||
1443 | SdrTextObjGeoData& rTGeo=static_cast<SdrTextObjGeoData&>(rGeo); | |||
1444 | rTGeo.aRect = maRect; | |||
1445 | rTGeo.aGeo =aGeo; | |||
1446 | } | |||
1447 | ||||
1448 | void SdrTextObj::RestGeoData(const SdrObjGeoData& rGeo) | |||
1449 | { // RectsDirty is called by SdrObject | |||
1450 | SdrAttrObj::RestGeoData(rGeo); | |||
1451 | const SdrTextObjGeoData& rTGeo=static_cast<const SdrTextObjGeoData&>(rGeo); | |||
1452 | NbcSetLogicRect(rTGeo.aRect); | |||
1453 | aGeo =rTGeo.aGeo; | |||
1454 | SetTextSizeDirty(); | |||
1455 | } | |||
1456 | ||||
1457 | drawing::TextFitToSizeType SdrTextObj::GetFitToSize() const | |||
1458 | { | |||
1459 | drawing::TextFitToSizeType eType = drawing::TextFitToSizeType_NONE; | |||
1460 | ||||
1461 | if(!IsAutoGrowWidth()) | |||
1462 | eType = GetObjectItem(SDRATTR_TEXT_FITTOSIZE).GetValue(); | |||
1463 | ||||
1464 | return eType; | |||
1465 | } | |||
1466 | ||||
1467 | const tools::Rectangle& SdrTextObj::GetGeoRect() const | |||
1468 | { | |||
1469 | return maRect; | |||
1470 | } | |||
1471 | ||||
1472 | void SdrTextObj::ForceOutlinerParaObject() | |||
1473 | { | |||
1474 | SdrText* pText = getActiveText(); | |||
1475 | if( pText && (pText->GetOutlinerParaObject() == nullptr) ) | |||
1476 | { | |||
1477 | OutlinerMode nOutlMode = OutlinerMode::TextObject; | |||
1478 | if( IsTextFrame() && eTextKind == OBJ_OUTLINETEXT ) | |||
1479 | nOutlMode = OutlinerMode::OutlineObject; | |||
1480 | ||||
1481 | pText->ForceOutlinerParaObject( nOutlMode ); | |||
1482 | } | |||
1483 | } | |||
1484 | ||||
1485 | TextChain *SdrTextObj::GetTextChain() const | |||
1486 | { | |||
1487 | //if (!IsChainable()) | |||
1488 | // return NULL; | |||
1489 | ||||
1490 | return getSdrModelFromSdrObject().GetTextChain(); | |||
1491 | } | |||
1492 | ||||
1493 | bool SdrTextObj::IsVerticalWriting() const | |||
1494 | { | |||
1495 | if(pEdtOutl) | |||
1496 | { | |||
1497 | return pEdtOutl->IsVertical(); | |||
1498 | } | |||
1499 | ||||
1500 | OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject(); | |||
1501 | if(pOutlinerParaObject) | |||
1502 | { | |||
1503 | return pOutlinerParaObject->IsVertical(); | |||
1504 | } | |||
1505 | ||||
1506 | return false; | |||
1507 | } | |||
1508 | ||||
1509 | void SdrTextObj::SetVerticalWriting(bool bVertical) | |||
1510 | { | |||
1511 | OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject(); | |||
1512 | ||||
1513 | if( !pOutlinerParaObject && bVertical ) | |||
1514 | { | |||
1515 | // we only need to force an outliner para object if the default of | |||
1516 | // horizontal text is changed | |||
1517 | ForceOutlinerParaObject(); | |||
1518 | pOutlinerParaObject = GetOutlinerParaObject(); | |||
1519 | } | |||
1520 | ||||
1521 | if (!pOutlinerParaObject || | |||
1522 | (pOutlinerParaObject->IsVertical() == bVertical)) | |||
1523 | return; | |||
1524 | ||||
1525 | // get item settings | |||
1526 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
1527 | bool bAutoGrowWidth = rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue(); | |||
1528 | bool bAutoGrowHeight = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue(); | |||
1529 | ||||
1530 | // Also exchange hor/ver adjust items | |||
1531 | SdrTextHorzAdjust eHorz = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue(); | |||
1532 | SdrTextVertAdjust eVert = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue(); | |||
1533 | ||||
1534 | // rescue object size | |||
1535 | tools::Rectangle aObjectRect = GetSnapRect(); | |||
1536 | ||||
1537 | // prepare ItemSet to set exchanged width and height items | |||
1538 | SfxItemSet aNewSet(*rSet.GetPool(), | |||
1539 | svl::Items<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT, | |||
1540 | // Expanded item ranges to also support hor and ver adjust. | |||
1541 | SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST, | |||
1542 | SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST>{}); | |||
1543 | ||||
1544 | aNewSet.Put(rSet); | |||
1545 | aNewSet.Put(makeSdrTextAutoGrowWidthItem(bAutoGrowHeight)); | |||
1546 | aNewSet.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth)); | |||
1547 | ||||
1548 | // Exchange horz and vert adjusts | |||
1549 | switch (eVert) | |||
1550 | { | |||
1551 | case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break; | |||
1552 | case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break; | |||
1553 | case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break; | |||
1554 | case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break; | |||
1555 | } | |||
1556 | switch (eHorz) | |||
1557 | { | |||
1558 | case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break; | |||
1559 | case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break; | |||
1560 | case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break; | |||
1561 | case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break; | |||
1562 | } | |||
1563 | ||||
1564 | SetObjectItemSet(aNewSet); | |||
1565 | ||||
1566 | pOutlinerParaObject = GetOutlinerParaObject(); | |||
1567 | if (pOutlinerParaObject) | |||
1568 | { | |||
1569 | // set ParaObject orientation accordingly | |||
1570 | pOutlinerParaObject->SetVertical(bVertical); | |||
1571 | } | |||
1572 | ||||
1573 | // restore object size | |||
1574 | SetSnapRect(aObjectRect); | |||
1575 | } | |||
1576 | ||||
1577 | // transformation interface for StarOfficeAPI. This implements support for | |||
1578 | // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the | |||
1579 | // moment it contains a shearX, rotation and translation, but for setting all linear | |||
1580 | // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported. | |||
1581 | ||||
1582 | ||||
1583 | // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon | |||
1584 | // with the base geometry and returns TRUE. Otherwise it returns FALSE. | |||
1585 | bool SdrTextObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const | |||
1586 | { | |||
1587 | // get turn and shear | |||
1588 | double fRotate = basegfx::deg2rad(aGeo.nRotationAngle / 100.0); | |||
1589 | double fShearX = basegfx::deg2rad(aGeo.nShearAngle / 100.0); | |||
1590 | ||||
1591 | // get aRect, this is the unrotated snaprect | |||
1592 | tools::Rectangle aRectangle(maRect); | |||
1593 | ||||
1594 | // fill other values | |||
1595 | basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight()); | |||
1596 | basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top()); | |||
1597 | ||||
1598 | // position maybe relative to anchorpos, convert | |||
1599 | if( getSdrModelFromSdrObject().IsWriter() ) | |||
1600 | { | |||
1601 | if(GetAnchorPos().X() || GetAnchorPos().Y()) | |||
1602 | { | |||
1603 | aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); | |||
1604 | } | |||
1605 | } | |||
1606 | ||||
1607 | // build matrix | |||
1608 | rMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( | |||
1609 | aScale, | |||
1610 | basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX), | |||
1611 | basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate, | |||
1612 | aTranslate); | |||
1613 | ||||
1614 | return false; | |||
1615 | } | |||
1616 | ||||
1617 | // sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix. | |||
1618 | // If it's an SdrPathObj it will use the provided geometry information. The Polygon has | |||
1619 | // to use (0,0) as upper left and will be scaled to the given size in the matrix. | |||
1620 | void SdrTextObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/) | |||
1621 | { | |||
1622 | // break up matrix | |||
1623 | basegfx::B2DTuple aScale; | |||
1624 | basegfx::B2DTuple aTranslate; | |||
1625 | double fRotate(0.0); | |||
1626 | double fShearX(0.0); | |||
1627 | rMatrix.decompose(aScale, aTranslate, fRotate, fShearX); | |||
1628 | ||||
1629 | // flip? | |||
1630 | bool bFlipX = aScale.getX() < 0.0, | |||
1631 | bFlipY = aScale.getY() < 0.0; | |||
1632 | if (bFlipX) | |||
1633 | { | |||
1634 | aScale.setX(fabs(aScale.getX())); | |||
1635 | } | |||
1636 | if (bFlipY) | |||
1637 | { | |||
1638 | aScale.setY(fabs(aScale.getY())); | |||
1639 | } | |||
1640 | ||||
1641 | // reset object shear and rotations | |||
1642 | aGeo.nRotationAngle = 0; | |||
1643 | aGeo.RecalcSinCos(); | |||
1644 | aGeo.nShearAngle = 0; | |||
1645 | aGeo.RecalcTan(); | |||
1646 | ||||
1647 | // if anchor is used, make position relative to it | |||
1648 | if( getSdrModelFromSdrObject().IsWriter() ) | |||
1649 | { | |||
1650 | if(GetAnchorPos().X() || GetAnchorPos().Y()) | |||
1651 | { | |||
1652 | aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); | |||
1653 | } | |||
1654 | } | |||
1655 | ||||
1656 | // build and set BaseRect (use scale) | |||
1657 | Size aSize(FRound(aScale.getX()), FRound(aScale.getY())); | |||
1658 | tools::Rectangle aBaseRect(Point(), aSize); | |||
1659 | SetSnapRect(aBaseRect); | |||
1660 | ||||
1661 | // flip? | |||
1662 | if (bFlipX) | |||
1663 | { | |||
1664 | Mirror(Point(), Point(0, 1)); | |||
1665 | } | |||
1666 | if (bFlipY) | |||
1667 | { | |||
1668 | Mirror(Point(), Point(1, 0)); | |||
1669 | } | |||
1670 | ||||
1671 | // shear? | |||
1672 | if(!basegfx::fTools::equalZero(fShearX)) | |||
1673 | { | |||
1674 | GeoStat aGeoStat; | |||
1675 | aGeoStat.nShearAngle = FRound(basegfx::rad2deg(atan(fShearX)) * 100.0); | |||
1676 | aGeoStat.RecalcTan(); | |||
1677 | Shear(Point(), aGeoStat.nShearAngle, aGeoStat.nTan, false); | |||
1678 | } | |||
1679 | ||||
1680 | // rotation? | |||
1681 | if(!basegfx::fTools::equalZero(fRotate)) | |||
1682 | { | |||
1683 | GeoStat aGeoStat; | |||
1684 | ||||
1685 | // #i78696# | |||
1686 | // fRotate is matematically correct, but aGeoStat.nRotationAngle is | |||
1687 | // mirrored -> mirror value here | |||
1688 | aGeoStat.nRotationAngle = NormAngle36000(FRound(-fRotate / F_PI18000(3.14159265358979323846/18000.0))); | |||
1689 | aGeoStat.RecalcSinCos(); | |||
1690 | Rotate(Point(), aGeoStat.nRotationAngle, aGeoStat.nSin, aGeoStat.nCos); | |||
1691 | } | |||
1692 | ||||
1693 | // translate? | |||
1694 | if(!aTranslate.equalZero()) | |||
1695 | { | |||
1696 | Move(Size(FRound(aTranslate.getX()), FRound(aTranslate.getY()))); | |||
1697 | } | |||
1698 | } | |||
1699 | ||||
1700 | bool SdrTextObj::IsReallyEdited() const | |||
1701 | { | |||
1702 | return pEdtOutl && pEdtOutl->IsModified(); | |||
1703 | } | |||
1704 | ||||
1705 | // moved inlines here form hxx | |||
1706 | ||||
1707 | long SdrTextObj::GetEckenradius() const | |||
1708 | { | |||
1709 | return GetObjectItemSet().Get(SDRATTR_ECKENRADIUS).GetValue(); | |||
1710 | } | |||
1711 | ||||
1712 | long SdrTextObj::GetMinTextFrameHeight() const | |||
1713 | { | |||
1714 | return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEHEIGHT).GetValue(); | |||
1715 | } | |||
1716 | ||||
1717 | long SdrTextObj::GetMaxTextFrameHeight() const | |||
1718 | { | |||
1719 | return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEHEIGHT).GetValue(); | |||
1720 | } | |||
1721 | ||||
1722 | long SdrTextObj::GetMinTextFrameWidth() const | |||
1723 | { | |||
1724 | return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEWIDTH).GetValue(); | |||
1725 | } | |||
1726 | ||||
1727 | long SdrTextObj::GetMaxTextFrameWidth() const | |||
1728 | { | |||
1729 | return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEWIDTH).GetValue(); | |||
1730 | } | |||
1731 | ||||
1732 | bool SdrTextObj::IsFontwork() const | |||
1733 | { | |||
1734 | return !bTextFrame // Default is FALSE | |||
1735 | && GetObjectItemSet().Get(XATTR_FORMTXTSTYLE).GetValue() != XFormTextStyle::NONE; | |||
1736 | } | |||
1737 | ||||
1738 | bool SdrTextObj::IsHideContour() const | |||
1739 | { | |||
1740 | return !bTextFrame // Default is: no, don't HideContour; HideContour not together with TextFrames | |||
1741 | && GetObjectItemSet().Get(XATTR_FORMTXTHIDEFORM).GetValue(); | |||
1742 | } | |||
1743 | ||||
1744 | bool SdrTextObj::IsContourTextFrame() const | |||
1745 | { | |||
1746 | return !bTextFrame // ContourFrame not together with normal TextFrames | |||
1747 | && GetObjectItemSet().Get(SDRATTR_TEXT_CONTOURFRAME).GetValue(); | |||
1748 | } | |||
1749 | ||||
1750 | long SdrTextObj::GetTextLeftDistance() const | |||
1751 | { | |||
1752 | return GetObjectItemSet().Get(SDRATTR_TEXT_LEFTDIST).GetValue(); | |||
1753 | } | |||
1754 | ||||
1755 | long SdrTextObj::GetTextRightDistance() const | |||
1756 | { | |||
1757 | return GetObjectItemSet().Get(SDRATTR_TEXT_RIGHTDIST).GetValue(); | |||
1758 | } | |||
1759 | ||||
1760 | long SdrTextObj::GetTextUpperDistance() const | |||
1761 | { | |||
1762 | return GetObjectItemSet().Get(SDRATTR_TEXT_UPPERDIST).GetValue(); | |||
1763 | } | |||
1764 | ||||
1765 | long SdrTextObj::GetTextLowerDistance() const | |||
1766 | { | |||
1767 | return GetObjectItemSet().Get(SDRATTR_TEXT_LOWERDIST).GetValue(); | |||
1768 | } | |||
1769 | ||||
1770 | SdrTextAniKind SdrTextObj::GetTextAniKind() const | |||
1771 | { | |||
1772 | return GetObjectItemSet().Get(SDRATTR_TEXT_ANIKIND).GetValue(); | |||
1773 | } | |||
1774 | ||||
1775 | SdrTextAniDirection SdrTextObj::GetTextAniDirection() const | |||
1776 | { | |||
1777 | return GetObjectItemSet().Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
1778 | } | |||
1779 | ||||
1780 | // Get necessary data for text scroll animation. ATM base it on a Text-Metafile and a | |||
1781 | // painting rectangle. Rotation is excluded from the returned values. | |||
1782 | GDIMetaFile* SdrTextObj::GetTextScrollMetaFileAndRectangle( | |||
1783 | tools::Rectangle& rScrollRectangle, tools::Rectangle& rPaintRectangle) | |||
1784 | { | |||
1785 | GDIMetaFile* pRetval = nullptr; | |||
1786 | SdrOutliner& rOutliner = ImpGetDrawOutliner(); | |||
1787 | tools::Rectangle aTextRect; | |||
1788 | tools::Rectangle aAnchorRect; | |||
1789 | tools::Rectangle aPaintRect; | |||
1790 | Fraction aFitXCorrection(1,1); | |||
1791 | bool bContourFrame(IsContourTextFrame()); | |||
1792 | ||||
1793 | // get outliner set up. To avoid getting a somehow rotated MetaFile, | |||
1794 | // temporarily disable object rotation. | |||
1795 | sal_Int32 nAngle(aGeo.nRotationAngle); | |||
1796 | aGeo.nRotationAngle = 0; | |||
1797 | ImpSetupDrawOutlinerForPaint( bContourFrame, rOutliner, aTextRect, aAnchorRect, aPaintRect, aFitXCorrection ); | |||
1798 | aGeo.nRotationAngle = nAngle; | |||
1799 | ||||
1800 | tools::Rectangle aScrollFrameRect(aPaintRect); | |||
1801 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
1802 | SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue(); | |||
1803 | ||||
1804 | if(SdrTextAniDirection::Left == eDirection || SdrTextAniDirection::Right == eDirection) | |||
| ||||
1805 | { | |||
1806 | aScrollFrameRect.SetLeft( aAnchorRect.Left() ); | |||
1807 | aScrollFrameRect.SetRight( aAnchorRect.Right() ); | |||
1808 | } | |||
1809 | ||||
1810 | if(SdrTextAniDirection::Up == eDirection || SdrTextAniDirection::Down == eDirection) | |||
1811 | { | |||
1812 | aScrollFrameRect.SetTop( aAnchorRect.Top() ); | |||
1813 | aScrollFrameRect.SetBottom( aAnchorRect.Bottom() ); | |||
1814 | } | |||
1815 | ||||
1816 | // create the MetaFile | |||
1817 | pRetval = new GDIMetaFile; | |||
1818 | ScopedVclPtrInstance< VirtualDevice > pBlackHole; | |||
1819 | pBlackHole->EnableOutput(false); | |||
1820 | pRetval->Record(pBlackHole); | |||
1821 | Point aPaintPos = aPaintRect.TopLeft(); | |||
1822 | ||||
1823 | rOutliner.Draw(pBlackHole, aPaintPos); | |||
1824 | ||||
1825 | pRetval->Stop(); | |||
1826 | pRetval->WindStart(); | |||
1827 | ||||
1828 | // return PaintRectanglePixel and pRetval; | |||
1829 | rScrollRectangle = aScrollFrameRect; | |||
1830 | rPaintRectangle = aPaintRect; | |||
1831 | ||||
1832 | return pRetval; | |||
1833 | } | |||
1834 | ||||
1835 | // Access to TextAnimationAllowed flag | |||
1836 | bool SdrTextObj::IsAutoFit() const | |||
1837 | { | |||
1838 | return GetFitToSize() == drawing::TextFitToSizeType_AUTOFIT; | |||
1839 | } | |||
1840 | ||||
1841 | bool SdrTextObj::IsFitToSize() const | |||
1842 | { | |||
1843 | const drawing::TextFitToSizeType eFit = GetFitToSize(); | |||
1844 | return (eFit == drawing::TextFitToSizeType_PROPORTIONAL | |||
1845 | || eFit == drawing::TextFitToSizeType_ALLLINES); | |||
1846 | } | |||
1847 | ||||
1848 | void SdrTextObj::SetTextAnimationAllowed(bool bNew) | |||
1849 | { | |||
1850 | if(mbTextAnimationAllowed != bNew) | |||
1851 | { | |||
1852 | mbTextAnimationAllowed = bNew; | |||
1853 | ActionChanged(); | |||
1854 | } | |||
1855 | } | |||
1856 | ||||
1857 | /** called from the SdrObjEditView during text edit when the status of the edit outliner changes */ | |||
1858 | void SdrTextObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus ) | |||
1859 | { | |||
1860 | const EditStatusFlags nStat = pEditStatus->GetStatusWord(); | |||
1861 | const bool bGrowX = bool(nStat & EditStatusFlags::TEXTWIDTHCHANGED); | |||
1862 | const bool bGrowY = bool(nStat & EditStatusFlags::TextHeightChanged); | |||
1863 | if(!(bTextFrame && (bGrowX || bGrowY))) | |||
1864 | return; | |||
1865 | ||||
1866 | if ((bGrowX && IsAutoGrowWidth()) || (bGrowY && IsAutoGrowHeight())) | |||
1867 | { | |||
1868 | AdjustTextFrameWidthAndHeight(); | |||
1869 | } | |||
1870 | else if ( (IsAutoFit() || IsFitToSize()) && !mbInDownScale) | |||
1871 | { | |||
1872 | assert(pEdtOutl)(static_cast <bool> (pEdtOutl) ? void (0) : __assert_fail ("pEdtOutl", "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" , 1872, __extension__ __PRETTY_FUNCTION__)); | |||
1873 | mbInDownScale = true; | |||
1874 | ||||
1875 | // sucks that we cannot disable paints via | |||
1876 | // pEdtOutl->SetUpdateMode(FALSE) - but EditEngine skips | |||
1877 | // formatting as well, then. | |||
1878 | ImpAutoFitText(*pEdtOutl); | |||
1879 | mbInDownScale = false; | |||
1880 | } | |||
1881 | } | |||
1882 | ||||
1883 | /* Begin chaining code */ | |||
1884 | ||||
1885 | // XXX: Make it a method somewhere? | |||
1886 | static SdrObject *ImpGetObjByName(SdrObjList const *pObjList, OUString const& aObjName) | |||
1887 | { | |||
1888 | // scan the whole list | |||
1889 | size_t nObjCount = pObjList->GetObjCount(); | |||
1890 | for (size_t i = 0; i < nObjCount; i++) { | |||
1891 | SdrObject *pCurObj = pObjList->GetObj(i); | |||
1892 | ||||
1893 | if (pCurObj->GetName() == aObjName) { | |||
1894 | return pCurObj; | |||
1895 | } | |||
1896 | } | |||
1897 | // not found | |||
1898 | return nullptr; | |||
1899 | } | |||
1900 | ||||
1901 | // XXX: Make it a (private) method of SdrTextObj | |||
1902 | static void ImpUpdateChainLinks(SdrTextObj *pTextObj, OUString const& aNextLinkName) | |||
1903 | { | |||
1904 | // XXX: Current implementation constraints text boxes to be on the same page | |||
1905 | ||||
1906 | // No next link | |||
1907 | if (aNextLinkName.isEmpty()) { | |||
1908 | pTextObj->SetNextLinkInChain(nullptr); | |||
1909 | return; | |||
1910 | } | |||
1911 | ||||
1912 | SdrPage *pPage(pTextObj->getSdrPageFromSdrObject()); | |||
1913 | assert(pPage)(static_cast <bool> (pPage) ? void (0) : __assert_fail ( "pPage", "/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" , 1913, __extension__ __PRETTY_FUNCTION__)); | |||
1914 | SdrTextObj *pNextTextObj = dynamic_cast< SdrTextObj * > | |||
1915 | (ImpGetObjByName(pPage, aNextLinkName)); | |||
1916 | if (!pNextTextObj) { | |||
1917 | SAL_INFO("svx.chaining", "[CHAINING] Can't find object as next link.")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "[CHAINING] Can't find object as next link." ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1917" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Can't find object as next link." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Can't find object as next link."; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1917" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "[CHAINING] Can't find object as next link.") == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1917" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Can't find object as next link." ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Can't find object as next link."; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1917" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1918 | return; | |||
1919 | } | |||
1920 | ||||
1921 | pTextObj->SetNextLinkInChain(pNextTextObj); | |||
1922 | } | |||
1923 | ||||
1924 | bool SdrTextObj::IsChainable() const | |||
1925 | { | |||
1926 | // Read it as item | |||
1927 | const SfxItemSet& rSet = GetObjectItemSet(); | |||
1928 | OUString aNextLinkName = rSet.Get(SDRATTR_TEXT_CHAINNEXTNAME).GetValue(); | |||
1929 | ||||
1930 | // Update links if any inconsistency is found | |||
1931 | bool bNextLinkUnsetYet = !aNextLinkName.isEmpty() && !mpNextInChain; | |||
1932 | bool bInconsistentNextLink = mpNextInChain && mpNextInChain->GetName() != aNextLinkName; | |||
1933 | // if the link is not set despite there should be one OR if it has changed | |||
1934 | if (bNextLinkUnsetYet || bInconsistentNextLink) { | |||
1935 | ImpUpdateChainLinks(const_cast<SdrTextObj *>(this), aNextLinkName); | |||
1936 | } | |||
1937 | ||||
1938 | return !aNextLinkName.isEmpty(); // XXX: Should we also check for GetNilChainingEvent? (see old code below) | |||
1939 | ||||
1940 | /* | |||
1941 | // Check that no overflow is going on | |||
1942 | if (!GetTextChain() || GetTextChain()->GetNilChainingEvent(this)) | |||
1943 | return false; | |||
1944 | */ | |||
1945 | } | |||
1946 | ||||
1947 | void SdrTextObj::onChainingEvent() | |||
1948 | { | |||
1949 | if (!pEdtOutl) | |||
1950 | return; | |||
1951 | ||||
1952 | // Outliner for text transfer | |||
1953 | SdrOutliner &aDrawOutliner = ImpGetDrawOutliner(); | |||
1954 | ||||
1955 | EditingTextChainFlow aTxtChainFlow(this); | |||
1956 | aTxtChainFlow.CheckForFlowEvents(pEdtOutl); | |||
1957 | ||||
1958 | if (aTxtChainFlow.IsOverflow()) { | |||
1959 | SAL_INFO("svx.chaining", "[CHAINING] Overflow going on")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "[CHAINING] Overflow going on" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1959" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Overflow going on"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Overflow going on"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1959" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "[CHAINING] Overflow going on") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1959" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Overflow going on"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Overflow going on"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1959" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1960 | // One outliner is for non-overflowing text, the other for overflowing text | |||
1961 | // We remove text directly from the editing outliner | |||
1962 | aTxtChainFlow.ExecuteOverflow(pEdtOutl, &aDrawOutliner); | |||
1963 | } else if (aTxtChainFlow.IsUnderflow()) { | |||
1964 | SAL_INFO("svx.chaining", "[CHAINING] Underflow going on")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "[CHAINING] Underflow going on" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1964" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Underflow going on"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Underflow going on"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1964" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "[CHAINING] Underflow going on") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1964" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Underflow going on"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Underflow going on"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1964" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1965 | // underflow-induced overflow | |||
1966 | aTxtChainFlow.ExecuteUnderflow(&aDrawOutliner); | |||
1967 | bool bIsOverflowFromUnderflow = aTxtChainFlow.IsOverflow(); | |||
1968 | // handle overflow | |||
1969 | if (bIsOverflowFromUnderflow) { | |||
1970 | SAL_INFO("svx.chaining", "[CHAINING] Overflow going on (underflow induced)")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "svx.chaining")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "[CHAINING] Overflow going on (underflow induced)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1970" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Overflow going on (underflow induced)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Overflow going on (underflow induced)"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1970" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "[CHAINING] Overflow going on (underflow induced)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1970" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "[CHAINING] Overflow going on (underflow induced)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "[CHAINING] Overflow going on (underflow induced)"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svx.chaining" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdotext.cxx" ":" "1970" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1971 | // prevents infinite loops when setting text for editing outliner | |||
1972 | aTxtChainFlow.ExecuteOverflow(&aDrawOutliner, &aDrawOutliner); | |||
1973 | } | |||
1974 | } | |||
1975 | } | |||
1976 | ||||
1977 | SdrTextObj* SdrTextObj::GetNextLinkInChain() const | |||
1978 | { | |||
1979 | /* | |||
1980 | if (GetTextChain()) | |||
1981 | return GetTextChain()->GetNextLink(this); | |||
1982 | ||||
1983 | return NULL; | |||
1984 | */ | |||
1985 | ||||
1986 | return mpNextInChain; | |||
1987 | } | |||
1988 | ||||
1989 | void SdrTextObj::SetNextLinkInChain(SdrTextObj *pNextObj) | |||
1990 | { | |||
1991 | // Basically a doubly linked list implementation | |||
1992 | ||||
1993 | SdrTextObj *pOldNextObj = mpNextInChain; | |||
1994 | ||||
1995 | // Replace next link | |||
1996 | mpNextInChain = pNextObj; | |||
1997 | // Deal with old next link's prev link | |||
1998 | if (pOldNextObj) { | |||
1999 | pOldNextObj->mpPrevInChain = nullptr; | |||
2000 | } | |||
2001 | ||||
2002 | // Deal with new next link's prev link | |||
2003 | if (mpNextInChain) { | |||
2004 | // If there is a prev already at all and this is not already the current object | |||
2005 | if (mpNextInChain->mpPrevInChain && | |||
2006 | mpNextInChain->mpPrevInChain != this) | |||
2007 | mpNextInChain->mpPrevInChain->mpNextInChain = nullptr; | |||
2008 | mpNextInChain->mpPrevInChain = this; | |||
2009 | } | |||
2010 | ||||
2011 | // TODO: Introduce check for circular chains | |||
2012 | ||||
2013 | } | |||
2014 | ||||
2015 | SdrTextObj* SdrTextObj::GetPrevLinkInChain() const | |||
2016 | { | |||
2017 | /* | |||
2018 | if (GetTextChain()) | |||
2019 | return GetTextChain()->GetPrevLink(this); | |||
2020 | ||||
2021 | return NULL; | |||
2022 | */ | |||
2023 | ||||
2024 | return mpPrevInChain; | |||
2025 | } | |||
2026 | ||||
2027 | bool SdrTextObj::GetPreventChainable() const | |||
2028 | { | |||
2029 | // Prevent chaining it 1) during dragging && 2) when we are editing next link | |||
2030 | return mbIsUnchainableClone || (GetNextLinkInChain() && GetNextLinkInChain()->IsInEditMode()); | |||
2031 | } | |||
2032 | ||||
2033 | SdrObjectUniquePtr SdrTextObj::getFullDragClone() const | |||
2034 | { | |||
2035 | SdrObjectUniquePtr pClone = SdrAttrObj::getFullDragClone(); | |||
2036 | SdrTextObj *pTextObjClone = dynamic_cast<SdrTextObj *>(pClone.get()); | |||
2037 | if (pTextObjClone != nullptr) { | |||
2038 | // Avoid transferring of text for chainable object during dragging | |||
2039 | pTextObjClone->mbIsUnchainableClone = true; | |||
2040 | } | |||
2041 | ||||
2042 | return pClone; | |||
2043 | } | |||
2044 | ||||
2045 | /* End chaining code */ | |||
2046 | ||||
2047 | /** returns the currently active text. */ | |||
2048 | SdrText* SdrTextObj::getActiveText() const | |||
2049 | { | |||
2050 | if( !mpText ) | |||
2051 | return getText( 0 ); | |||
2052 | else | |||
2053 | return mpText.get(); | |||
2054 | } | |||
2055 | ||||
2056 | /** returns the nth available text. */ | |||
2057 | SdrText* SdrTextObj::getText( sal_Int32 nIndex ) const | |||
2058 | { | |||
2059 | if( nIndex == 0 ) | |||
2060 | { | |||
2061 | if( !mpText ) | |||
2062 | const_cast< SdrTextObj* >(this)->mpText.reset( new SdrText( *const_cast< SdrTextObj* >(this) ) ); | |||
2063 | return mpText.get(); | |||
2064 | } | |||
2065 | else | |||
2066 | { | |||
2067 | return nullptr; | |||
2068 | } | |||
2069 | } | |||
2070 | ||||
2071 | /** returns the number of texts available for this object. */ | |||
2072 | sal_Int32 SdrTextObj::getTextCount() const | |||
2073 | { | |||
2074 | return 1; | |||
2075 | } | |||
2076 | ||||
2077 | /** changes the current active text */ | |||
2078 | void SdrTextObj::setActiveText( sal_Int32 /*nIndex*/ ) | |||
2079 | { | |||
2080 | } | |||
2081 | ||||
2082 | /** returns the index of the text that contains the given point or -1 */ | |||
2083 | sal_Int32 SdrTextObj::CheckTextHit(const Point& /*rPnt*/) const | |||
2084 | { | |||
2085 | return 0; | |||
2086 | } | |||
2087 | ||||
2088 | void SdrTextObj::SetObjectItemNoBroadcast(const SfxPoolItem& rItem) | |||
2089 | { | |||
2090 | static_cast< sdr::properties::TextProperties& >(GetProperties()).SetObjectItemNoBroadcast(rItem); | |||
2091 | } | |||
2092 | ||||
2093 | ||||
2094 | // The concept of the text object: | |||
2095 | // ~~~~~~~~~~~~~~~~~~~~~~~~ | |||
2096 | // Attributes/Variations: | |||
2097 | // - bool text frame / graphics object with caption | |||
2098 | // - bool FontWork (if it is not a text frame and not a ContourTextFrame) | |||
2099 | // - bool ContourTextFrame (if it is not a text frame and not Fontwork) | |||
2100 | // - long rotation angle (if it is not FontWork) | |||
2101 | // - long text frame margins (if it is not FontWork) | |||
2102 | // - bool FitToSize (if it is not FontWork) | |||
2103 | // - bool AutoGrowingWidth/Height (if it is not FitToSize and not FontWork) | |||
2104 | // - long Min/MaxFrameWidth/Height (if AutoGrowingWidth/Height) | |||
2105 | // - enum horizontal text anchoring left,center,right,justify/block,Stretch(ni) | |||
2106 | // - enum vertical text anchoring top, middle, bottom, block, stretch(ni) | |||
2107 | // - enum ticker text (if it is not FontWork) | |||
2108 | ||||
2109 | // Every derived object is either a text frame (bTextFrame=true) | |||
2110 | // or a drawing object with a caption (bTextFrame=false). | |||
2111 | ||||
2112 | // Default anchoring for text frames: | |||
2113 | // SDRTEXTHORZADJUST_BLOCK, SDRTEXTVERTADJUST_TOP | |||
2114 | // = static Pool defaults | |||
2115 | // Default anchoring for drawing objects with a caption: | |||
2116 | // SDRTEXTHORZADJUST_CENTER, SDRTEXTVERTADJUST_CENTER | |||
2117 | // via "hard" attribution of SdrAttrObj | |||
2118 | ||||
2119 | // Every object derived from SdrTextObj must return an "UnrotatedSnapRect" | |||
2120 | // (->TakeUnrotatedSnapRect()) (the reference point for the rotation is the top | |||
2121 | // left of the rectangle (aGeo.nRotationAngle)) which is the basis for anchoring | |||
2122 | // text. We then subtract the text frame margins from this rectangle, as a re- | |||
2123 | // sult we get the anchoring area (->TakeTextAnchorRect()). Within this area, we | |||
2124 | // calculate the anchoring point and the painting area, depending on the hori- | |||
2125 | // zontal and vertical adjustment of the text (SdrTextVertAdjust, | |||
2126 | // SdrTextHorzAdjust). | |||
2127 | // In the case of drawing objects with a caption the painting area might well | |||
2128 | // be larger than the anchoring area, for text frames on the other hand, it is | |||
2129 | // always of the same or a smaller size (except when there are negative text | |||
2130 | // frame margins). | |||
2131 | ||||
2132 | // FitToSize takes priority over text anchoring and AutoGrowHeight/Width. When | |||
2133 | // FitToSize is turned on, the painting area is always equal to the anchoring | |||
2134 | // area. Additionally, FitToSize doesn't allow automatic line breaks. | |||
2135 | ||||
2136 | // ContourTextFrame: | |||
2137 | // - long rotation angle | |||
2138 | // - long text frame margins (maybe later) | |||
2139 | // - bool FitToSize (maybe later) | |||
2140 | // - bool AutoGrowingWidth/Height (maybe much later) | |||
2141 | // - long Min/MaxFrameWidth/Height (maybe much later) | |||
2142 | // - enum horizontal text anchoring (maybe later, for now: left, centered) | |||
2143 | // - enum vertical text anchoring (maybe later, for now: top) | |||
2144 | // - enum ticker text (maybe later, maybe even with correct clipping) | |||
2145 | ||||
2146 | // When making changes, check these: | |||
2147 | // - Paint | |||
2148 | // - HitTest | |||
2149 | // - ConvertToPoly | |||
2150 | // - Edit | |||
2151 | // - Printing, Saving, Painting in neighboring View while editing | |||
2152 | // - ModelChanged (e. g. through a neighboring View or rulers) while editing | |||
2153 | // - FillColorChanged while editing | |||
2154 | // - and many more... | |||
2155 | ||||
2156 | ||||
2157 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
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/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
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 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_VCL_PTR_HXX |
21 | #define INCLUDED_VCL_PTR_HXX |
22 | |
23 | #include <sal/config.h> |
24 | |
25 | #include <rtl/ref.hxx> |
26 | |
27 | #include <utility> |
28 | #include <type_traits> |
29 | |
30 | #ifdef DBG_UTIL |
31 | #ifndef _WIN32 |
32 | #include <vcl/vclmain.hxx> |
33 | #endif |
34 | #endif |
35 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase( |
44 | int (*)[sizeof(T)]) |
45 | { return std::is_base_of<VclReferenceBase, T>::value; } |
46 | |
47 | } // namespace vcl::detail |
48 | |
49 | /** |
50 | * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses. |
51 | * |
52 | * For more details on the design please see vcl/README.lifecycle |
53 | * |
54 | * @param reference_type must be a subclass of vcl::Window |
55 | */ |
56 | template <class reference_type> |
57 | class VclPtr |
58 | { |
59 | static_assert( |
60 | vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>( |
61 | nullptr), |
62 | "template argument type must be derived from VclReferenceBase"); |
63 | |
64 | ::rtl::Reference<reference_type> m_rInnerRef; |
65 | |
66 | public: |
67 | /** Constructor... |
68 | */ |
69 | VclPtr() |
70 | : m_rInnerRef() |
71 | {} |
72 | |
73 | /** Constructor... |
74 | */ |
75 | VclPtr (reference_type * pBody) |
76 | : m_rInnerRef(pBody) |
77 | {} |
78 | |
79 | /** Constructor... that doesn't take a ref. |
80 | */ |
81 | VclPtr (reference_type * pBody, __sal_NoAcquire) |
82 | : m_rInnerRef(pBody, SAL_NO_ACQUIRE) |
83 | {} |
84 | |
85 | /** Up-casting conversion constructor: Copies interface reference. |
86 | |
87 | Does not work for up-casts to ambiguous bases. For the special case of |
88 | up-casting to Reference< XInterface >, see the corresponding conversion |
89 | operator. |
90 | |
91 | @param rRef another reference |
92 | */ |
93 | template< class derived_type > |
94 | VclPtr( |
95 | const VclPtr< derived_type > & rRef, |
96 | typename std::enable_if< |
97 | std::is_base_of<reference_type, derived_type>::value, int>::type |
98 | = 0 ) |
99 | : m_rInnerRef( static_cast<reference_type*>(rRef) ) |
100 | { |
101 | } |
102 | |
103 | #if defined(DBG_UTIL) && !defined(_WIN32) |
104 | virtual ~VclPtr() |
105 | { |
106 | assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain ::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 106, __extension__ __PRETTY_FUNCTION__)); |
107 | // We can be one of the intermediate counts, but if we are the last |
108 | // VclPtr keeping this object alive, then something forgot to call dispose(). |
109 | assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)) |
110 | && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)); |
111 | } |
112 | VclPtr(VclPtr const &) = default; |
113 | VclPtr(VclPtr &&) = default; |
114 | VclPtr & operator =(VclPtr const &) = default; |
115 | VclPtr & operator =(VclPtr &&) = default; |
116 | #endif |
117 | |
118 | /** |
119 | * A construction helper for VclPtr. Since VclPtr types are created |
120 | * with a reference-count of one - to help fit into the existing |
121 | * code-flow; this helps us to construct them easily. |
122 | * |
123 | * For more details on the design please see vcl/README.lifecycle |
124 | * |
125 | * @tparam reference_type must be a subclass of vcl::Window |
126 | */ |
127 | template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg) |
128 | { |
129 | return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ); |
130 | } |
131 | |
132 | /** Probably most common used: handle->someBodyOp(). |
133 | */ |
134 | reference_type * operator->() const |
135 | { |
136 | return m_rInnerRef.get(); |
137 | } |
138 | |
139 | /** Get the body. Can be used instead of operator->(). |
140 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() |
141 | are the same. |
142 | */ |
143 | reference_type * get() const |
144 | { |
145 | return m_rInnerRef.get(); |
146 | } |
147 | |
148 | void set(reference_type *pBody) |
149 | { |
150 | m_rInnerRef.set(pBody); |
151 | } |
152 | |
153 | void reset(reference_type *pBody) |
154 | { |
155 | m_rInnerRef.set(pBody); |
156 | } |
157 | |
158 | /** Up-casting copy assignment operator. |
159 | |
160 | Does not work for up-casts to ambiguous bases. |
161 | |
162 | @param rRef another reference |
163 | */ |
164 | template<typename derived_type> |
165 | typename std::enable_if< |
166 | std::is_base_of<reference_type, derived_type>::value, |
167 | VclPtr &>::type |
168 | operator =(VclPtr<derived_type> const & rRef) |
169 | { |
170 | m_rInnerRef.set(rRef.get()); |
171 | return *this; |
172 | } |
173 | |
174 | VclPtr & operator =(reference_type * pBody) |
175 | { |
176 | m_rInnerRef.set(pBody); |
177 | return *this; |
178 | } |
179 | |
180 | operator reference_type * () const |
181 | { |
182 | return m_rInnerRef.get(); |
183 | } |
184 | |
185 | explicit operator bool () const |
186 | { |
187 | return m_rInnerRef.get() != nullptr; |
188 | } |
189 | |
190 | void clear() |
191 | { |
192 | m_rInnerRef.clear(); |
193 | } |
194 | |
195 | void reset() |
196 | { |
197 | m_rInnerRef.clear(); |
198 | } |
199 | |
200 | void disposeAndClear() |
201 | { |
202 | // hold it alive for the lifetime of this method |
203 | ::rtl::Reference<reference_type> aTmp(m_rInnerRef); |
204 | m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-) |
205 | if (aTmp.get()) { |
206 | aTmp->disposeOnce(); |
207 | } |
208 | } |
209 | |
210 | /** Needed to place VclPtr's into STL collection. |
211 | */ |
212 | bool operator< (const VclPtr<reference_type> & handle) const |
213 | { |
214 | return (m_rInnerRef < handle.m_rInnerRef); |
215 | } |
216 | }; // class VclPtr |
217 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) { |
261 | return !(p1 == p2); |
262 | } |
263 | |
264 | /** |
265 | * A construction helper for a temporary VclPtr. Since VclPtr types |
266 | * are created with a reference-count of one - to help fit into |
267 | * the existing code-flow; this helps us to construct them easily. |
268 | * see also VclPtr::Create and ScopedVclPtr |
269 | * |
270 | * For more details on the design please see vcl/README.lifecycle |
271 | * |
272 | * @param reference_type must be a subclass of vcl::Window |
273 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
278 | template<typename... Arg> VclPtrInstance(Arg &&... arg) |
279 | : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
280 | { |
281 | } |
282 | |
283 | /** |
284 | * Override and disallow this, to prevent people accidentally calling it and actually |
285 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
286 | */ |
287 | template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete; |
288 | }; |
289 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
294 | /** Constructor... |
295 | */ |
296 | ScopedVclPtr() |
297 | : VclPtr<reference_type>() |
298 | {} |
299 | |
300 | /** Constructor |
301 | */ |
302 | ScopedVclPtr (reference_type * pBody) |
303 | : VclPtr<reference_type>(pBody) |
304 | {} |
305 | |
306 | /** Copy constructor... |
307 | */ |
308 | ScopedVclPtr (const VclPtr<reference_type> & handle) |
309 | : VclPtr<reference_type>(handle) |
310 | {} |
311 | |
312 | /** |
313 | Assignment that releases the last reference. |
314 | */ |
315 | void disposeAndReset(reference_type *pBody) |
316 | { |
317 | if (pBody != this->get()) { |
318 | VclPtr<reference_type>::disposeAndClear(); |
319 | VclPtr<reference_type>::set(pBody); |
320 | } |
321 | } |
322 | |
323 | /** |
324 | Assignment that releases the last reference. |
325 | */ |
326 | ScopedVclPtr<reference_type>& operator = (reference_type * pBody) |
327 | { |
328 | disposeAndReset(pBody); |
329 | return *this; |
330 | } |
331 | |
332 | /** Up-casting conversion constructor: Copies interface reference. |
333 | |
334 | Does not work for up-casts to ambiguous bases. For the special case of |
335 | up-casting to Reference< XInterface >, see the corresponding conversion |
336 | operator. |
337 | |
338 | @param rRef another reference |
339 | */ |
340 | template< class derived_type > |
341 | ScopedVclPtr( |
342 | const VclPtr< derived_type > & rRef, |
343 | typename std::enable_if< |
344 | std::is_base_of<reference_type, derived_type>::value, int>::type |
345 | = 0 ) |
346 | : VclPtr<reference_type>( rRef ) |
347 | { |
348 | } |
349 | |
350 | /** Up-casting assignment operator. |
351 | |
352 | Does not work for up-casts to ambiguous bases. |
353 | |
354 | @param rRef another VclPtr |
355 | */ |
356 | template<typename derived_type> |
357 | typename std::enable_if< |
358 | std::is_base_of<reference_type, derived_type>::value, |
359 | ScopedVclPtr &>::type |
360 | operator =(VclPtr<derived_type> const & rRef) |
361 | { |
362 | disposeAndReset(rRef.get()); |
363 | return *this; |
364 | } |
365 | |
366 | /** |
367 | * Override and disallow this, to prevent people accidentally calling it and actually |
368 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
369 | */ |
370 | template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete; |
371 | |
372 | ~ScopedVclPtr() |
373 | { |
374 | VclPtr<reference_type>::disposeAndClear(); |
375 | assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get( ) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 375, __extension__ __PRETTY_FUNCTION__)); // make sure there are no lingering references |
376 | } |
377 | |
378 | private: |
379 | // Most likely we don't want this default copy-constructor. |
380 | ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete; |
381 | // And certainly we don't want a default assignment operator. |
382 | ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete; |
383 | // And disallow reset as that doesn't call disposeAndClear on the original reference |
384 | void reset() = delete; |
385 | void reset(reference_type *pBody) = delete; |
386 | |
387 | protected: |
388 | ScopedVclPtr (reference_type * pBody, __sal_NoAcquire) |
389 | : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE) |
390 | {} |
391 | }; |
392 | |
393 | /** |
394 | * A construction helper for ScopedVclPtr. Since VclPtr types are created |
395 | * with a reference-count of one - to help fit into the existing |
396 | * code-flow; this helps us to construct them easily. |
397 | * |
398 | * For more details on the design please see vcl/README.lifecycle |
399 | * |
400 | * @param reference_type must be a subclass of vcl::Window |
401 | */ |
402 | #if defined _MSC_VER |
403 | #pragma warning(push) |
404 | #pragma warning(disable: 4521) // " multiple copy constructors specified" |
405 | #endif |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
410 | template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg) |
411 | : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
412 | { |
413 | } |
414 | |
415 | /** |
416 | * Override and disallow this, to prevent people accidentally calling it and actually |
417 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
418 | */ |
419 | template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete; |
420 | |
421 | private: |
422 | // Prevent the above perfect forwarding ctor from hijacking (accidental) |
423 | // attempts at ScopedVclPtrInstance copy construction (where the hijacking |
424 | // would typically lead to somewhat obscure error messages); both non-const |
425 | // and const variants are needed here, as the ScopedVclPtr base class has a |
426 | // const--variant copy ctor, so the implicitly declared copy ctor for |
427 | // ScopedVclPtrInstance would also be the const variant, so non-const copy |
428 | // construction attempts would be hijacked by the perfect forwarding ctor; |
429 | // but if we only declared a non-const variant here, the const variant would |
430 | // no longer be implicitly declared (as there would already be an explicitly |
431 | // declared copy ctor), so const copy construction attempts would then be |
432 | // hijacked by the perfect forwarding ctor: |
433 | ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete; |
434 | ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete; |
435 | }; |
436 | #if defined _MSC_VER |
437 | #pragma warning(pop) |
438 | #endif |
439 | |
440 | #endif // INCLUDED_VCL_PTR_HXX |
441 | |
442 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||||||
2 | /* | ||||||||
3 | * This file is part of the LibreOffice project. | ||||||||
4 | * | ||||||||
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/. | ||||||||
8 | * | ||||||||
9 | * This file incorporates work covered by the following license notice: | ||||||||
10 | * | ||||||||
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 . | ||||||||
18 | */ | ||||||||
19 | |||||||||
20 | #ifndef INCLUDED_RTL_REF_HXX | ||||||||
21 | #define INCLUDED_RTL_REF_HXX | ||||||||
22 | |||||||||
23 | #include "sal/config.h" | ||||||||
24 | |||||||||
25 | #include <cassert> | ||||||||
26 | #include <cstddef> | ||||||||
27 | #include <functional> | ||||||||
28 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
29 | #include <type_traits> | ||||||||
30 | #endif | ||||||||
31 | |||||||||
32 | #include "sal/types.h" | ||||||||
33 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
48 | /** Constructor... | ||||||||
49 | */ | ||||||||
50 | Reference() | ||||||||
51 | : m_pBody (NULL__null) | ||||||||
52 | {} | ||||||||
53 | |||||||||
54 | |||||||||
55 | /** Constructor... | ||||||||
56 | */ | ||||||||
57 | Reference (reference_type * pBody, __sal_NoAcquire) | ||||||||
58 | : m_pBody (pBody) | ||||||||
59 | { | ||||||||
60 | } | ||||||||
61 | |||||||||
62 | /** Constructor... | ||||||||
63 | */ | ||||||||
64 | Reference (reference_type * pBody) | ||||||||
65 | : m_pBody (pBody) | ||||||||
66 | { | ||||||||
67 | if (m_pBody) | ||||||||
68 | m_pBody->acquire(); | ||||||||
69 | } | ||||||||
70 | |||||||||
71 | /** Copy constructor... | ||||||||
72 | */ | ||||||||
73 | Reference (const Reference<reference_type> & handle) | ||||||||
74 | : m_pBody (handle.m_pBody) | ||||||||
75 | { | ||||||||
76 | if (m_pBody) | ||||||||
77 | m_pBody->acquire(); | ||||||||
78 | } | ||||||||
79 | |||||||||
80 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
81 | /** Move constructor... | ||||||||
82 | */ | ||||||||
83 | Reference (Reference<reference_type> && handle) noexcept | ||||||||
84 | : m_pBody (handle.m_pBody) | ||||||||
85 | { | ||||||||
86 | handle.m_pBody = nullptr; | ||||||||
87 | } | ||||||||
88 | #endif | ||||||||
89 | |||||||||
90 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
91 | /** Up-casting conversion constructor: Copies interface reference. | ||||||||
92 | |||||||||
93 | Does not work for up-casts to ambiguous bases. | ||||||||
94 | |||||||||
95 | @param rRef another reference | ||||||||
96 | */ | ||||||||
97 | template< class derived_type > | ||||||||
98 | inline Reference( | ||||||||
99 | const Reference< derived_type > & rRef, | ||||||||
100 | std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 ) | ||||||||
101 | : m_pBody (rRef.get()) | ||||||||
102 | { | ||||||||
103 | if (m_pBody) | ||||||||
104 | m_pBody->acquire(); | ||||||||
105 | } | ||||||||
106 | #endif | ||||||||
107 | |||||||||
108 | /** Destructor... | ||||||||
109 | */ | ||||||||
110 | ~Reference() COVERITY_NOEXCEPT_FALSE | ||||||||
111 | { | ||||||||
112 | if (m_pBody) | ||||||||
113 | m_pBody->release(); | ||||||||
114 | } | ||||||||
115 | |||||||||
116 | /** Set... | ||||||||
117 | Similar to assignment. | ||||||||
118 | */ | ||||||||
119 | Reference<reference_type> & | ||||||||
120 | SAL_CALL set (reference_type * pBody) | ||||||||
121 | { | ||||||||
122 | if (pBody) | ||||||||
123 | pBody->acquire(); | ||||||||
124 | reference_type * const pOld = m_pBody; | ||||||||
125 | m_pBody = pBody; | ||||||||
126 | if (pOld) | ||||||||
127 | pOld->release(); | ||||||||
128 | return *this; | ||||||||
129 | } | ||||||||
130 | |||||||||
131 | /** Assignment. | ||||||||
132 | Unbinds this instance from its body (if bound) and | ||||||||
133 | bind it to the body represented by the handle. | ||||||||
134 | */ | ||||||||
135 | Reference<reference_type> & | ||||||||
136 | SAL_CALL operator= (const Reference<reference_type> & handle) | ||||||||
137 | { | ||||||||
138 | return set( handle.m_pBody ); | ||||||||
139 | } | ||||||||
140 | |||||||||
141 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
142 | /** Assignment. | ||||||||
143 | * Unbinds this instance from its body (if bound), | ||||||||
144 | * bind it to the body represented by the handle, and | ||||||||
145 | * set the body represented by the handle to nullptr. | ||||||||
146 | */ | ||||||||
147 | Reference<reference_type> & | ||||||||
148 | operator= (Reference<reference_type> && handle) | ||||||||
149 | { | ||||||||
150 | // self-movement guts ourself | ||||||||
151 | if (m_pBody) | ||||||||
152 | m_pBody->release(); | ||||||||
153 | m_pBody = handle.m_pBody; | ||||||||
154 | handle.m_pBody = nullptr; | ||||||||
155 | return *this; | ||||||||
156 | } | ||||||||
157 | #endif | ||||||||
158 | |||||||||
159 | /** Assignment... | ||||||||
160 | */ | ||||||||
161 | Reference<reference_type> & | ||||||||
162 | SAL_CALL operator= (reference_type * pBody) | ||||||||
163 | { | ||||||||
164 | return set( pBody ); | ||||||||
165 | } | ||||||||
166 | |||||||||
167 | /** Unbind the body from this handle. | ||||||||
168 | Note that for a handle representing a large body, | ||||||||
169 | "handle.clear().set(new body());" _might_ | ||||||||
170 | perform a little bit better than "handle.set(new body());", | ||||||||
171 | since in the second case two large objects exist in memory | ||||||||
172 | (the old body and the new body). | ||||||||
173 | */ | ||||||||
174 | Reference<reference_type> & SAL_CALL clear() | ||||||||
175 | { | ||||||||
176 | if (m_pBody
| ||||||||
177 | { | ||||||||
178 | reference_type * const pOld = m_pBody; | ||||||||
179 | m_pBody = NULL__null; | ||||||||
180 | pOld->release(); | ||||||||
181 | } | ||||||||
182 | return *this; | ||||||||
183 | } | ||||||||
184 | |||||||||
185 | |||||||||
186 | /** Get the body. Can be used instead of operator->(). | ||||||||
187 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() | ||||||||
188 | are the same. | ||||||||
189 | */ | ||||||||
190 | reference_type * SAL_CALL get() const | ||||||||
191 | { | ||||||||
192 | return m_pBody; | ||||||||
| |||||||||
193 | } | ||||||||
194 | |||||||||
195 | |||||||||
196 | /** Probably most common used: handle->someBodyOp(). | ||||||||
197 | */ | ||||||||
198 | reference_type * SAL_CALL operator->() const | ||||||||
199 | { | ||||||||
200 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 200, __extension__ __PRETTY_FUNCTION__)); | ||||||||
201 | return m_pBody; | ||||||||
202 | } | ||||||||
203 | |||||||||
204 | |||||||||
205 | /** Allows (*handle).someBodyOp(). | ||||||||
206 | */ | ||||||||
207 | reference_type & SAL_CALL operator*() const | ||||||||
208 | { | ||||||||
209 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 209, __extension__ __PRETTY_FUNCTION__)); | ||||||||
210 | return *m_pBody; | ||||||||
211 | } | ||||||||
212 | |||||||||
213 | |||||||||
214 | /** Returns True if the handle does point to a valid body. | ||||||||
215 | */ | ||||||||
216 | bool SAL_CALL is() const | ||||||||
217 | { | ||||||||
218 | return (m_pBody != NULL__null); | ||||||||
219 | } | ||||||||
220 | |||||||||
221 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
222 | /** Returns True if the handle does point to a valid body. | ||||||||
223 | */ | ||||||||
224 | explicit operator bool() const | ||||||||
225 | { | ||||||||
226 | return is(); | ||||||||
227 | } | ||||||||
228 | #endif | ||||||||
229 | |||||||||
230 | /** Returns True if this points to pBody. | ||||||||
231 | */ | ||||||||
232 | bool SAL_CALL operator== (const reference_type * pBody) const | ||||||||
233 | { | ||||||||
234 | return (m_pBody == pBody); | ||||||||
235 | } | ||||||||
236 | |||||||||
237 | |||||||||
238 | /** Returns True if handle points to the same body. | ||||||||
239 | */ | ||||||||
240 | bool | ||||||||
241 | SAL_CALL operator== (const Reference<reference_type> & handle) const | ||||||||
242 | { | ||||||||
243 | return (m_pBody == handle.m_pBody); | ||||||||
244 | } | ||||||||
245 | |||||||||
246 | |||||||||
247 | /** Needed to place References into STL collection. | ||||||||
248 | */ | ||||||||
249 | bool | ||||||||
250 | SAL_CALL operator!= (const Reference<reference_type> & handle) const | ||||||||
251 | { | ||||||||
252 | return (m_pBody != handle.m_pBody); | ||||||||
253 | } | ||||||||
254 | |||||||||
255 | |||||||||
256 | /** Needed to place References into STL collection. | ||||||||
257 | */ | ||||||||
258 | bool | ||||||||
259 | SAL_CALL operator< (const Reference<reference_type> & handle) const | ||||||||
260 | { | ||||||||
261 | return (m_pBody < handle.m_pBody); | ||||||||
262 | } | ||||||||
263 | |||||||||
264 | |||||||||
265 | /** Needed to place References into STL collection. | ||||||||
266 | */ | ||||||||
267 | bool | ||||||||
268 | SAL_CALL operator> (const Reference<reference_type> & handle) const | ||||||||
269 | { | ||||||||
270 | return (m_pBody > handle.m_pBody); | ||||||||
271 | } | ||||||||
272 | }; | ||||||||
273 | |||||||||
274 | } // namespace rtl | ||||||||
275 | |||||||||
276 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
277 | namespace std | ||||||||
278 | { | ||||||||
279 | |||||||||
280 | /// @cond INTERNAL | ||||||||
281 | /** | ||||||||
282 | Make rtl::Reference hashable by default for use in STL containers. | ||||||||
283 | |||||||||
284 | @since LibreOffice 6.3 | ||||||||
285 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct hash<::rtl::Reference<T>> | ||||||||
288 | { | ||||||||
289 | std::size_t operator()(::rtl::Reference<T> const & s) const | ||||||||
290 | { return std::size_t(s.get()); } | ||||||||
291 | }; | ||||||||
292 | /// @endcond | ||||||||
293 | |||||||||
294 | } | ||||||||
295 | |||||||||
296 | #endif | ||||||||
297 | |||||||||
298 | #endif /* ! INCLUDED_RTL_REF_HXX */ | ||||||||
299 | |||||||||
300 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
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/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
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 . |
18 | */ |
19 | #ifndef INCLUDED_VCL_Reference_HXX |
20 | #define INCLUDED_VCL_Reference_HXX |
21 | |
22 | #include <vcl/dllapi.h> |
23 | #include <osl/interlck.h> |
24 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
32 | void acquire() const |
33 | { |
34 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
35 | } |
36 | |
37 | void release() const |
38 | { |
39 | if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |