1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <sdr/properties/textproperties.hxx>
23 #include <svl/itemset.hxx>
24 #include <svl/style.hxx>
25 #include <svl/itemiter.hxx>
26 #include <svl/hint.hxx>
27 #include <svx/svddef.hxx>
28 #include <svx/svdotext.hxx>
29 #include <svx/svdoutl.hxx>
30 #include <svx/sdmetitm.hxx>
31 #include <svx/sdtditm.hxx>
32 #include <editeng/writingmodeitem.hxx>
33 #include <svx/svdmodel.hxx>
34 #include <editeng/eeitem.hxx>
35 #include <editeng/outlobj.hxx>
36 #include <svx/xfillit0.hxx>
37 #include <svx/xflclit.hxx>
38 #include <editeng/adjustitem.hxx>
39 #include <svx/svdetc.hxx>
40 #include <editeng/editeng.hxx>
41 #include <editeng/flditem.hxx>
42 #include <svx/xlineit0.hxx>
43 #include <svx/xlnwtit.hxx>
45 using namespace com::sun::star
;
47 namespace sdr::properties
49 SfxItemSet
TextProperties::CreateObjectSpecificItemSet(SfxItemPool
& rPool
)
51 return SfxItemSet(rPool
,
53 // range from SdrAttrObj
54 svl::Items
<SDRATTR_START
, SDRATTR_SHADOW_LAST
,
55 SDRATTR_MISC_FIRST
, SDRATTR_MISC_LAST
,
56 SDRATTR_TEXTDIRECTION
, SDRATTR_TEXTDIRECTION
,
57 SDRATTR_GLOW_TEXT_FIRST
, SDRATTR_GLOW_TEXT_LAST
,
58 SDRATTR_TEXTCOLUMNS_FIRST
, SDRATTR_TEXTCOLUMNS_LAST
,
60 // range from SdrTextObj
61 EE_ITEMS_START
, EE_ITEMS_END
>);
64 TextProperties::TextProperties(SdrObject
& rObj
)
65 : AttributeProperties(rObj
),
70 TextProperties::TextProperties(const TextProperties
& rProps
, SdrObject
& rObj
)
71 : AttributeProperties(rProps
, rObj
),
72 maVersion(rProps
.getVersion())
76 TextProperties::~TextProperties()
80 std::unique_ptr
<BaseProperties
> TextProperties::Clone(SdrObject
& rObj
) const
82 return std::unique_ptr
<BaseProperties
>(new TextProperties(*this, rObj
));
85 void TextProperties::ItemSetChanged(std::span
< const SfxPoolItem
* const > aChangedItems
, sal_uInt16 nDeletedWhich
, bool bAdjustTextFrameWidthAndHeight
)
87 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
89 // #i101556# ItemSet has changed -> new version
92 if (auto pOutliner
= rObj
.GetTextEditOutliner())
94 pOutliner
->SetTextColumns(rObj
.GetTextColumnsNumber(),
95 rObj
.GetTextColumnsSpacing());
98 const svx::ITextProvider
& rTextProvider(getTextProvider());
99 sal_Int32 nText
= rTextProvider
.getTextCount();
102 SdrText
* pText
= rTextProvider
.getText( nText
);
104 OutlinerParaObject
* pParaObj
= pText
? pText
->GetOutlinerParaObject() : nullptr;
108 const bool bTextEdit
= rObj
.IsTextEditActive() && (rObj
.getActiveText() == pText
);
110 // handle outliner attributes
112 Outliner
* pOutliner
= rObj
.GetTextEditOutliner();
116 pOutliner
= &rObj
.ImpGetDrawOutliner();
117 pOutliner
->SetText(*pParaObj
);
120 sal_Int32
nParaCount(pOutliner
->GetParagraphCount());
122 for(sal_Int32 nPara
= 0; nPara
< nParaCount
; nPara
++)
124 SfxItemSet
aSet(pOutliner
->GetParaAttribs(nPara
));
125 for (const SfxPoolItem
* pItem
: aChangedItems
)
128 aSet
.ClearItem(nDeletedWhich
);
129 pOutliner
->SetParaAttribs(nPara
, aSet
);
139 moItemSet
->Put(pOutliner
->GetParaAttribs(0));
142 std::optional
<OutlinerParaObject
> pTemp
= pOutliner
->CreateParaObject(0, nParaCount
);
145 rObj
.NbcSetOutlinerParaObjectForText(std::move(pTemp
), pText
, bAdjustTextFrameWidthAndHeight
);
150 // Extra-Repaint for radical layout changes (#43139#)
151 for (const SfxPoolItem
* pItem
: aChangedItems
)
152 if (pItem
->Which() == SDRATTR_TEXT_CONTOURFRAME
)
154 // Here only repaint wanted
155 rObj
.ActionChanged();
156 //rObj.BroadcastObjectChange();
161 AttributeProperties::ItemSetChanged(aChangedItems
, nDeletedWhich
, bAdjustTextFrameWidthAndHeight
);
164 void TextProperties::ItemChange(const sal_uInt16 nWhich
, const SfxPoolItem
* pNewItem
)
166 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
169 sal_Int32
nOldLineWidth(0);
171 if(XATTR_LINEWIDTH
== nWhich
&& rObj
.DoesSupportTextIndentingOnLineWidthChange())
173 nOldLineWidth
= GetItem(XATTR_LINEWIDTH
).GetValue();
176 if(pNewItem
&& (SDRATTR_TEXTDIRECTION
== nWhich
))
178 bool bVertical(css::text::WritingMode_TB_RL
== static_cast<const SvxWritingModeItem
*>(pNewItem
)->GetValue());
179 rObj
.SetVerticalWriting(bVertical
);
182 // #95501# reset to default
183 if(!pNewItem
&& !nWhich
&& rObj
.HasText() )
185 SdrOutliner
& rOutliner
= rObj
.ImpGetDrawOutliner();
187 const svx::ITextProvider
& rTextProvider(getTextProvider());
188 sal_Int32 nCount
= rTextProvider
.getTextCount();
191 SdrText
* pText
= rTextProvider
.getText( nCount
);
192 OutlinerParaObject
* pParaObj
= pText
->GetOutlinerParaObject();
195 rOutliner
.SetText(*pParaObj
);
196 sal_Int32
nParaCount(rOutliner
.GetParagraphCount());
200 auto aSelection
= ESelection::All();
201 rOutliner
.RemoveAttribs(aSelection
, true, 0);
203 std::optional
<OutlinerParaObject
> pTemp
= rOutliner
.CreateParaObject(0, nParaCount
);
206 rObj
.NbcSetOutlinerParaObjectForText( std::move(pTemp
), pText
);
213 AttributeProperties::ItemChange( nWhich
, pNewItem
);
216 if(!(XATTR_LINEWIDTH
== nWhich
&& rObj
.DoesSupportTextIndentingOnLineWidthChange()))
219 const sal_Int32
nNewLineWidth(GetItem(XATTR_LINEWIDTH
).GetValue());
220 const sal_Int32
nDifference((nNewLineWidth
- nOldLineWidth
) / 2);
225 const bool bLineVisible(drawing::LineStyle_NONE
!= GetItem(XATTR_LINESTYLE
).GetValue());
229 const sal_Int32
nLeftDist(GetItem(SDRATTR_TEXT_LEFTDIST
).GetValue());
230 const sal_Int32
nRightDist(GetItem(SDRATTR_TEXT_RIGHTDIST
).GetValue());
231 const sal_Int32
nUpperDist(GetItem(SDRATTR_TEXT_UPPERDIST
).GetValue());
232 const sal_Int32
nLowerDist(GetItem(SDRATTR_TEXT_LOWERDIST
).GetValue());
234 SetObjectItemDirect(makeSdrTextLeftDistItem(nLeftDist
+ nDifference
));
235 SetObjectItemDirect(makeSdrTextRightDistItem(nRightDist
+ nDifference
));
236 SetObjectItemDirect(makeSdrTextUpperDistItem(nUpperDist
+ nDifference
));
237 SetObjectItemDirect(makeSdrTextLowerDistItem(nLowerDist
+ nDifference
));
241 const svx::ITextProvider
& TextProperties::getTextProvider() const
243 return static_cast<const SdrTextObj
&>(GetSdrObject());
246 void TextProperties::SetStyleSheet(SfxStyleSheet
* pNewStyleSheet
, bool bDontRemoveHardAttr
,
247 bool bBroadcast
, bool bAdjustTextFrameWidthAndHeight
)
249 // call parent (always first thing to do, may create the SfxItemSet)
250 AttributeProperties::SetStyleSheet(pNewStyleSheet
, bDontRemoveHardAttr
, bBroadcast
, bAdjustTextFrameWidthAndHeight
);
252 // #i101556# StyleSheet has changed -> new version
253 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
256 if(!rObj
.IsLinkedText() )
258 SdrOutliner
& rOutliner
= rObj
.ImpGetDrawOutliner();
260 const svx::ITextProvider
& rTextProvider(getTextProvider());
261 sal_Int32 nText
= rTextProvider
.getTextCount();
264 SdrText
* pText
= rTextProvider
.getText( nText
);
266 OutlinerParaObject
* pParaObj
= pText
? pText
->GetOutlinerParaObject() : nullptr;
270 // apply StyleSheet to all paragraphs
271 rOutliner
.SetText(*pParaObj
);
272 sal_Int32
nParaCount(rOutliner
.GetParagraphCount());
276 for(sal_Int32 nPara
= 0; nPara
< nParaCount
; nPara
++)
278 std::optional
<SfxItemSet
> pTempSet
;
280 // since setting the stylesheet removes all para attributes
281 if(bDontRemoveHardAttr
)
283 // we need to remember them if we want to keep them
284 pTempSet
.emplace(rOutliner
.GetParaAttribs(nPara
));
289 if((SdrObjKind::OutlineText
== rObj
.GetTextKind()) && (SdrInventor::Default
== rObj
.GetObjInventor()))
291 OUString
aNewStyleSheetName(GetStyleSheet()->GetName());
292 aNewStyleSheetName
= aNewStyleSheetName
.copy(0, aNewStyleSheetName
.getLength() - 1);
293 sal_Int16 nDepth
= rOutliner
.GetDepth(nPara
);
294 aNewStyleSheetName
+= OUString::number( nDepth
<= 0 ? 1 : nDepth
+ 1);
295 SfxStyleSheetBasePool
* pStylePool(rObj
.getSdrModelFromSdrObject().GetStyleSheetPool());
296 SfxStyleSheet
* pNewStyle
= nullptr;
298 pNewStyle
= static_cast<SfxStyleSheet
*>(pStylePool
->Find(aNewStyleSheetName
, GetStyleSheet()->GetFamily()));
299 DBG_ASSERT( pNewStyle
, "AutoStyleSheetName - Style not found!" );
303 rOutliner
.SetStyleSheet(nPara
, pNewStyle
);
308 rOutliner
.SetStyleSheet(nPara
, GetStyleSheet());
314 rOutliner
.SetStyleSheet(nPara
, nullptr);
317 if(bDontRemoveHardAttr
)
321 // restore para attributes
322 rOutliner
.SetParaAttribs(nPara
, *pTempSet
);
329 // remove all hard paragraph attributes
330 // which occur in StyleSheet, take care of
332 SfxItemIter
aIter(pNewStyleSheet
->GetItemSet());
334 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
;
335 pItem
= aIter
.NextItem())
337 if(!IsInvalidItem(pItem
))
339 sal_uInt16
nW(pItem
->Which());
341 if(nW
>= EE_ITEMS_START
&& nW
<= EE_ITEMS_END
)
343 rOutliner
.RemoveCharAttribs(nPara
, nW
);
351 std::optional
<OutlinerParaObject
> pTemp
= rOutliner
.CreateParaObject(0, nParaCount
);
353 rObj
.NbcSetOutlinerParaObjectForText(std::move(pTemp
), pText
, bAdjustTextFrameWidthAndHeight
);
358 if(rObj
.IsTextFrame() && !rObj
.getSdrModelFromSdrObject().isLocked() && bAdjustTextFrameWidthAndHeight
)
359 rObj
.NbcAdjustTextFrameWidthAndHeight();
362 void TextProperties::ForceDefaultAttributes()
364 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
366 if( rObj
.GetObjInventor() == SdrInventor::Default
)
368 const SdrObjKind nSdrObjKind
= rObj
.GetObjIdentifier();
370 if( nSdrObjKind
== SdrObjKind::TitleText
|| nSdrObjKind
== SdrObjKind::OutlineText
)
371 return; // no defaults for presentation objects
374 bool bTextFrame(rObj
.IsTextFrame());
378 moItemSet
->Put(XLineStyleItem(drawing::LineStyle_NONE
));
379 moItemSet
->Put(XFillColorItem(OUString(), COL_WHITE
));
380 moItemSet
->Put(XFillStyleItem(drawing::FillStyle_NONE
));
384 moItemSet
->Put(SvxAdjustItem(SvxAdjust::Center
, EE_PARA_JUST
));
385 moItemSet
->Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER
));
386 moItemSet
->Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER
));
390 void TextProperties::ForceStyleToHardAttributes()
392 // #i61284# call parent first to get the hard ObjectItemSet
393 AttributeProperties::ForceStyleToHardAttributes();
395 // #i61284# push hard ObjectItemSet to OutlinerParaObject attributes
396 // using existing functionality
397 GetObjectItemSet(); // force ItemSet
398 std::vector
<const SfxPoolItem
*> aChangedItems
;
400 { // own scope to get SfxItemIter aIter destroyed ASAP - it maybe detected
401 // as reading source to the ItemSet when Items get changed below, but it
402 // is no longer active/needed
403 SfxItemIter
aIter(*moItemSet
);
404 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
406 if(!IsInvalidItem(pItem
))
407 aChangedItems
.push_back(pItem
);
411 ItemSetChanged(aChangedItems
, 0);
413 // now the standard TextProperties stuff
414 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
416 if(rObj
.IsTextEditActive() || rObj
.IsLinkedText())
419 std::unique_ptr
<Outliner
> pOutliner
= SdrMakeOutliner(OutlinerMode::OutlineObject
, rObj
.getSdrModelFromSdrObject());
420 const svx::ITextProvider
& rTextProvider(getTextProvider());
421 sal_Int32 nText
= rTextProvider
.getTextCount();
424 SdrText
* pText
= rTextProvider
.getText( nText
);
426 OutlinerParaObject
* pParaObj
= pText
? pText
->GetOutlinerParaObject() : nullptr;
430 pOutliner
->SetText(*pParaObj
);
432 sal_Int32
nParaCount(pOutliner
->GetParagraphCount());
438 for(sal_Int32 nPara
= 0; nPara
< nParaCount
; nPara
++)
440 SfxStyleSheet
* pSheet
= pOutliner
->GetStyleSheet(nPara
);
444 SfxItemSet
aParaSet(pOutliner
->GetParaAttribs(nPara
));
445 SfxItemSet
aSet(*aParaSet
.GetPool());
446 aSet
.Put(pSheet
->GetItemSet());
448 /** the next code handles a special case for paragraphs that contain a
449 url field. The color for URL fields is either the system color for
450 urls or the char color attribute that formats the portion in which the
451 url field is contained.
452 When we set a char color attribute to the paragraphs item set from the
453 styles item set, we would have this char color attribute as an attribute
454 that is spanned over the complete paragraph after xml import due to some
455 problems in the xml import (using a XCursor on import so it does not know
456 the paragraphs and can't set char attributes to paragraphs ).
458 To avoid this, as soon as we try to set a char color attribute from the style
460 1. check if we have at least one url field in this paragraph
461 2. if we found at least one url field, we span the char color attribute over
462 all portions that are not url fields and remove the char color attribute
463 from the paragraphs item set
468 if(aSet
.GetItemState(EE_CHAR_COLOR
) == SfxItemState::SET
)
470 EditEngine
* pEditEngine
= const_cast<EditEngine
*>(&(pOutliner
->GetEditEngine()));
471 std::vector
<EECharAttrib
> aAttribs
;
472 pEditEngine
->GetCharAttribs(nPara
, aAttribs
);
474 for(const auto& rAttrib
: aAttribs
)
476 if(rAttrib
.pAttr
&& EE_FEATURE_FIELD
== rAttrib
.pAttr
->Which())
478 const SvxFieldItem
* pFieldItem
= static_cast<const SvxFieldItem
*>(rAttrib
.pAttr
);
482 const SvxFieldData
* pData
= pFieldItem
->GetField();
484 if(dynamic_cast<const SvxURLField
*>( pData
))
495 SfxItemSetFixed
<EE_CHAR_COLOR
, EE_CHAR_COLOR
> aColorSet(*aSet
.GetPool());
496 aColorSet
.Put(aSet
, false);
498 ESelection
aSel(nPara
, 0);
500 for(const auto& rAttrib
: aAttribs
)
502 if(EE_FEATURE_FIELD
== rAttrib
.pAttr
->Which())
504 aSel
.end
.nIndex
= rAttrib
.nStart
;
506 if (aSel
.start
.nIndex
!= aSel
.end
.nIndex
)
507 pEditEngine
->QuickSetAttribs(aColorSet
, aSel
);
509 aSel
.start
.nIndex
= rAttrib
.nEnd
;
513 aSel
.end
.nIndex
= pEditEngine
->GetTextLen(nPara
);
515 if (aSel
.start
.nIndex
!= aSel
.end
.nIndex
)
517 pEditEngine
->QuickSetAttribs( aColorSet
, aSel
);
523 aSet
.Put(aParaSet
, false);
527 aSet
.ClearItem(EE_CHAR_COLOR
);
530 pOutliner
->SetParaAttribs(nPara
, aSet
);
531 bBurnIn
= true; // #i51163# Flag was set wrong
537 std::optional
<OutlinerParaObject
> pTemp
= pOutliner
->CreateParaObject(0, nParaCount
);
538 rObj
.NbcSetOutlinerParaObjectForText(std::move(pTemp
),pText
);
546 void TextProperties::SetObjectItemNoBroadcast(const SfxPoolItem
& rItem
)
549 moItemSet
->Put(rItem
);
553 void TextProperties::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
556 AttributeProperties::Notify(rBC
, rHint
);
558 SfxHintId
nId(rHint
.GetId());
560 if(SfxHintId::DataChanged
== nId
&& rBC
.IsSfxStyleSheet())
562 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
566 const svx::ITextProvider
& rTextProvider(getTextProvider());
567 sal_Int32 nText
= rTextProvider
.getTextCount();
570 OutlinerParaObject
* pParaObj
= rTextProvider
.getText( nText
)->GetOutlinerParaObject();
572 pParaObj
->ClearPortionInfo();
574 rObj
.SetTextSizeDirty();
576 if(rObj
.IsTextFrame() && rObj
.NbcAdjustTextFrameWidthAndHeight())
578 // here only repaint wanted
579 rObj
.ActionChanged();
580 //rObj.BroadcastObjectChange();
583 // #i101556# content of StyleSheet has changed -> new version
586 else if(SfxHintId::Dying
== nId
&& rBC
.IsSfxStyleSheet())
588 SdrTextObj
& rObj
= static_cast<SdrTextObj
&>(GetSdrObject());
592 const svx::ITextProvider
& rTextProvider(getTextProvider());
593 sal_Int32 nText
= rTextProvider
.getTextCount();
596 OutlinerParaObject
* pParaObj
= rTextProvider
.getText( nText
)->GetOutlinerParaObject();
598 pParaObj
->ClearPortionInfo();
601 else if (nId
== SfxHintId::StyleSheetModifiedExtended
)
603 assert(dynamic_cast<const SfxStyleSheetBasePool
*>(&rBC
) != nullptr);
604 const SfxStyleSheetModifiedHint
& rExtendedHint
= static_cast<const SfxStyleSheetModifiedHint
&>(rHint
);
605 const OUString
& aOldName(rExtendedHint
.GetOldName());
606 OUString
aNewName(rExtendedHint
.GetStyleSheet()->GetName());
607 SfxStyleFamily eFamily
= rExtendedHint
.GetStyleSheet()->GetFamily();
609 if(aOldName
!= aNewName
)
611 const svx::ITextProvider
& rTextProvider(getTextProvider());
612 sal_Int32 nText
= rTextProvider
.getTextCount();
615 OutlinerParaObject
* pParaObj
= rTextProvider
.getText( nText
)->GetOutlinerParaObject();
617 pParaObj
->ChangeStyleSheetName(eFamily
, aOldName
, aNewName
);
623 // #i101556# Handout version information
624 sal_uInt32
TextProperties::getVersion() const
628 } // end of namespace
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */