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 <comphelper/interfacecontainer4.hxx>
23 #include <comphelper/sequence.hxx>
24 #include <comphelper/servicehelper.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <svl/listener.hxx>
29 #include <unofootnote.hxx>
30 #include <unotextrange.hxx>
31 #include <unotextcursor.hxx>
32 #include <unoparagraph.hxx>
34 #include <unoprnms.hxx>
40 #include <unocrsr.hxx>
41 #include <svl/itemprop.hxx>
43 using namespace ::com::sun::star
;
47 uno::Sequence
< OUString
>
48 GetSupportedServiceNamesImpl(
49 size_t const nServices
, char const*const pServices
[])
51 uno::Sequence
< OUString
> ret(static_cast<sal_Int32
>(nServices
));
53 std::transform(pServices
, pServices
+ nServices
, ret
.getArray(),
54 [](const char* pService
) -> OUString
{ return OUString::createFromAscii(pService
); });
61 class SwXFootnote::Impl
67 unotools::WeakReference
<SwXFootnote
> m_wThis
;
68 const bool m_bIsEndnote
;
69 std::mutex m_Mutex
; // just for OInterfaceContainerHelper4
70 ::comphelper::OInterfaceContainerHelper4
<css::lang::XEventListener
> m_EventListeners
;
72 SwFormatFootnote
* m_pFormatFootnote
;
75 Impl(SwXFootnote
& rThis
,
76 SwFormatFootnote
* const pFootnote
,
77 const bool bIsEndnote
)
79 , m_bIsEndnote(bIsEndnote
)
80 , m_bIsDescriptor(nullptr == pFootnote
)
81 , m_pFormatFootnote(pFootnote
)
83 m_pFormatFootnote
&& StartListening(m_pFormatFootnote
->GetNotifier());
86 const SwFormatFootnote
* GetFootnoteFormat() const {
87 return m_rThis
.GetDoc() ? m_pFormatFootnote
: nullptr;
90 SwFormatFootnote
const& GetFootnoteFormatOrThrow() const {
91 SwFormatFootnote
const*const pFootnote( GetFootnoteFormat() );
93 throw uno::RuntimeException("SwXFootnote: disposed or invalid", nullptr);
100 void Notify(const SfxHint
& rHint
) override
;
104 void SwXFootnote::Impl::Invalidate()
107 m_pFormatFootnote
= nullptr;
108 m_rThis
.SetDoc(nullptr);
109 uno::Reference
<uno::XInterface
> const xThis(m_wThis
);
111 { // fdo#72695: if UNO object is already dead, don't revive it with event
114 lang::EventObject
const ev(xThis
);
115 std::unique_lock
aGuard(m_Mutex
);
116 m_EventListeners
.disposeAndClear(aGuard
, ev
);
119 void SwXFootnote::Impl::Notify(const SfxHint
& rHint
)
121 if(rHint
.GetId() == SfxHintId::Dying
)
125 SwXFootnote::SwXFootnote(const bool bEndnote
)
126 : SwXText(nullptr, CursorType::Footnote
)
127 , m_pImpl( new SwXFootnote::Impl(*this, nullptr, bEndnote
) )
131 SwXFootnote::SwXFootnote(SwDoc
& rDoc
, SwFormatFootnote
& rFormat
)
132 : SwXText(& rDoc
, CursorType::Footnote
)
133 , m_pImpl( new SwXFootnote::Impl(*this, &rFormat
, rFormat
.IsEndNote()) )
137 SwXFootnote::~SwXFootnote()
141 rtl::Reference
<SwXFootnote
>
142 SwXFootnote::CreateXFootnote(SwDoc
& rDoc
, SwFormatFootnote
*const pFootnoteFormat
,
143 bool const isEndnote
)
145 // i#105557: do not iterate over the registered clients: race condition
146 rtl::Reference
<SwXFootnote
> xNote
;
149 xNote
= pFootnoteFormat
->GetXFootnote();
153 xNote
= pFootnoteFormat
154 ? new SwXFootnote(rDoc
, *pFootnoteFormat
)
155 : new SwXFootnote(isEndnote
);
158 pFootnoteFormat
->SetXFootnote(xNote
);
160 // need a permanent Reference to initialize m_wThis
161 xNote
->m_pImpl
->m_wThis
= xNote
.get();
167 SwXFootnote::getImplementationName()
169 return "SwXFootnote";
172 char const*const g_ServicesFootnote
[] =
174 "com.sun.star.text.TextContent",
175 "com.sun.star.text.Footnote",
176 "com.sun.star.text.Text",
177 "com.sun.star.text.Endnote", // NB: only supported for endnotes!
180 const size_t g_nServicesEndnote( SAL_N_ELEMENTS(g_ServicesFootnote
) );
182 const size_t g_nServicesFootnote( g_nServicesEndnote
- 1 ); // NB: omit!
184 sal_Bool SAL_CALL
SwXFootnote::supportsService(const OUString
& rServiceName
)
186 return cppu::supportsService(this, rServiceName
);
189 uno::Sequence
< OUString
> SAL_CALL
190 SwXFootnote::getSupportedServiceNames()
193 return GetSupportedServiceNamesImpl(
194 (m_pImpl
->m_bIsEndnote
) ? g_nServicesEndnote
: g_nServicesFootnote
,
198 uno::Sequence
< uno::Type
> SAL_CALL
199 SwXFootnote::getTypes()
201 const uno::Sequence
< uno::Type
> aTypes
= SwXFootnote_Base::getTypes();
202 const uno::Sequence
< uno::Type
> aTextTypes
= SwXText::getTypes();
203 return ::comphelper::concatSequences(aTypes
, aTextTypes
);
206 uno::Sequence
< sal_Int8
> SAL_CALL
207 SwXFootnote::getImplementationId()
209 return css::uno::Sequence
<sal_Int8
>();
213 SwXFootnote::queryInterface(const uno::Type
& rType
)
215 const uno::Any ret
= SwXFootnote_Base::queryInterface(rType
);
216 return (ret
.getValueType() == cppu::UnoType
<void>::get())
217 ? SwXText::queryInterface(rType
)
221 OUString SAL_CALL
SwXFootnote::getLabel()
223 SolarMutexGuard aGuard
;
226 SwFormatFootnote
const*const pFormat
= m_pImpl
->GetFootnoteFormat();
229 sRet
= pFormat
->GetNumStr();
231 else if (m_pImpl
->m_bIsDescriptor
)
233 sRet
= m_pImpl
->m_sLabel
;
237 throw uno::RuntimeException();
243 SwXFootnote::setLabel(const OUString
& aLabel
)
245 SolarMutexGuard aGuard
;
246 OUString
newLabel(aLabel
);
247 //new line must not occur as footnote label
248 if(newLabel
.indexOf('\n') >=0 )
250 newLabel
= newLabel
.replace('\n', ' ');
252 SwFormatFootnote
const*const pFormat
= m_pImpl
->GetFootnoteFormat();
255 const SwTextFootnote
* pTextFootnote
= pFormat
->GetTextFootnote();
256 OSL_ENSURE(pTextFootnote
, "No TextNode?");
257 SwTextNode
& rTextNode
= const_cast<SwTextNode
&>(pTextFootnote
->GetTextNode());
259 SwPaM
aPam(rTextNode
, pTextFootnote
->GetStart());
260 GetDoc()->SetCurFootnote(aPam
, newLabel
, pFormat
->IsEndNote());
262 else if (m_pImpl
->m_bIsDescriptor
)
264 m_pImpl
->m_sLabel
= newLabel
;
268 throw uno::RuntimeException();
273 SwXFootnote::attach(const uno::Reference
< text::XTextRange
> & xTextRange
)
275 SolarMutexGuard aGuard
;
277 if (!m_pImpl
->m_bIsDescriptor
)
279 throw uno::RuntimeException();
281 SwXTextRange
*const pRange
= dynamic_cast<SwXTextRange
*>(xTextRange
.get());
282 OTextCursorHelper
*const pCursor
= dynamic_cast<OTextCursorHelper
*>(xTextRange
.get());
283 SwDoc
*const pNewDoc
=
284 pRange
? &pRange
->GetDoc() : (pCursor
? pCursor
->GetDoc() : nullptr);
287 throw lang::IllegalArgumentException();
290 SwUnoInternalPaM
aPam(*pNewDoc
);
291 // this now needs to return TRUE
292 ::sw::XTextRangeToSwPaM(aPam
, xTextRange
);
294 UnoActionContext
aCont(pNewDoc
);
295 pNewDoc
->getIDocumentContentOperations().DeleteAndJoin(aPam
);
297 SwFormatFootnote
aFootNote(m_pImpl
->m_bIsEndnote
);
298 if (!m_pImpl
->m_sLabel
.isEmpty())
300 aFootNote
.SetNumStr(m_pImpl
->m_sLabel
);
303 SwXTextCursor
const*const pTextCursor(
304 dynamic_cast<SwXTextCursor
*>(pCursor
));
305 const bool bForceExpandHints( pTextCursor
&& pTextCursor
->IsAtEndOfMeta() );
306 const SetAttrMode nInsertFlags
= bForceExpandHints
307 ? SetAttrMode::FORCEHINTEXPAND
308 : SetAttrMode::DEFAULT
;
310 pNewDoc
->getIDocumentContentOperations().InsertPoolItem(aPam
, aFootNote
, nInsertFlags
);
312 SwTextFootnote
*const pTextAttr
= static_cast<SwTextFootnote
*>(
313 aPam
.GetPointNode().GetTextNode()->GetTextAttrForCharAt(
314 aPam
.GetPoint()->GetContentIndex()-1, RES_TXTATR_FTN
));
318 m_pImpl
->EndListeningAll();
319 SwFormatFootnote
* pFootnote
= const_cast<SwFormatFootnote
*>(&pTextAttr
->GetFootnote());
320 m_pImpl
->m_pFormatFootnote
= pFootnote
;
321 m_pImpl
->StartListening(pFootnote
->GetNotifier());
322 // force creation of sequence id - is used for references
323 if (pNewDoc
->IsInReading())
325 pTextAttr
->SetSeqNo(pNewDoc
->GetFootnoteIdxs().size());
329 pTextAttr
->SetSeqRefNo();
332 m_pImpl
->m_bIsDescriptor
= false;
336 uno::Reference
< text::XTextRange
> SAL_CALL
337 SwXFootnote::getAnchor()
339 SolarMutexGuard aGuard
;
340 return m_pImpl
->GetFootnoteFormatOrThrow().getAnchor(*GetDoc());
343 void SAL_CALL
SwXFootnote::dispose()
345 SolarMutexGuard aGuard
;
347 SwFormatFootnote
const& rFormat( m_pImpl
->GetFootnoteFormatOrThrow() );
349 SwTextFootnote
const*const pTextFootnote
= rFormat
.GetTextFootnote();
350 OSL_ENSURE(pTextFootnote
, "no TextNode?");
351 SwTextNode
& rTextNode
= const_cast<SwTextNode
&>(pTextFootnote
->GetTextNode());
352 const sal_Int32 nPos
= pTextFootnote
->GetStart();
353 SwPaM
aPam(rTextNode
, nPos
, rTextNode
, nPos
+1);
354 GetDoc()->getIDocumentContentOperations().DeleteAndJoin( aPam
);
358 SwXFootnote::addEventListener(
359 const uno::Reference
< lang::XEventListener
> & xListener
)
361 // no need to lock here as m_pImpl is const and container threadsafe
362 std::unique_lock
aGuard(m_pImpl
->m_Mutex
);
363 m_pImpl
->m_EventListeners
.addInterface(aGuard
, xListener
);
367 SwXFootnote::removeEventListener(
368 const uno::Reference
< lang::XEventListener
> & xListener
)
370 // no need to lock here as m_pImpl is const and container threadsafe
371 std::unique_lock
aGuard(m_pImpl
->m_Mutex
);
372 m_pImpl
->m_EventListeners
.removeInterface(aGuard
, xListener
);
375 const SwStartNode
*SwXFootnote::GetStartNode() const
377 SwFormatFootnote
const*const pFormat
= m_pImpl
->GetFootnoteFormat();
380 const SwTextFootnote
* pTextFootnote
= pFormat
->GetTextFootnote();
383 return pTextFootnote
->GetStartNode()->GetNode().GetStartNode();
389 rtl::Reference
< SwXTextCursor
>
390 SwXFootnote::createXTextCursor()
392 SwFormatFootnote
const& rFormat( m_pImpl
->GetFootnoteFormatOrThrow() );
394 SwTextFootnote
const*const pTextFootnote
= rFormat
.GetTextFootnote();
395 SwPosition
aPos( *pTextFootnote
->GetStartNode() );
396 rtl::Reference
<SwXTextCursor
> pXCursor
=
397 new SwXTextCursor(*GetDoc(), this, CursorType::Footnote
, aPos
);
398 auto& rUnoCursor(pXCursor
->GetCursor());
399 rUnoCursor
.Move(fnMoveForward
, GoInNode
);
403 rtl::Reference
< SwXTextCursor
>
404 SwXFootnote::createXTextCursorByRange(
405 const uno::Reference
< text::XTextRange
> & xTextPosition
)
407 SwFormatFootnote
const& rFormat( m_pImpl
->GetFootnoteFormatOrThrow() );
409 SwUnoInternalPaM
aPam(*GetDoc());
410 if (!::sw::XTextRangeToSwPaM(aPam
, xTextPosition
))
412 throw uno::RuntimeException();
415 SwTextFootnote
const*const pTextFootnote
= rFormat
.GetTextFootnote();
416 SwNode
const*const pFootnoteStartNode
= &pTextFootnote
->GetStartNode()->GetNode();
418 const SwNode
* pStart
= aPam
.GetPointNode().FindFootnoteStartNode();
419 if (pStart
!= pFootnoteStartNode
)
421 throw uno::RuntimeException();
424 const rtl::Reference
< SwXTextCursor
> xRet
=
425 new SwXTextCursor(*GetDoc(), this, CursorType::Footnote
,
426 *aPam
.GetPoint(), aPam
.GetMark());
430 uno::Reference
< container::XEnumeration
> SAL_CALL
431 SwXFootnote::createEnumeration()
433 SolarMutexGuard aGuard
;
435 SwFormatFootnote
const& rFormat( m_pImpl
->GetFootnoteFormatOrThrow() );
437 SwTextFootnote
const*const pTextFootnote
= rFormat
.GetTextFootnote();
438 SwPosition
aPos( *pTextFootnote
->GetStartNode() );
439 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos
));
440 pUnoCursor
->Move(fnMoveForward
, GoInNode
);
441 return SwXParagraphEnumeration::Create(this, pUnoCursor
, CursorType::Footnote
);
444 uno::Type SAL_CALL
SwXFootnote::getElementType()
446 return cppu::UnoType
<text::XTextRange
>::get();
449 sal_Bool SAL_CALL
SwXFootnote::hasElements()
454 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
455 SwXFootnote::getPropertySetInfo()
458 static uno::Reference
< beans::XPropertySetInfo
> xRet
=
459 aSwMapProvider
.GetPropertySet(PROPERTY_MAP_FOOTNOTE
)
460 ->getPropertySetInfo();
465 SwXFootnote::setPropertyValue(const OUString
&, const uno::Any
&)
467 //no values to be set
468 throw lang::IllegalArgumentException();
472 SwXFootnote::getPropertyValue(const OUString
& rPropertyName
)
474 SolarMutexGuard aGuard
;
477 if (! ::sw::GetDefaultTextContentValue(aRet
, rPropertyName
))
479 if (rPropertyName
== UNO_NAME_START_REDLINE
||
480 rPropertyName
== UNO_NAME_END_REDLINE
)
482 //redline can only be returned if it's a living object
483 if (!m_pImpl
->m_bIsDescriptor
)
485 aRet
= SwXText::getPropertyValue(rPropertyName
);
488 else if (rPropertyName
== UNO_NAME_REFERENCE_ID
)
490 SwFormatFootnote
const*const pFormat
= m_pImpl
->GetFootnoteFormat();
493 SwTextFootnote
const*const pTextFootnote
= pFormat
->GetTextFootnote();
494 OSL_ENSURE(pTextFootnote
, "no TextNode?");
495 aRet
<<= static_cast<sal_Int16
>(pTextFootnote
->GetSeqRefNo());
500 beans::UnknownPropertyException aExcept
;
501 aExcept
.Message
= rPropertyName
;
509 SwXFootnote::addPropertyChangeListener(
510 const OUString
& /*rPropertyName*/,
511 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
513 OSL_FAIL("SwXFootnote::addPropertyChangeListener(): not implemented");
517 SwXFootnote::removePropertyChangeListener(
518 const OUString
& /*rPropertyName*/,
519 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
521 OSL_FAIL("SwXFootnote::removePropertyChangeListener(): not implemented");
525 SwXFootnote::addVetoableChangeListener(
526 const OUString
& /*rPropertyName*/,
527 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
529 OSL_FAIL("SwXFootnote::addVetoableChangeListener(): not implemented");
533 SwXFootnote::removeVetoableChangeListener(
534 const OUString
& /*rPropertyName*/,
535 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
537 OSL_FAIL("SwXFootnote::removeVetoableChangeListener(): not implemented");
540 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */