Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / unocore / unoftn.cxx
blobef04f1f62d3047b97df07d34cfaa992162fa9369
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 <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>
27 #include <mutex>
29 #include <unofootnote.hxx>
30 #include <unotextrange.hxx>
31 #include <unotextcursor.hxx>
32 #include <unoparagraph.hxx>
33 #include <unomap.hxx>
34 #include <unoprnms.hxx>
35 #include <doc.hxx>
36 #include <ftnidx.hxx>
37 #include <fmtftn.hxx>
38 #include <txtftn.hxx>
39 #include <ndtxt.hxx>
40 #include <unocrsr.hxx>
41 #include <svl/itemprop.hxx>
43 using namespace ::com::sun::star;
45 namespace {
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); });
56 return ret;
61 class SwXFootnote::Impl
62 : public SvtListener
64 public:
66 SwXFootnote& m_rThis;
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;
71 bool m_bIsDescriptor;
72 SwFormatFootnote* m_pFormatFootnote;
73 OUString m_sLabel;
75 Impl(SwXFootnote& rThis,
76 SwFormatFootnote* const pFootnote,
77 const bool bIsEndnote)
78 : m_rThis(rThis)
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() );
92 if (!pFootnote) {
93 throw uno::RuntimeException("SwXFootnote: disposed or invalid", nullptr);
95 return *pFootnote;
98 void Invalidate();
99 protected:
100 void Notify(const SfxHint& rHint) override;
104 void SwXFootnote::Impl::Invalidate()
106 EndListeningAll();
107 m_pFormatFootnote = nullptr;
108 m_rThis.SetDoc(nullptr);
109 uno::Reference<uno::XInterface> const xThis(m_wThis);
110 if (!xThis.is())
111 { // fdo#72695: if UNO object is already dead, don't revive it with event
112 return;
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)
122 Invalidate();
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;
147 if (pFootnoteFormat)
149 xNote = pFootnoteFormat->GetXFootnote();
151 if (!xNote.is())
153 xNote = pFootnoteFormat
154 ? new SwXFootnote(rDoc, *pFootnoteFormat)
155 : new SwXFootnote(isEndnote);
156 if (pFootnoteFormat)
158 pFootnoteFormat->SetXFootnote(xNote);
160 // need a permanent Reference to initialize m_wThis
161 xNote->m_pImpl->m_wThis = xNote.get();
163 return xNote;
166 OUString SAL_CALL
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()
192 SolarMutexGuard g;
193 return GetSupportedServiceNamesImpl(
194 (m_pImpl->m_bIsEndnote) ? g_nServicesEndnote : g_nServicesFootnote,
195 g_ServicesFootnote);
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>();
212 uno::Any SAL_CALL
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)
218 : ret;
221 OUString SAL_CALL SwXFootnote::getLabel()
223 SolarMutexGuard aGuard;
225 OUString sRet;
226 SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat();
227 if(pFormat)
229 sRet = pFormat->GetNumStr();
231 else if (m_pImpl->m_bIsDescriptor)
233 sRet = m_pImpl->m_sLabel;
235 else
237 throw uno::RuntimeException();
239 return sRet;
242 void SAL_CALL
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();
253 if(pFormat)
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;
266 else
268 throw uno::RuntimeException();
272 void SAL_CALL
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);
285 if (!pNewDoc)
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);
296 aPam.DeleteMark();
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 ));
316 if (pTextAttr)
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());
327 else
329 pTextAttr->SetSeqRefNo();
332 m_pImpl->m_bIsDescriptor = false;
333 SetDoc(pNewDoc);
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 );
357 void SAL_CALL
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);
366 void SAL_CALL
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();
378 if(pFormat)
380 const SwTextFootnote* pTextFootnote = pFormat->GetTextFootnote();
381 if( pTextFootnote )
383 return pTextFootnote->GetStartNode()->GetNode().GetStartNode();
386 return nullptr;
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);
400 return pXCursor;
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());
427 return xRet;
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()
451 return true;
454 uno::Reference< beans::XPropertySetInfo > SAL_CALL
455 SwXFootnote::getPropertySetInfo()
457 SolarMutexGuard g;
458 static uno::Reference< beans::XPropertySetInfo > xRet =
459 aSwMapProvider.GetPropertySet(PROPERTY_MAP_FOOTNOTE)
460 ->getPropertySetInfo();
461 return xRet;
464 void SAL_CALL
465 SwXFootnote::setPropertyValue(const OUString&, const uno::Any&)
467 //no values to be set
468 throw lang::IllegalArgumentException();
471 uno::Any SAL_CALL
472 SwXFootnote::getPropertyValue(const OUString& rPropertyName)
474 SolarMutexGuard aGuard;
476 uno::Any aRet;
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();
491 if (pFormat)
493 SwTextFootnote const*const pTextFootnote = pFormat->GetTextFootnote();
494 OSL_ENSURE(pTextFootnote, "no TextNode?");
495 aRet <<= static_cast<sal_Int16>(pTextFootnote->GetSeqRefNo());
498 else
500 beans::UnknownPropertyException aExcept;
501 aExcept.Message = rPropertyName;
502 throw aExcept;
505 return aRet;
508 void SAL_CALL
509 SwXFootnote::addPropertyChangeListener(
510 const OUString& /*rPropertyName*/,
511 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
513 OSL_FAIL("SwXFootnote::addPropertyChangeListener(): not implemented");
516 void SAL_CALL
517 SwXFootnote::removePropertyChangeListener(
518 const OUString& /*rPropertyName*/,
519 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
521 OSL_FAIL("SwXFootnote::removePropertyChangeListener(): not implemented");
524 void SAL_CALL
525 SwXFootnote::addVetoableChangeListener(
526 const OUString& /*rPropertyName*/,
527 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
529 OSL_FAIL("SwXFootnote::addVetoableChangeListener(): not implemented");
532 void SAL_CALL
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: */