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 .
21 #include <comphelper/string.hxx>
22 #include <i18nlangtag/languagetag.hxx>
23 #include <o3tl/any.hxx>
24 #include <swtypes.hxx>
25 #include <strings.hrc>
26 #include <authfld.hxx>
30 #include <rootfrm.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <IDocumentLayoutAccess.hxx>
39 #include <unofldmid.h>
40 #include <unoprnms.hxx>
43 #include <com/sun/star/beans/PropertyValues.hpp>
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::beans
;
47 using namespace ::com::sun::star::lang
;
49 SwAuthEntry::SwAuthEntry(const SwAuthEntry
& rCopy
)
50 : SimpleReferenceObject()
52 for(int i
= 0; i
< AUTH_FIELD_END
; ++i
)
53 m_aAuthFields
[i
] = rCopy
.m_aAuthFields
[i
];
56 bool SwAuthEntry::operator==(const SwAuthEntry
& rComp
) const
58 for(int i
= 0; i
< AUTH_FIELD_END
; ++i
)
59 if(m_aAuthFields
[i
] != rComp
.m_aAuthFields
[i
])
64 SwAuthorityFieldType::SwAuthorityFieldType(SwDoc
* pDoc
)
65 : SwFieldType( SwFieldIds::TableOfAuthorities
),
70 m_bSortByDocument(true),
71 m_eLanguage(::GetAppLanguage())
75 SwAuthorityFieldType::~SwAuthorityFieldType()
79 std::unique_ptr
<SwFieldType
> SwAuthorityFieldType::Copy() const
81 return std::make_unique
<SwAuthorityFieldType
>(m_pDoc
);
84 void SwAuthorityFieldType::RemoveField(const SwAuthEntry
* pEntry
)
86 for(SwAuthDataArr::size_type j
= 0; j
< m_DataArr
.size(); ++j
)
88 if(m_DataArr
[j
].get() == pEntry
)
90 if (m_DataArr
[j
]->m_nCount
<= 1)
92 m_DataArr
.erase(m_DataArr
.begin() + j
);
93 //re-generate positions of the fields
100 OSL_FAIL("Field unknown" );
103 SwAuthEntry
* SwAuthorityFieldType::AddField(const OUString
& rFieldContents
)
105 rtl::Reference
<SwAuthEntry
> pEntry(new SwAuthEntry
);
107 for( sal_Int32 i
= 0; i
< AUTH_FIELD_END
; ++i
)
108 pEntry
->SetAuthorField( static_cast<ToxAuthorityField
>(i
),
109 rFieldContents
.getToken( 0, TOX_STYLE_DELIMITER
, nIdx
));
111 for (auto &rpTemp
: m_DataArr
)
113 if (*rpTemp
== *pEntry
)
119 //if it is a new Entry - insert
120 m_DataArr
.push_back(std::move(pEntry
));
121 //re-generate positions of the fields
123 return m_DataArr
.back().get();
126 void SwAuthorityFieldType::GetAllEntryIdentifiers(
127 std::vector
<OUString
>& rToFill
)const
129 for (const auto & rpTemp
: m_DataArr
)
131 rToFill
.push_back(rpTemp
->GetAuthorField(AUTH_FIELD_IDENTIFIER
));
135 SwAuthEntry
* SwAuthorityFieldType::GetEntryByIdentifier(
136 const OUString
& rIdentifier
)const
138 for (const auto &rpTemp
: m_DataArr
)
140 if (rIdentifier
== rpTemp
->GetAuthorField(AUTH_FIELD_IDENTIFIER
))
148 bool SwAuthorityFieldType::ChangeEntryContent(const SwAuthEntry
* pNewEntry
)
150 for (auto &rpTemp
: m_DataArr
)
152 if (rpTemp
->GetAuthorField(AUTH_FIELD_IDENTIFIER
) ==
153 pNewEntry
->GetAuthorField(AUTH_FIELD_IDENTIFIER
))
155 for(int i
= 0; i
< AUTH_FIELD_END
; ++i
)
157 rpTemp
->SetAuthorField(static_cast<ToxAuthorityField
>(i
),
158 pNewEntry
->GetAuthorField(static_cast<ToxAuthorityField
>(i
)));
166 /// appends a new entry (if new) and returns the array position
167 sal_uInt16
SwAuthorityFieldType::AppendField( const SwAuthEntry
& rInsert
)
169 for( SwAuthDataArr::size_type nRet
= 0; nRet
< m_DataArr
.size(); ++nRet
)
171 if( *m_DataArr
[ nRet
] == rInsert
)
175 //if it is a new Entry - insert
176 m_DataArr
.push_back(new SwAuthEntry(rInsert
));
177 return m_DataArr
.size()-1;
180 sal_uInt16
SwAuthorityFieldType::GetSequencePos(const SwAuthEntry
* pAuthEntry
,
181 SwRootFrame
const*const pLayout
)
183 //find the field in a sorted array of handles,
184 if(!m_SequArr
.empty() && m_SequArr
.size() != m_DataArr
.size())
186 if(m_SequArr
.empty())
188 IDocumentRedlineAccess
const& rIDRA(m_pDoc
->getIDocumentRedlineAccess());
189 SwTOXInternational
aIntl(m_eLanguage
, SwTOIOptions::NONE
, m_sSortAlgorithm
);
190 // sw_redlinehide: need 2 arrays because the sorting may be different,
191 // if multiple fields refer to the same entry and first one is deleted
192 std::vector
<std::unique_ptr
<SwTOXSortTabBase
>> aSortArr
;
193 std::vector
<std::unique_ptr
<SwTOXSortTabBase
>> aSortArrRLHidden
;
194 std::vector
<SwFormatField
*> vFields
;
195 GatherFields(vFields
);
196 for(SwFormatField
* pFormatField
: vFields
)
198 const SwTextField
* pTextField
= pFormatField
->GetTextField();
199 if(!pTextField
|| !pTextField
->GetpTextNode())
203 const SwTextNode
& rFieldTextNode
= pTextField
->GetTextNode();
204 SwPosition
aFieldPos(rFieldTextNode
);
205 SwDoc
& rDoc
= const_cast<SwDoc
&>(rFieldTextNode
.GetDoc());
206 SwContentFrame
*pFrame
= rFieldTextNode
.getLayoutFrame( rDoc
.getIDocumentLayoutAccess().GetCurrentLayout() );
207 const SwTextNode
* pTextNode
= nullptr;
208 if(pFrame
&& !pFrame
->IsInDocBody())
209 pTextNode
= GetBodyTextNode( rDoc
, aFieldPos
, *pFrame
);
210 //if no text node could be found or the field is in the document
211 //body the directly available text node will be used
213 pTextNode
= &rFieldTextNode
;
214 if (pTextNode
->GetText().isEmpty()
215 || !pTextNode
->getLayoutFrame(rDoc
.getIDocumentLayoutAccess().GetCurrentLayout())
216 || !pTextNode
->GetNodes().IsDocNodes())
220 auto const InsertImpl
= [&aIntl
, pTextNode
, pFormatField
]
221 (std::vector
<std::unique_ptr
<SwTOXSortTabBase
>> & rSortArr
)
223 std::unique_ptr
<SwTOXAuthority
> pNew(
224 new SwTOXAuthority(*pTextNode
, *pFormatField
, aIntl
));
226 for (size_t i
= 0; i
< rSortArr
.size(); ++i
)
228 SwTOXSortTabBase
* pOld
= rSortArr
[i
].get();
229 if (pOld
->equivalent(*pNew
))
231 //only the first occurrence in the document
232 //has to be in the array
233 if (pOld
->sort_lt(*pNew
))
235 else // remove the old content
236 rSortArr
.erase(rSortArr
.begin() + i
);
240 //if it still exists - insert at the correct position
245 while (j
< rSortArr
.size())
247 SwTOXSortTabBase
* pOld
= rSortArr
[j
].get();
248 if (pNew
->sort_lt(*pOld
))
252 rSortArr
.insert(rSortArr
.begin() + j
, std::move(pNew
));
255 InsertImpl(aSortArr
);
256 if (!sw::IsFieldDeletedInModel(rIDRA
, *pTextField
))
258 InsertImpl(aSortArrRLHidden
);
262 for(auto & pBase
: aSortArr
)
264 SwFormatField
& rFormatField
= static_cast<SwTOXAuthority
&>(*pBase
).GetFieldFormat();
265 SwAuthorityField
* pAField
= static_cast<SwAuthorityField
*>(rFormatField
.GetField());
266 m_SequArr
.push_back(pAField
->GetAuthEntry());
268 for (auto & pBase
: aSortArrRLHidden
)
270 SwFormatField
& rFormatField
= static_cast<SwTOXAuthority
&>(*pBase
).GetFieldFormat();
271 SwAuthorityField
* pAField
= static_cast<SwAuthorityField
*>(rFormatField
.GetField());
272 m_SequArrRLHidden
.push_back(pAField
->GetAuthEntry());
276 auto const& rSequArr(pLayout
&& pLayout
->IsHideRedlines() ? m_SequArrRLHidden
: m_SequArr
);
277 for (std::vector
<sal_IntPtr
>::size_type i
= 0; i
< rSequArr
.size(); ++i
)
279 if (rSequArr
[i
] == pAuthEntry
)
287 void SwAuthorityFieldType::QueryValue( Any
& rVal
, sal_uInt16 nWhichId
) const
291 case FIELD_PROP_PAR1
:
292 case FIELD_PROP_PAR2
:
295 sal_Unicode uRet
= FIELD_PROP_PAR1
== nWhichId
? m_cPrefix
: m_cSuffix
;
297 sVal
= OUString(uRet
);
301 case FIELD_PROP_PAR3
:
302 rVal
<<= GetSortAlgorithm();
305 case FIELD_PROP_BOOL1
:
306 rVal
<<= m_bIsSequence
;
309 case FIELD_PROP_BOOL2
:
310 rVal
<<= m_bSortByDocument
;
313 case FIELD_PROP_LOCALE
:
314 rVal
<<= LanguageTag(GetLanguage()).getLocale();
317 case FIELD_PROP_PROP_SEQ
:
319 Sequence
<PropertyValues
> aRet(m_SortKeyArr
.size());
320 PropertyValues
* pValues
= aRet
.getArray();
321 for(SortKeyArr::size_type i
= 0; i
< m_SortKeyArr
.size(); ++i
)
323 const SwTOXSortKey
* pKey
= &m_SortKeyArr
[i
];
324 pValues
[i
].realloc(2);
325 PropertyValue
* pValue
= pValues
[i
].getArray();
326 pValue
[0].Name
= UNO_NAME_SORT_KEY
;
327 pValue
[0].Value
<<= sal_Int16(pKey
->eField
);
328 pValue
[1].Name
= UNO_NAME_IS_SORT_ASCENDING
;
329 pValue
[1].Value
<<= pKey
->bSortAscending
;
339 void SwAuthorityFieldType::PutValue( const Any
& rAny
, sal_uInt16 nWhichId
)
343 case FIELD_PROP_PAR1
:
344 case FIELD_PROP_PAR2
:
348 const sal_Unicode uSet
= !sTmp
.isEmpty() ? sTmp
[0] : 0;
349 if( FIELD_PROP_PAR1
== nWhichId
)
355 case FIELD_PROP_PAR3
:
359 SetSortAlgorithm(sTmp
);
362 case FIELD_PROP_BOOL1
:
363 m_bIsSequence
= *o3tl::doAccess
<bool>(rAny
);
365 case FIELD_PROP_BOOL2
:
366 m_bSortByDocument
= *o3tl::doAccess
<bool>(rAny
);
369 case FIELD_PROP_LOCALE
:
371 css::lang::Locale aLocale
;
372 if( rAny
>>= aLocale
)
373 SetLanguage( LanguageTag::convertToLanguageType( aLocale
));
377 case FIELD_PROP_PROP_SEQ
:
379 Sequence
<PropertyValues
> aSeq
;
382 m_SortKeyArr
.clear();
383 const PropertyValues
* pValues
= aSeq
.getConstArray();
384 //TODO: Limiting to the first SAL_MAX_UINT16 elements of aSeq so that size of
385 // m_SortKeyArr remains in range of sal_uInt16, as GetSortKeyCount and GetSortKey
386 // still expect m_SortKeyArr to be indexed by sal_uInt16:
387 auto nSize
= std::min
<sal_Int32
>(aSeq
.getLength(), SAL_MAX_UINT16
);
388 for(sal_Int32 i
= 0; i
< nSize
; i
++)
390 SwTOXSortKey aSortKey
;
391 for(const PropertyValue
& rValue
: pValues
[i
])
393 if(rValue
.Name
== UNO_NAME_SORT_KEY
)
395 sal_Int16 nVal
= -1; rValue
.Value
>>= nVal
;
396 if(nVal
>= 0 && nVal
< AUTH_FIELD_END
)
397 aSortKey
.eField
= static_cast<ToxAuthorityField
>(nVal
);
399 else if(rValue
.Name
== UNO_NAME_IS_SORT_ASCENDING
)
401 aSortKey
.bSortAscending
= *o3tl::doAccess
<bool>(rValue
.Value
);
404 m_SortKeyArr
.push_back(aSortKey
);
414 void SwAuthorityFieldType::Modify( const SfxPoolItem
* pOld
, const SfxPoolItem
*pNew
)
416 //re-generate positions of the fields
418 NotifyClients( pOld
, pNew
);
421 sal_uInt16
SwAuthorityFieldType::GetSortKeyCount() const
423 return m_SortKeyArr
.size();
426 const SwTOXSortKey
* SwAuthorityFieldType::GetSortKey(sal_uInt16 nIdx
) const
428 if(m_SortKeyArr
.size() > nIdx
)
429 return &m_SortKeyArr
[nIdx
];
430 OSL_FAIL("Sort key not found");
434 void SwAuthorityFieldType::SetSortKeys(sal_uInt16 nKeyCount
, SwTOXSortKey
const aKeys
[])
436 m_SortKeyArr
.clear();
437 for(sal_uInt16 i
= 0; i
< nKeyCount
; i
++)
438 if(aKeys
[i
].eField
< AUTH_FIELD_END
)
439 m_SortKeyArr
.push_back(aKeys
[i
]);
442 SwAuthorityField::SwAuthorityField( SwAuthorityFieldType
* pInitType
,
443 const OUString
& rFieldContents
)
445 , m_nTempSequencePos( -1 )
446 , m_nTempSequencePosRLHidden( -1 )
448 m_xAuthEntry
= pInitType
->AddField( rFieldContents
);
451 SwAuthorityField::SwAuthorityField( SwAuthorityFieldType
* pInitType
,
452 SwAuthEntry
* pAuthEntry
)
453 : SwField( pInitType
)
454 , m_xAuthEntry( pAuthEntry
)
455 , m_nTempSequencePos( -1 )
456 , m_nTempSequencePosRLHidden( -1 )
460 SwAuthorityField::~SwAuthorityField()
462 static_cast<SwAuthorityFieldType
* >(GetTyp())->RemoveField(m_xAuthEntry
.get());
465 OUString
SwAuthorityField::ExpandImpl(SwRootFrame
const*const pLayout
) const
467 return ConditionalExpandAuthIdentifier(pLayout
);
470 OUString
SwAuthorityField::ConditionalExpandAuthIdentifier(
471 SwRootFrame
const*const pLayout
) const
473 SwAuthorityFieldType
* pAuthType
= static_cast<SwAuthorityFieldType
*>(GetTyp());
475 if(pAuthType
->GetPrefix())
476 sRet
= OUString(pAuthType
->GetPrefix());
478 if( pAuthType
->IsSequence() )
480 sal_IntPtr
& rnTempSequencePos(pLayout
&& pLayout
->IsHideRedlines()
481 ? m_nTempSequencePosRLHidden
: m_nTempSequencePos
);
482 if(!pAuthType
->GetDoc()->getIDocumentFieldsAccess().IsExpFieldsLocked())
483 rnTempSequencePos
= pAuthType
->GetSequencePos(m_xAuthEntry
.get(), pLayout
);
484 if (0 <= rnTempSequencePos
)
485 sRet
+= OUString::number(rnTempSequencePos
);
489 //TODO: Expand to: identifier, number sequence, ...
492 OUString
sIdentifier(m_xAuthEntry
->GetAuthorField(AUTH_FIELD_IDENTIFIER
));
493 // tdf#107784 Use title if it's a ooxml citation
494 if (sIdentifier
.trim().startsWith("CITATION"))
495 return m_xAuthEntry
->GetAuthorField(AUTH_FIELD_TITLE
);
500 if(pAuthType
->GetSuffix())
501 sRet
+= OUStringChar(pAuthType
->GetSuffix());
505 OUString
SwAuthorityField::ExpandCitation(ToxAuthorityField eField
,
506 SwRootFrame
const*const pLayout
) const
508 SwAuthorityFieldType
* pAuthType
= static_cast<SwAuthorityFieldType
*>(GetTyp());
511 if( pAuthType
->IsSequence() )
513 sal_IntPtr
& rnTempSequencePos(pLayout
&& pLayout
->IsHideRedlines()
514 ? m_nTempSequencePosRLHidden
: m_nTempSequencePos
);
515 if(!pAuthType
->GetDoc()->getIDocumentFieldsAccess().IsExpFieldsLocked())
516 rnTempSequencePos
= pAuthType
->GetSequencePos(m_xAuthEntry
.get(), pLayout
);
517 if (0 <= rnTempSequencePos
)
518 sRet
+= OUString::number(rnTempSequencePos
);
522 //TODO: Expand to: identifier, number sequence, ...
524 sRet
+= m_xAuthEntry
->GetAuthorField(eField
);
529 std::unique_ptr
<SwField
> SwAuthorityField::Copy() const
531 SwAuthorityFieldType
* pAuthType
= static_cast<SwAuthorityFieldType
*>(GetTyp());
532 return std::make_unique
<SwAuthorityField
>(pAuthType
, m_xAuthEntry
.get());
535 const OUString
& SwAuthorityField::GetFieldText(ToxAuthorityField eField
) const
537 return m_xAuthEntry
->GetAuthorField( eField
);
540 void SwAuthorityField::SetPar1(const OUString
& rStr
)
542 SwAuthorityFieldType
* pInitType
= static_cast<SwAuthorityFieldType
* >(GetTyp());
543 pInitType
->RemoveField(m_xAuthEntry
.get());
544 m_xAuthEntry
= pInitType
->AddField(rStr
);
547 OUString
SwAuthorityField::GetDescription() const
549 return SwResId(STR_AUTHORITY_ENTRY
);
552 const char* const aFieldNames
[] =
555 "BibiliographicType",
587 bool SwAuthorityField::QueryValue( Any
& rAny
, sal_uInt16
/*nWhichId*/ ) const
593 Sequence
<PropertyValue
> aRet(AUTH_FIELD_END
);
594 PropertyValue
* pValues
= aRet
.getArray();
595 for(int i
= 0; i
< AUTH_FIELD_END
; ++i
)
597 pValues
[i
].Name
= OUString::createFromAscii(aFieldNames
[i
]);
598 const OUString
& sField
= m_xAuthEntry
->GetAuthorField(static_cast<ToxAuthorityField
>(i
));
599 if(i
== AUTH_FIELD_AUTHORITY_TYPE
)
600 pValues
[i
].Value
<<= sal_Int16(sField
.toInt32());
602 pValues
[i
].Value
<<= sField
;
605 /* FIXME: it is weird that we always return false here */
609 static sal_Int32
lcl_Find(const OUString
& rFieldName
)
611 for(sal_Int32 i
= 0; i
< AUTH_FIELD_END
; ++i
)
612 if(rFieldName
.equalsAscii(aFieldNames
[i
]))
617 bool SwAuthorityField::PutValue( const Any
& rAny
, sal_uInt16
/*nWhichId*/ )
619 if(!GetTyp() || !m_xAuthEntry
)
622 Sequence
<PropertyValue
> aParam
;
623 if(!(rAny
>>= aParam
))
627 comphelper::string::padToLength(sBuf
, AUTH_FIELD_ISBN
, TOX_STYLE_DELIMITER
);
628 OUString
sToSet(sBuf
.makeStringAndClear());
629 for(const PropertyValue
& rParam
: std::as_const(aParam
))
631 const sal_Int32 nFound
= lcl_Find(rParam
.Name
);
635 if(AUTH_FIELD_AUTHORITY_TYPE
== nFound
)
638 rParam
.Value
>>= nVal
;
639 sContent
= OUString::number(nVal
);
642 rParam
.Value
>>= sContent
;
643 sToSet
= comphelper::string::setToken(sToSet
, nFound
, TOX_STYLE_DELIMITER
, sContent
);
647 static_cast<SwAuthorityFieldType
*>(GetTyp())->RemoveField(m_xAuthEntry
.get());
648 m_xAuthEntry
= static_cast<SwAuthorityFieldType
*>(GetTyp())->AddField(sToSet
);
650 /* FIXME: it is weird that we always return false here */
654 SwFieldType
* SwAuthorityField::ChgTyp( SwFieldType
* pFieldTyp
)
656 SwAuthorityFieldType
* pSrcTyp
= static_cast<SwAuthorityFieldType
*>(GetTyp()),
657 * pDstTyp
= static_cast<SwAuthorityFieldType
*>(pFieldTyp
);
658 if( pSrcTyp
!= pDstTyp
)
660 const SwAuthEntry
* pSrcEntry
= m_xAuthEntry
.get();
661 pDstTyp
->AppendField( *pSrcEntry
);
662 pSrcTyp
->RemoveField( pSrcEntry
);
663 SwField::ChgTyp( pFieldTyp
);
668 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */