summaryrefslogtreecommitdiffstats
path: root/sw/source/core/unocore/unoftn.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/unocore/unoftn.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/unocore/unoftn.cxx')
-rw-r--r--sw/source/core/unocore/unoftn.cxx538
1 files changed, 538 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unoftn.cxx b/sw/source/core/unocore/unoftn.cxx
new file mode 100644
index 0000000000..1a73e2e617
--- /dev/null
+++ b/sw/source/core/unocore/unoftn.cxx
@@ -0,0 +1,538 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/interfacecontainer4.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svl/listener.hxx>
+#include <mutex>
+
+#include <unofootnote.hxx>
+#include <unotextrange.hxx>
+#include <unotextcursor.hxx>
+#include <unoparagraph.hxx>
+#include <unomap.hxx>
+#include <unoprnms.hxx>
+#include <doc.hxx>
+#include <ftnidx.hxx>
+#include <fmtftn.hxx>
+#include <txtftn.hxx>
+#include <ndtxt.hxx>
+#include <unocrsr.hxx>
+#include <svl/itemprop.hxx>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+uno::Sequence< OUString >
+GetSupportedServiceNamesImpl(
+ size_t const nServices, char const*const pServices[])
+{
+ uno::Sequence< OUString > ret(static_cast<sal_Int32>(nServices));
+
+ std::transform(pServices, pServices + nServices, ret.getArray(),
+ [](const char* pService) -> OUString { return OUString::createFromAscii(pService); });
+
+ return ret;
+}
+
+}
+
+class SwXFootnote::Impl
+ : public SvtListener
+{
+public:
+
+ SwXFootnote& m_rThis;
+ unotools::WeakReference<SwXFootnote> m_wThis;
+ const bool m_bIsEndnote;
+ std::mutex m_Mutex; // just for OInterfaceContainerHelper4
+ ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners;
+ bool m_bIsDescriptor;
+ SwFormatFootnote* m_pFormatFootnote;
+ OUString m_sLabel;
+
+ Impl(SwXFootnote& rThis,
+ SwFormatFootnote* const pFootnote,
+ const bool bIsEndnote)
+ : m_rThis(rThis)
+ , m_bIsEndnote(bIsEndnote)
+ , m_bIsDescriptor(nullptr == pFootnote)
+ , m_pFormatFootnote(pFootnote)
+ {
+ m_pFormatFootnote && StartListening(m_pFormatFootnote->GetNotifier());
+ }
+
+ const SwFormatFootnote* GetFootnoteFormat() const {
+ return m_rThis.GetDoc() ? m_pFormatFootnote : nullptr;
+ }
+
+ SwFormatFootnote const& GetFootnoteFormatOrThrow() const {
+ SwFormatFootnote const*const pFootnote( GetFootnoteFormat() );
+ if (!pFootnote) {
+ throw uno::RuntimeException("SwXFootnote: disposed or invalid", nullptr);
+ }
+ return *pFootnote;
+ }
+
+ void Invalidate();
+protected:
+ void Notify(const SfxHint& rHint) override;
+
+};
+
+void SwXFootnote::Impl::Invalidate()
+{
+ EndListeningAll();
+ m_pFormatFootnote = nullptr;
+ m_rThis.SetDoc(nullptr);
+ uno::Reference<uno::XInterface> const xThis(m_wThis);
+ if (!xThis.is())
+ { // fdo#72695: if UNO object is already dead, don't revive it with event
+ return;
+ }
+ lang::EventObject const ev(xThis);
+ std::unique_lock aGuard(m_Mutex);
+ m_EventListeners.disposeAndClear(aGuard, ev);
+}
+
+void SwXFootnote::Impl::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ Invalidate();
+}
+
+SwXFootnote::SwXFootnote(const bool bEndnote)
+ : SwXText(nullptr, CursorType::Footnote)
+ , m_pImpl( new SwXFootnote::Impl(*this, nullptr, bEndnote) )
+{
+}
+
+SwXFootnote::SwXFootnote(SwDoc & rDoc, SwFormatFootnote & rFormat)
+ : SwXText(& rDoc, CursorType::Footnote)
+ , m_pImpl( new SwXFootnote::Impl(*this, &rFormat, rFormat.IsEndNote()) )
+{
+}
+
+SwXFootnote::~SwXFootnote()
+{
+}
+
+rtl::Reference<SwXFootnote>
+SwXFootnote::CreateXFootnote(SwDoc & rDoc, SwFormatFootnote *const pFootnoteFormat,
+ bool const isEndnote)
+{
+ // i#105557: do not iterate over the registered clients: race condition
+ rtl::Reference<SwXFootnote> xNote;
+ if (pFootnoteFormat)
+ {
+ xNote = pFootnoteFormat->GetXFootnote();
+ }
+ if (!xNote.is())
+ {
+ xNote = pFootnoteFormat
+ ? new SwXFootnote(rDoc, *pFootnoteFormat)
+ : new SwXFootnote(isEndnote);
+ if (pFootnoteFormat)
+ {
+ pFootnoteFormat->SetXFootnote(xNote);
+ }
+ // need a permanent Reference to initialize m_wThis
+ xNote->m_pImpl->m_wThis = xNote.get();
+ }
+ return xNote;
+}
+
+OUString SAL_CALL
+SwXFootnote::getImplementationName()
+{
+ return "SwXFootnote";
+}
+
+char const*const g_ServicesFootnote[] =
+{
+ "com.sun.star.text.TextContent",
+ "com.sun.star.text.Footnote",
+ "com.sun.star.text.Text",
+ "com.sun.star.text.Endnote", // NB: only supported for endnotes!
+};
+
+const size_t g_nServicesEndnote( SAL_N_ELEMENTS(g_ServicesFootnote) );
+
+const size_t g_nServicesFootnote( g_nServicesEndnote - 1 ); // NB: omit!
+
+sal_Bool SAL_CALL SwXFootnote::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL
+SwXFootnote::getSupportedServiceNames()
+{
+ SolarMutexGuard g;
+ return GetSupportedServiceNamesImpl(
+ (m_pImpl->m_bIsEndnote) ? g_nServicesEndnote : g_nServicesFootnote,
+ g_ServicesFootnote);
+}
+
+uno::Sequence< uno::Type > SAL_CALL
+SwXFootnote::getTypes()
+{
+ const uno::Sequence< uno::Type > aTypes = SwXFootnote_Base::getTypes();
+ const uno::Sequence< uno::Type > aTextTypes = SwXText::getTypes();
+ return ::comphelper::concatSequences(aTypes, aTextTypes);
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL
+SwXFootnote::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+uno::Any SAL_CALL
+SwXFootnote::queryInterface(const uno::Type& rType)
+{
+ const uno::Any ret = SwXFootnote_Base::queryInterface(rType);
+ return (ret.getValueType() == cppu::UnoType<void>::get())
+ ? SwXText::queryInterface(rType)
+ : ret;
+}
+
+OUString SAL_CALL SwXFootnote::getLabel()
+{
+ SolarMutexGuard aGuard;
+
+ OUString sRet;
+ SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat();
+ if(pFormat)
+ {
+ sRet = pFormat->GetNumStr();
+ }
+ else if (m_pImpl->m_bIsDescriptor)
+ {
+ sRet = m_pImpl->m_sLabel;
+ }
+ else
+ {
+ throw uno::RuntimeException();
+ }
+ return sRet;
+}
+
+void SAL_CALL
+SwXFootnote::setLabel(const OUString& aLabel)
+{
+ SolarMutexGuard aGuard;
+ OUString newLabel(aLabel);
+ //new line must not occur as footnote label
+ if(newLabel.indexOf('\n') >=0 )
+ {
+ newLabel = newLabel.replace('\n', ' ');
+ }
+ SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat();
+ if(pFormat)
+ {
+ const SwTextFootnote* pTextFootnote = pFormat->GetTextFootnote();
+ OSL_ENSURE(pTextFootnote, "No TextNode?");
+ SwTextNode& rTextNode = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
+
+ SwPaM aPam(rTextNode, pTextFootnote->GetStart());
+ GetDoc()->SetCurFootnote(aPam, newLabel, pFormat->IsEndNote());
+ }
+ else if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_sLabel = newLabel;
+ }
+ else
+ {
+ throw uno::RuntimeException();
+ }
+}
+
+void SAL_CALL
+SwXFootnote::attach(const uno::Reference< text::XTextRange > & xTextRange)
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pImpl->m_bIsDescriptor)
+ {
+ throw uno::RuntimeException();
+ }
+ SwXTextRange *const pRange = dynamic_cast<SwXTextRange*>(xTextRange.get());
+ OTextCursorHelper *const pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get());
+ SwDoc *const pNewDoc =
+ pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr);
+ if (!pNewDoc)
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ SwUnoInternalPaM aPam(*pNewDoc);
+ // this now needs to return TRUE
+ ::sw::XTextRangeToSwPaM(aPam, xTextRange);
+
+ UnoActionContext aCont(pNewDoc);
+ pNewDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ aPam.DeleteMark();
+ SwFormatFootnote aFootNote(m_pImpl->m_bIsEndnote);
+ if (!m_pImpl->m_sLabel.isEmpty())
+ {
+ aFootNote.SetNumStr(m_pImpl->m_sLabel);
+ }
+
+ SwXTextCursor const*const pTextCursor(
+ dynamic_cast<SwXTextCursor*>(pCursor));
+ const bool bForceExpandHints( pTextCursor && pTextCursor->IsAtEndOfMeta() );
+ const SetAttrMode nInsertFlags = bForceExpandHints
+ ? SetAttrMode::FORCEHINTEXPAND
+ : SetAttrMode::DEFAULT;
+
+ pNewDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aFootNote, nInsertFlags);
+
+ SwTextFootnote *const pTextAttr = static_cast<SwTextFootnote*>(
+ aPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt(
+ aPam.GetPoint()->GetContentIndex()-1, RES_TXTATR_FTN ));
+
+ if (pTextAttr)
+ {
+ m_pImpl->EndListeningAll();
+ SwFormatFootnote* pFootnote = const_cast<SwFormatFootnote*>(&pTextAttr->GetFootnote());
+ m_pImpl->m_pFormatFootnote = pFootnote;
+ m_pImpl->StartListening(pFootnote->GetNotifier());
+ // force creation of sequence id - is used for references
+ if (pNewDoc->IsInReading())
+ {
+ pTextAttr->SetSeqNo(pNewDoc->GetFootnoteIdxs().size());
+ }
+ else
+ {
+ pTextAttr->SetSeqRefNo();
+ }
+ }
+ m_pImpl->m_bIsDescriptor = false;
+ SetDoc(pNewDoc);
+}
+
+uno::Reference< text::XTextRange > SAL_CALL
+SwXFootnote::getAnchor()
+{
+ SolarMutexGuard aGuard;
+ return m_pImpl->GetFootnoteFormatOrThrow().getAnchor(*GetDoc());
+}
+
+void SAL_CALL SwXFootnote::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() );
+
+ SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote();
+ OSL_ENSURE(pTextFootnote, "no TextNode?");
+ SwTextNode& rTextNode = const_cast<SwTextNode&>(pTextFootnote->GetTextNode());
+ const sal_Int32 nPos = pTextFootnote->GetStart();
+ SwPaM aPam(rTextNode, nPos, rTextNode, nPos+1);
+ GetDoc()->getIDocumentContentOperations().DeleteAndJoin( aPam );
+}
+
+void SAL_CALL
+SwXFootnote::addEventListener(
+ const uno::Reference< lang::XEventListener > & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_EventListeners.addInterface(aGuard, xListener);
+}
+
+void SAL_CALL
+SwXFootnote::removeEventListener(
+ const uno::Reference< lang::XEventListener > & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_EventListeners.removeInterface(aGuard, xListener);
+}
+
+const SwStartNode *SwXFootnote::GetStartNode() const
+{
+ SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat();
+ if(pFormat)
+ {
+ const SwTextFootnote* pTextFootnote = pFormat->GetTextFootnote();
+ if( pTextFootnote )
+ {
+ return pTextFootnote->GetStartNode()->GetNode().GetStartNode();
+ }
+ }
+ return nullptr;
+}
+
+rtl::Reference< SwXTextCursor >
+SwXFootnote::createXTextCursor()
+{
+ SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() );
+
+ SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote();
+ SwPosition aPos( *pTextFootnote->GetStartNode() );
+ rtl::Reference<SwXTextCursor> pXCursor =
+ new SwXTextCursor(*GetDoc(), this, CursorType::Footnote, aPos);
+ auto& rUnoCursor(pXCursor->GetCursor());
+ rUnoCursor.Move(fnMoveForward, GoInNode);
+ return pXCursor;
+}
+
+rtl::Reference< SwXTextCursor >
+SwXFootnote::createXTextCursorByRange(
+ const uno::Reference< text::XTextRange > & xTextPosition)
+{
+ SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() );
+
+ SwUnoInternalPaM aPam(*GetDoc());
+ if (!::sw::XTextRangeToSwPaM(aPam, xTextPosition))
+ {
+ throw uno::RuntimeException();
+ }
+
+ SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote();
+ SwNode const*const pFootnoteStartNode = &pTextFootnote->GetStartNode()->GetNode();
+
+ const SwNode* pStart = aPam.GetPointNode().FindFootnoteStartNode();
+ if (pStart != pFootnoteStartNode)
+ {
+ throw uno::RuntimeException();
+ }
+
+ const rtl::Reference< SwXTextCursor > xRet =
+ new SwXTextCursor(*GetDoc(), this, CursorType::Footnote,
+ *aPam.GetPoint(), aPam.GetMark());
+ return xRet;
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+SwXFootnote::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+
+ SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() );
+
+ SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote();
+ SwPosition aPos( *pTextFootnote->GetStartNode() );
+ auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Footnote);
+}
+
+uno::Type SAL_CALL SwXFootnote::getElementType()
+{
+ return cppu::UnoType<text::XTextRange>::get();
+}
+
+sal_Bool SAL_CALL SwXFootnote::hasElements()
+{
+ return true;
+}
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL
+SwXFootnote::getPropertySetInfo()
+{
+ SolarMutexGuard g;
+ static uno::Reference< beans::XPropertySetInfo > xRet =
+ aSwMapProvider.GetPropertySet(PROPERTY_MAP_FOOTNOTE)
+ ->getPropertySetInfo();
+ return xRet;
+}
+
+void SAL_CALL
+SwXFootnote::setPropertyValue(const OUString&, const uno::Any&)
+{
+ //no values to be set
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL
+SwXFootnote::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aRet;
+ if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName))
+ {
+ if (rPropertyName == UNO_NAME_START_REDLINE ||
+ rPropertyName == UNO_NAME_END_REDLINE)
+ {
+ //redline can only be returned if it's a living object
+ if (!m_pImpl->m_bIsDescriptor)
+ {
+ aRet = SwXText::getPropertyValue(rPropertyName);
+ }
+ }
+ else if (rPropertyName == UNO_NAME_REFERENCE_ID)
+ {
+ SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat();
+ if (pFormat)
+ {
+ SwTextFootnote const*const pTextFootnote = pFormat->GetTextFootnote();
+ OSL_ENSURE(pTextFootnote, "no TextNode?");
+ aRet <<= static_cast<sal_Int16>(pTextFootnote->GetSeqRefNo());
+ }
+ }
+ else
+ {
+ throw beans::UnknownPropertyException(rPropertyName);
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL
+SwXFootnote::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
+{
+ OSL_FAIL("SwXFootnote::addPropertyChangeListener(): not implemented");
+}
+
+void SAL_CALL
+SwXFootnote::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
+{
+ OSL_FAIL("SwXFootnote::removePropertyChangeListener(): not implemented");
+}
+
+void SAL_CALL
+SwXFootnote::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
+{
+ OSL_FAIL("SwXFootnote::addVetoableChangeListener(): not implemented");
+}
+
+void SAL_CALL
+SwXFootnote::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
+{
+ OSL_FAIL("SwXFootnote::removeVetoableChangeListener(): not implemented");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */