Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / txtnode / fmtatr2.cxx
blobc776116a4ecccb50e118ba18652bdddc2386b67b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <libxml/xmlwriter.h>
21 #include <hintids.hxx>
22 #include <poolfmt.hxx>
23 #include <unomid.h>
25 #include <o3tl/any.hxx>
26 #include <svl/macitem.hxx>
27 #include <svl/stylepool.hxx>
28 #include <fmtautofmt.hxx>
29 #include <fchrfmt.hxx>
30 #include <fmtinfmt.hxx>
31 #include <txtatr.hxx>
32 #include <fmtruby.hxx>
33 #include <charfmt.hxx>
34 #include <unoevent.hxx>
35 #include <com/sun/star/text/RubyAdjust.hpp>
36 #include <com/sun/star/text/RubyPosition.hpp>
37 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
38 #include <com/sun/star/util/XCloneable.hpp>
39 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/uno/Any.h>
42 #include <SwStyleNameMapper.hxx>
43 #include <comphelper/diagnose_ex.hxx>
45 #include <fmtmeta.hxx>
46 #include <ndtxt.hxx>
47 #include <doc.hxx>
48 #include <unometa.hxx>
49 #include <docsh.hxx>
50 #include <osl/diagnose.h>
52 #include <algorithm>
53 #include <utility>
55 using namespace ::com::sun::star;
58 SfxPoolItem* SwFormatINetFormat::CreateDefault() { return new SwFormatINetFormat; }
60 SwFormatCharFormat::SwFormatCharFormat( SwCharFormat *pFormat )
61 : SfxPoolItem( RES_TXTATR_CHARFMT ),
62 SwClient(pFormat),
63 m_pTextAttribute( nullptr )
67 SwFormatCharFormat::SwFormatCharFormat( const SwFormatCharFormat& rAttr )
68 : SfxPoolItem( RES_TXTATR_CHARFMT ),
69 SwClient( rAttr.GetCharFormat() ),
70 m_pTextAttribute( nullptr )
74 SwFormatCharFormat::~SwFormatCharFormat() {}
76 bool SwFormatCharFormat::operator==( const SfxPoolItem& rAttr ) const
78 assert(SfxPoolItem::operator==(rAttr));
79 return GetCharFormat() == static_cast<const SwFormatCharFormat&>(rAttr).GetCharFormat();
82 SwFormatCharFormat* SwFormatCharFormat::Clone( SfxItemPool* ) const
84 return new SwFormatCharFormat( *this );
87 // forward to the TextAttribute
88 void SwFormatCharFormat::SwClientNotify(const SwModify&, const SfxHint& rHint)
90 if (rHint.GetId() != SfxHintId::SwLegacyModify)
91 return;
92 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
93 if(m_pTextAttribute)
94 m_pTextAttribute->TriggerNodeUpdate(*pLegacy);
97 // forward to the TextAttribute
98 bool SwFormatCharFormat::GetInfo( SfxPoolItem& rInfo ) const
100 return m_pTextAttribute && m_pTextAttribute->GetInfo( rInfo );
102 bool SwFormatCharFormat::QueryValue( uno::Any& rVal, sal_uInt8 ) const
104 OUString sCharFormatName;
105 if(GetCharFormat())
106 SwStyleNameMapper::FillProgName(GetCharFormat()->GetName(), sCharFormatName, SwGetPoolIdFromName::ChrFmt );
107 rVal <<= sCharFormatName;
108 return true;
110 bool SwFormatCharFormat::PutValue( const uno::Any& , sal_uInt8 )
112 OSL_FAIL("format cannot be set with PutValue!");
113 return false;
116 void SwFormatCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
118 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatCharFormat"));
119 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
120 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("text-attribute"), "%p", m_pTextAttribute);
121 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("char-format"), "%p", GetCharFormat());
122 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("char-format-name"),
123 BAD_CAST(GetCharFormat()->GetName().toUtf8().getStr()));
124 (void)xmlTextWriterEndElement(pWriter);
127 SwFormatAutoFormat::SwFormatAutoFormat( sal_uInt16 nInitWhich )
128 : SfxPoolItem( nInitWhich )
132 bool SwFormatAutoFormat::operator==( const SfxPoolItem& rAttr ) const
134 assert(SfxPoolItem::operator==(rAttr));
135 return mpHandle == static_cast<const SwFormatAutoFormat&>(rAttr).mpHandle;
138 SwFormatAutoFormat* SwFormatAutoFormat::Clone( SfxItemPool* ) const
140 return new SwFormatAutoFormat( *this );
143 bool SwFormatAutoFormat::QueryValue( uno::Any& rVal, sal_uInt8 ) const
145 rVal <<= StylePool::nameOf( mpHandle );
146 return true;
149 bool SwFormatAutoFormat::PutValue( const uno::Any& , sal_uInt8 )
151 //the format is not renameable via API
152 return false;
155 void SwFormatAutoFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
157 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatAutoFormat"));
158 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
159 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
160 if (mpHandle) // pool default doesn't have one
162 mpHandle->dumpAsXml(pWriter);
164 (void)xmlTextWriterEndElement(pWriter);
167 SwFormatINetFormat::SwFormatINetFormat()
168 : SfxPoolItem( RES_TXTATR_INETFMT )
169 , msURL()
170 , msTargetFrame()
171 , msINetFormatName()
172 , msVisitedFormatName()
173 , msHyperlinkName()
174 , mpTextAttr( nullptr )
175 , mnINetFormatId( 0 )
176 , mnVisitedFormatId( 0 )
179 SwFormatINetFormat::SwFormatINetFormat( OUString aURL, OUString aTarget )
180 : SfxPoolItem( RES_TXTATR_INETFMT )
181 , msURL( std::move(aURL) )
182 , msTargetFrame( std::move(aTarget) )
183 , msINetFormatName()
184 , msVisitedFormatName()
185 , msHyperlinkName()
186 , mpTextAttr( nullptr )
187 , mnINetFormatId( RES_POOLCHR_INET_NORMAL )
188 , mnVisitedFormatId( RES_POOLCHR_INET_VISIT )
190 SwStyleNameMapper::FillUIName( mnINetFormatId, msINetFormatName );
191 SwStyleNameMapper::FillUIName( mnVisitedFormatId, msVisitedFormatName );
194 SwFormatINetFormat::SwFormatINetFormat( const SwFormatINetFormat& rAttr )
195 : SfxPoolItem( RES_TXTATR_INETFMT )
196 , sw::BroadcasterMixin()
197 , msURL( rAttr.GetValue() )
198 , msTargetFrame( rAttr.msTargetFrame )
199 , msINetFormatName( rAttr.msINetFormatName )
200 , msVisitedFormatName( rAttr.msVisitedFormatName )
201 , msHyperlinkName( rAttr.msHyperlinkName )
202 , mpTextAttr( nullptr )
203 , mnINetFormatId( rAttr.mnINetFormatId )
204 , mnVisitedFormatId( rAttr.mnVisitedFormatId )
206 if ( rAttr.GetMacroTable() )
207 mpMacroTable.reset( new SvxMacroTableDtor( *rAttr.GetMacroTable() ) );
210 SwFormatINetFormat::~SwFormatINetFormat()
214 bool SwFormatINetFormat::operator==( const SfxPoolItem& rAttr ) const
216 assert(SfxPoolItem::operator==(rAttr));
217 bool bRet = SfxPoolItem::operator==( rAttr )
218 && msURL == static_cast<const SwFormatINetFormat&>(rAttr).msURL
219 && msHyperlinkName == static_cast<const SwFormatINetFormat&>(rAttr).msHyperlinkName
220 && msTargetFrame == static_cast<const SwFormatINetFormat&>(rAttr).msTargetFrame
221 && msINetFormatName == static_cast<const SwFormatINetFormat&>(rAttr).msINetFormatName
222 && msVisitedFormatName == static_cast<const SwFormatINetFormat&>(rAttr).msVisitedFormatName
223 && mnINetFormatId == static_cast<const SwFormatINetFormat&>(rAttr).mnINetFormatId
224 && mnVisitedFormatId == static_cast<const SwFormatINetFormat&>(rAttr).mnVisitedFormatId;
226 if( !bRet )
227 return false;
229 const SvxMacroTableDtor* pOther = static_cast<const SwFormatINetFormat&>(rAttr).mpMacroTable.get();
230 if( !mpMacroTable )
231 return ( !pOther || pOther->empty() );
232 if( !pOther )
233 return mpMacroTable->empty();
235 const SvxMacroTableDtor& rOwn = *mpMacroTable;
236 const SvxMacroTableDtor& rOther = *pOther;
238 return rOwn == rOther;
241 SwFormatINetFormat* SwFormatINetFormat::Clone( SfxItemPool* ) const
243 return new SwFormatINetFormat( *this );
246 void SwFormatINetFormat::SetMacroTable( const SvxMacroTableDtor* pNewTable )
248 if( pNewTable )
250 if( mpMacroTable )
251 *mpMacroTable = *pNewTable;
252 else
253 mpMacroTable.reset( new SvxMacroTableDtor( *pNewTable ) );
255 else
257 mpMacroTable.reset();
261 void SwFormatINetFormat::SetMacro( SvMacroItemId nEvent, const SvxMacro& rMacro )
263 if( !mpMacroTable )
264 mpMacroTable.reset( new SvxMacroTableDtor );
266 mpMacroTable->Insert( nEvent, rMacro );
269 const SvxMacro* SwFormatINetFormat::GetMacro( SvMacroItemId nEvent ) const
271 const SvxMacro* pRet = nullptr;
272 if( mpMacroTable && mpMacroTable->IsKeyValid( nEvent ) )
273 pRet = mpMacroTable->Get( nEvent );
274 return pRet;
277 bool SwFormatINetFormat::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
279 nMemberId &= ~CONVERT_TWIPS;
280 switch(nMemberId)
282 case MID_URL_URL:
283 rVal <<= msURL;
284 break;
285 case MID_URL_TARGET:
286 rVal <<= msTargetFrame;
287 break;
288 case MID_URL_HYPERLINKNAME:
289 rVal <<= msHyperlinkName;
290 break;
291 case MID_URL_VISITED_FMT:
293 OUString sVal = msVisitedFormatName;
294 if (sVal.isEmpty() && mnVisitedFormatId != 0)
295 SwStyleNameMapper::FillUIName(mnVisitedFormatId, sVal);
296 if (!sVal.isEmpty())
297 SwStyleNameMapper::FillProgName(sVal, sVal,
298 SwGetPoolIdFromName::ChrFmt);
299 rVal <<= sVal;
301 break;
302 case MID_URL_UNVISITED_FMT:
304 OUString sVal = msINetFormatName;
305 if (sVal.isEmpty() && mnINetFormatId != 0)
306 SwStyleNameMapper::FillUIName(mnINetFormatId, sVal);
307 if (!sVal.isEmpty())
308 SwStyleNameMapper::FillProgName(sVal, sVal,
309 SwGetPoolIdFromName::ChrFmt);
310 rVal <<= sVal;
312 break;
313 case MID_URL_HYPERLINKEVENTS:
315 // create (and return) event descriptor
316 rtl::Reference<SwHyperlinkEventDescriptor> pEvents =
317 new SwHyperlinkEventDescriptor();
318 pEvents->copyMacrosFromINetFormat(*this);
320 // all others return a string; so we just set rVal here and exit
321 rVal <<= uno::Reference<container::XNameReplace>(pEvents);
323 break;
324 default:
325 rVal <<= OUString();
326 break;
328 return true;
330 bool SwFormatINetFormat::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
332 bool bRet = true;
333 nMemberId &= ~CONVERT_TWIPS;
335 // all properties except HyperlinkEvents are of type string, hence
336 // we treat HyperlinkEvents specially
337 if (MID_URL_HYPERLINKEVENTS == nMemberId)
339 uno::Reference<container::XNameReplace> xReplace;
340 rVal >>= xReplace;
341 if (xReplace.is())
343 // Create hyperlink event descriptor. Then copy events
344 // from argument into descriptor. Then copy events from
345 // the descriptor into the format.
346 rtl::Reference<SwHyperlinkEventDescriptor> pEvents = new SwHyperlinkEventDescriptor();
347 pEvents->copyMacrosFromNameReplace(xReplace);
348 pEvents->copyMacrosIntoINetFormat(*this);
350 else
352 // wrong type!
353 bRet = false;
356 else
358 // all string properties:
359 if(rVal.getValueType() != ::cppu::UnoType<OUString>::get())
360 return false;
362 switch(nMemberId)
364 case MID_URL_URL:
365 rVal >>= msURL;
366 break;
367 case MID_URL_TARGET:
368 rVal >>= msTargetFrame;
369 break;
370 case MID_URL_HYPERLINKNAME:
371 rVal >>= msHyperlinkName;
372 break;
373 case MID_URL_VISITED_FMT:
375 OUString sVal;
376 rVal >>= sVal;
377 OUString aString;
378 SwStyleNameMapper::FillUIName( sVal, aString, SwGetPoolIdFromName::ChrFmt );
379 msVisitedFormatName = aString;
380 mnVisitedFormatId = SwStyleNameMapper::GetPoolIdFromUIName( msVisitedFormatName,
381 SwGetPoolIdFromName::ChrFmt );
383 break;
384 case MID_URL_UNVISITED_FMT:
386 OUString sVal;
387 rVal >>= sVal;
388 OUString aString;
389 SwStyleNameMapper::FillUIName( sVal, aString, SwGetPoolIdFromName::ChrFmt );
390 msINetFormatName = aString;
391 mnINetFormatId = SwStyleNameMapper::GetPoolIdFromUIName( msINetFormatName, SwGetPoolIdFromName::ChrFmt );
393 break;
394 default:
395 bRet = false;
398 return bRet;
401 SwFormatRuby::SwFormatRuby( OUString aRubyText )
402 : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
403 m_sRubyText( std::move(aRubyText) ),
404 m_pTextAttr( nullptr ),
405 m_nCharFormatId( 0 ),
406 m_nPosition( 0 ),
407 m_eAdjustment( css::text::RubyAdjust_LEFT )
411 SwFormatRuby::SwFormatRuby( const SwFormatRuby& rAttr )
412 : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
413 m_sRubyText( rAttr.m_sRubyText ),
414 m_sCharFormatName( rAttr.m_sCharFormatName ),
415 m_pTextAttr( nullptr ),
416 m_nCharFormatId( rAttr.m_nCharFormatId),
417 m_nPosition( rAttr.m_nPosition ),
418 m_eAdjustment( rAttr.m_eAdjustment )
422 SwFormatRuby::~SwFormatRuby()
426 SwFormatRuby& SwFormatRuby::operator=( const SwFormatRuby& rAttr )
428 if(this == &rAttr)
429 return *this;
431 m_sRubyText = rAttr.m_sRubyText;
432 m_sCharFormatName = rAttr.m_sCharFormatName;
433 m_nCharFormatId = rAttr.m_nCharFormatId;
434 m_nPosition = rAttr.m_nPosition;
435 m_eAdjustment = rAttr.m_eAdjustment;
436 m_pTextAttr = nullptr;
437 return *this;
440 bool SwFormatRuby::operator==( const SfxPoolItem& rAttr ) const
442 assert(SfxPoolItem::operator==(rAttr));
443 return m_sRubyText == static_cast<const SwFormatRuby&>(rAttr).m_sRubyText &&
444 m_sCharFormatName == static_cast<const SwFormatRuby&>(rAttr).m_sCharFormatName &&
445 m_nCharFormatId == static_cast<const SwFormatRuby&>(rAttr).m_nCharFormatId &&
446 m_nPosition == static_cast<const SwFormatRuby&>(rAttr).m_nPosition &&
447 m_eAdjustment == static_cast<const SwFormatRuby&>(rAttr).m_eAdjustment;
450 SwFormatRuby* SwFormatRuby::Clone( SfxItemPool* ) const
452 return new SwFormatRuby( *this );
455 bool SwFormatRuby::QueryValue( uno::Any& rVal,
456 sal_uInt8 nMemberId ) const
458 bool bRet = true;
459 nMemberId &= ~CONVERT_TWIPS;
460 switch( nMemberId )
462 case MID_RUBY_TEXT: rVal <<= m_sRubyText; break;
463 case MID_RUBY_ADJUST: rVal <<= static_cast<sal_Int16>(m_eAdjustment); break;
464 case MID_RUBY_CHARSTYLE:
466 OUString aString;
467 SwStyleNameMapper::FillProgName(m_sCharFormatName, aString, SwGetPoolIdFromName::ChrFmt );
468 rVal <<= aString;
470 break;
471 case MID_RUBY_ABOVE:
473 rVal <<= static_cast<bool>(!m_nPosition);
475 break;
476 case MID_RUBY_POSITION:
478 rVal <<= m_nPosition;
480 break;
481 default:
482 bRet = false;
484 return bRet;
486 bool SwFormatRuby::PutValue( const uno::Any& rVal,
487 sal_uInt8 nMemberId )
489 bool bRet = true;
490 nMemberId &= ~CONVERT_TWIPS;
491 switch( nMemberId )
493 case MID_RUBY_TEXT:
494 bRet = rVal >>= m_sRubyText;
495 break;
496 case MID_RUBY_ADJUST:
498 sal_Int16 nSet = 0;
499 rVal >>= nSet;
500 if(nSet >= sal_Int16(text::RubyAdjust_LEFT) && nSet <= sal_Int16(text::RubyAdjust_INDENT_BLOCK))
501 m_eAdjustment = static_cast<text::RubyAdjust>(nSet);
502 else
503 bRet = false;
505 break;
506 case MID_RUBY_ABOVE:
508 const uno::Type& rType = cppu::UnoType<bool>::get();
509 if(rVal.hasValue() && rVal.getValueType() == rType)
511 bool bAbove = *o3tl::doAccess<bool>(rVal);
512 m_nPosition = bAbove ? 0 : 1;
515 break;
516 case MID_RUBY_POSITION:
518 sal_Int16 nSet = 0;
519 rVal >>= nSet;
520 if(nSet >= sal_Int16(text::RubyPosition::ABOVE) && nSet <= sal_Int16(text::RubyPosition::INTER_CHARACTER))
521 m_nPosition = nSet;
522 else
523 bRet = false;
525 break;
526 case MID_RUBY_CHARSTYLE:
528 OUString sTmp;
529 bRet = rVal >>= sTmp;
530 if(bRet)
531 m_sCharFormatName = SwStyleNameMapper::GetUIName(sTmp, SwGetPoolIdFromName::ChrFmt );
533 break;
534 default:
535 bRet = false;
537 return bRet;
540 SwFormatMeta * SwFormatMeta::CreatePoolDefault(const sal_uInt16 i_nWhich)
542 return new SwFormatMeta(i_nWhich);
545 SwFormatMeta::SwFormatMeta(const sal_uInt16 i_nWhich)
546 : SfxPoolItem( i_nWhich )
547 , m_pMeta()
548 , m_pTextAttr( nullptr )
550 OSL_ENSURE((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
551 "ERROR: SwFormatMeta: invalid which id!");
554 SwFormatMeta::SwFormatMeta( std::shared_ptr< ::sw::Meta > i_pMeta,
555 const sal_uInt16 i_nWhich )
556 : SfxPoolItem( i_nWhich )
557 , m_pMeta( std::move(i_pMeta) )
558 , m_pTextAttr( nullptr )
560 OSL_ENSURE((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
561 "ERROR: SwFormatMeta: invalid which id!");
562 OSL_ENSURE(m_pMeta, "SwFormatMeta: no Meta ?");
563 // DO NOT call m_pMeta->SetFormatMeta(this) here; only from SetTextAttr!
566 SwFormatMeta::~SwFormatMeta()
568 if (m_pMeta && (m_pMeta->GetFormatMeta() == this))
570 NotifyChangeTextNode(nullptr);
571 m_pMeta->SetFormatMeta(nullptr);
575 bool SwFormatMeta::operator==( const SfxPoolItem & i_rOther ) const
577 return SfxPoolItem::operator==( i_rOther )
578 && m_pMeta == static_cast<SwFormatMeta const &>( i_rOther ).m_pMeta;
581 SwFormatMeta* SwFormatMeta::Clone( SfxItemPool * /*pPool*/ ) const
583 // if this is indeed a copy, then DoCopy must be called later!
584 return m_pMeta // #i105148# pool default may be cloned also!
585 ? new SwFormatMeta( m_pMeta, Which() ) : new SwFormatMeta( Which() );
588 void SwFormatMeta::SetTextAttr(SwTextMeta * const i_pTextAttr)
590 OSL_ENSURE(!(m_pTextAttr && i_pTextAttr),
591 "SwFormatMeta::SetTextAttr: already has text attribute?");
592 OSL_ENSURE( m_pTextAttr || i_pTextAttr ,
593 "SwFormatMeta::SetTextAttr: no attribute to remove?");
594 m_pTextAttr = i_pTextAttr;
595 OSL_ENSURE(m_pMeta, "inserted SwFormatMeta has no sw::Meta?");
596 // the sw::Meta must be able to find the current text attribute!
597 if (m_pMeta)
599 if (i_pTextAttr)
601 m_pMeta->SetFormatMeta(this);
603 else if (m_pMeta->GetFormatMeta() == this)
604 { // text attribute gone => de-register from text node!
605 NotifyChangeTextNode(nullptr);
606 m_pMeta->SetFormatMeta(nullptr);
611 void SwFormatMeta::NotifyChangeTextNode(SwTextNode *const pTextNode)
613 // N.B.: do not reset m_pTextAttr here: see call in nodes.cxx,
614 // where the hint is not deleted!
615 OSL_ENSURE(m_pMeta, "SwFormatMeta::NotifyChangeTextNode: no Meta?");
616 if (m_pMeta && (m_pMeta->GetFormatMeta() == this))
617 { // do not call Modify, that would call SwXMeta::SwClientNotify
618 m_pMeta->NotifyChangeTextNode(pTextNode);
622 // this SwFormatMeta has been cloned and points at the same sw::Meta as the source
623 // this method copies the sw::Meta
624 void SwFormatMeta::DoCopy(::sw::MetaFieldManager & i_rTargetDocManager,
625 SwTextNode & i_rTargetTextNode)
627 OSL_ENSURE(m_pMeta, "DoCopy called for SwFormatMeta with no sw::Meta?");
628 if (!m_pMeta)
629 return;
631 const std::shared_ptr< ::sw::Meta> pOriginal( m_pMeta );
632 if (RES_TXTATR_META == Which())
634 m_pMeta = std::make_shared<::sw::Meta>(this);
636 else
638 ::sw::MetaField *const pMetaField(
639 static_cast< ::sw::MetaField* >(pOriginal.get()));
640 m_pMeta = i_rTargetDocManager.makeMetaField( this,
641 pMetaField->m_nNumberFormat, pMetaField->IsFixedLanguage() );
643 // Meta must have a text node before calling RegisterAsCopyOf
644 m_pMeta->NotifyChangeTextNode(& i_rTargetTextNode);
645 // this cannot be done in Clone: a Clone is not necessarily a copy!
646 m_pMeta->RegisterAsCopyOf(*pOriginal);
649 namespace sw {
651 Meta::Meta(SwFormatMeta * const i_pFormat)
652 : ::sfx2::Metadatable()
653 , sw::BroadcastingModify()
654 , m_pFormat(i_pFormat)
655 , m_pTextNode(nullptr)
659 Meta::~Meta()
663 SwTextMeta * Meta::GetTextAttr() const
665 return m_pFormat ? m_pFormat->GetTextAttr() : nullptr;
668 void Meta::SetXMeta(rtl::Reference<SwXMeta> const& xMeta)
669 { m_wXMeta = xMeta.get(); }
671 void Meta::NotifyChangeTextNode(SwTextNode *const pTextNode)
673 m_pTextNode = pTextNode;
674 if (m_pTextNode && (GetRegisteredIn() != m_pTextNode))
676 m_pTextNode->Add(this);
678 else if (!m_pTextNode)
680 EndListeningAll();
682 if (!pTextNode) // text node gone? invalidate UNO object!
684 GetNotifier().Broadcast(SfxHint(SfxHintId::Deinitializing));
688 void Meta::SwClientNotify(const SwModify&, const SfxHint& rHint)
690 if (rHint.GetId() != SfxHintId::SwLegacyModify)
691 return;
692 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
693 CallSwClientNotify(rHint);
694 GetNotifier().Broadcast(SfxHint(SfxHintId::DataChanged));
695 if(RES_REMOVE_UNO_OBJECT == pLegacy->GetWhich())
696 { // invalidate cached uno object
697 SetXMeta(nullptr);
698 GetNotifier().Broadcast(SfxHint(SfxHintId::Deinitializing));
702 // sfx2::Metadatable
703 ::sfx2::IXmlIdRegistry& Meta::GetRegistry()
705 SwTextNode * const pTextNode( GetTextNode() );
706 // GetRegistry may only be called on a meta that is actually in the
707 // document, which means it has a pointer to its text node
708 OSL_ENSURE(pTextNode, "ERROR: GetRegistry: no text node?");
709 if (!pTextNode)
710 throw uno::RuntimeException();
711 return pTextNode->GetRegistry();
714 bool Meta::IsInClipboard() const
716 const SwTextNode * const pTextNode( GetTextNode() );
717 // no text node: in UNDO OSL_ENSURE(pTextNode, "IsInClipboard: no text node?");
718 return pTextNode && pTextNode->IsInClipboard();
721 bool Meta::IsInUndo() const
723 const SwTextNode * const pTextNode( GetTextNode() );
724 // no text node: in UNDO OSL_ENSURE(pTextNode, "IsInUndo: no text node?");
725 return pTextNode == nullptr || pTextNode->IsInUndo();
728 bool Meta::IsInContent() const
730 const SwTextNode * const pTextNode( GetTextNode() );
731 OSL_ENSURE(pTextNode, "IsInContent: no text node?");
732 return pTextNode == nullptr || pTextNode->IsInContent();
735 css::uno::Reference< css::rdf::XMetadatable > Meta::MakeUnoObject()
737 return SwXMeta::CreateXMeta(*this);
740 MetaField::MetaField(SwFormatMeta * const i_pFormat,
741 const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
742 : Meta(i_pFormat)
743 , m_nNumberFormat( nNumberFormat )
744 , m_bIsFixedLanguage( bIsFixedLanguage )
748 void MetaField::GetPrefixAndSuffix(
749 OUString *const o_pPrefix, OUString *const o_pSuffix, OUString *const o_pShadowsColor)
753 const uno::Reference<rdf::XMetadatable> xMetaField( MakeUnoObject() );
754 assert(dynamic_cast<SwXMetaField*>(xMetaField.get()) && "GetPrefixAndSuffix: no SwXMetaField?");
755 if (xMetaField.is())
757 SwTextNode * const pTextNode( GetTextNode() );
758 SwDocShell const * const pShell(pTextNode->GetDoc().GetDocShell());
759 const uno::Reference<frame::XModel> xModel(
760 pShell ? pShell->GetModel() : nullptr, uno::UNO_SET_THROW);
761 getPrefixAndSuffix(xModel, xMetaField, o_pPrefix, o_pSuffix, o_pShadowsColor);
764 catch (const uno::Exception&)
766 TOOLS_WARN_EXCEPTION( "sw", "");
770 sal_uInt32 MetaField::GetNumberFormat(std::u16string_view aContent) const
772 //TODO: this probably lacks treatment for some special cases
773 sal_uInt32 nNumberFormat( m_nNumberFormat );
774 SwTextNode * const pTextNode( GetTextNode() );
775 if (pTextNode)
777 double number;
778 (void) pTextNode->GetDoc().IsNumberFormat( aContent, nNumberFormat, number );
780 return nNumberFormat;
783 void MetaField::SetNumberFormat(sal_uInt32 nNumberFormat)
785 // effectively, the member is only a default:
786 // GetNumberFormat checks if the text actually conforms
787 m_nNumberFormat = nNumberFormat;
790 MetaFieldManager::MetaFieldManager()
794 std::shared_ptr<MetaField>
795 MetaFieldManager::makeMetaField(SwFormatMeta * const i_pFormat,
796 const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
798 const std::shared_ptr<MetaField> pMetaField(
799 new MetaField(i_pFormat, nNumberFormat, bIsFixedLanguage) );
800 m_MetaFields.push_back(pMetaField);
801 return pMetaField;
804 namespace {
806 struct IsInUndo
808 bool operator()(std::weak_ptr<MetaField> const & pMetaField) {
809 return pMetaField.lock()->IsInUndo();
813 struct MakeUnoObject
815 uno::Reference<text::XTextField>
816 operator()(std::weak_ptr<MetaField> const & pMetaField) {
817 return uno::Reference<text::XTextField>(
818 pMetaField.lock()->MakeUnoObject(), uno::UNO_QUERY);
824 std::vector< uno::Reference<text::XTextField> >
825 MetaFieldManager::getMetaFields()
827 // erase deleted fields
828 const MetaFieldList_t::iterator iter(
829 std::remove_if(m_MetaFields.begin(), m_MetaFields.end(),
830 [] (std::weak_ptr<MetaField> const& rField) { return rField.expired(); }));
831 m_MetaFields.erase(iter, m_MetaFields.end());
832 // filter out fields in UNDO
833 MetaFieldList_t filtered(m_MetaFields.size());
834 const MetaFieldList_t::iterator iter2(
835 std::remove_copy_if(m_MetaFields.begin(), m_MetaFields.end(),
836 filtered.begin(), IsInUndo()));
837 filtered.erase(iter2, filtered.end());
838 // create uno objects
839 std::vector< uno::Reference<text::XTextField> > ret(filtered.size());
840 std::transform(filtered.begin(), filtered.end(), ret.begin(),
841 MakeUnoObject());
842 return ret;
845 void MetaFieldManager::copyDocumentProperties(const SwDoc& rSource)
847 const SwDocShell* pDocShell = rSource.GetDocShell();
848 if (!pDocShell)
849 return;
851 uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(pDocShell->GetModel(), uno::UNO_QUERY);
852 uno::Reference<util::XCloneable> xCloneable(xDocumentPropertiesSupplier->getDocumentProperties(), uno::UNO_QUERY);
853 m_xDocumentProperties.set(xCloneable->createClone(), uno::UNO_QUERY);
856 const uno::Reference<document::XDocumentProperties>& MetaFieldManager::getDocumentProperties() const
858 return m_xDocumentProperties;
861 } // namespace sw
863 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */