/* -*- 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 <com/sun/star/io/IOException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/container/ElementExistException.hpp>
#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
#include <rtl/character.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include <svtools/unoevent.hxx>
#include <sfx2/event.hxx>
#include <glosdoc.hxx>
#include <shellio.hxx>
#include <initui.hxx>
#include <gloslst.hxx>
#include <unoatxt.hxx>
#include <unomap.hxx>
#include <unotextbodyhf.hxx>
#include <unotextrange.hxx>
#include <TextCursorHelper.hxx>
#include <doc.hxx>
#include <IDocumentContentOperations.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentState.hxx>
#include <docsh.hxx>
#include <swdll.hxx>
#include <svl/hint.hxx>
#include <tools/urlobj.hxx>
#include <svl/macitem.hxx>
#include <editeng/acorrcfg.hxx>
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <memory>
using namespace ::com::sun::star;
SwXAutoTextContainer::SwXAutoTextContainer()
{
m_pGlossaries = ::GetGlossaries();
}
SwXAutoTextContainer::~SwXAutoTextContainer()
{
}
sal_Int32 SwXAutoTextContainer::getCount()
{
OSL_ENSURE(m_pGlossaries->GetGroupCnt() < o3tl::make_unsigned(SAL_MAX_INT32),
"SwXAutoTextContainer::getCount: too many items");
return static_cast<sal_Int32>(m_pGlossaries->GetGroupCnt());
}
uno::Any SwXAutoTextContainer::getByIndex(sal_Int32 nIndex)
{
SolarMutexGuard aGuard;
const size_t nCount = m_pGlossaries->GetGroupCnt();
if ( nIndex < 0 || o3tl::make_unsigned(nIndex) >= nCount )
throw lang::IndexOutOfBoundsException();
return getByName(m_pGlossaries->GetGroupName( static_cast<size_t>(nIndex) ));
}
uno::Type SwXAutoTextContainer::getElementType()
{
return cppu::UnoType<text::XAutoTextGroup>::get();
}
sal_Bool SwXAutoTextContainer::hasElements()
{
// At least standard should always exists!
return true;
}
uno::Any SwXAutoTextContainer::getByName(const OUString& GroupName)
{
SolarMutexGuard aGuard;
uno::Reference< text::XAutoTextGroup > xGroup;
if ( m_pGlossaries && hasByName( GroupName ) ) // group name already known?
// true = create group if not already available
xGroup = m_pGlossaries->GetAutoTextGroup( GroupName );
if ( !xGroup.is() )
throw container::NoSuchElementException();
return css::uno::Any( xGroup );
}
uno::Sequence< OUString > SwXAutoTextContainer::getElementNames()
{
SolarMutexGuard aGuard;
const size_t nCount = m_pGlossaries->GetGroupCnt();
OSL_ENSURE(nCount < o3tl::make_unsigned(SAL_MAX_INT32),
"SwXAutoTextContainer::getElementNames: too many groups");
uno::Sequence< OUString > aGroupNames(static_cast<sal_Int32>(nCount));
OUString *pArr = aGroupNames.getArray();
for ( size_t i = 0; i < nCount; ++i )
{
// The names will be passed without a path extension.
pArr[i] = m_pGlossaries->GetGroupName(i).getToken(0, GLOS_DELIM);
}
return aGroupNames;
}
// Finds group names with or without path index.
sal_Bool SwXAutoTextContainer::hasByName(const OUString& Name)
{
SolarMutexGuard aGuard;
OUString sGroupName( m_pGlossaries->GetCompleteGroupName( Name ) );
if(!sGroupName.isEmpty())
return true;
return false;
}
uno::Reference< text::XAutoTextGroup > SwXAutoTextContainer::insertNewByName(
const OUString& aGroupName)
{
SolarMutexGuard aGuard;
if(hasByName(aGroupName))
throw container::ElementExistException();
//check for non-ASCII characters
if(aGroupName.isEmpty())
{
throw lang::IllegalArgumentException(u"group name must not be empty"_ustr, nullptr, 0);
}
for(sal_Int32 nPos = 0; nPos < aGroupName.getLength(); nPos++)
{
sal_Unicode cChar = aGroupName[nPos];
if (rtl::isAsciiAlphanumeric(cChar) ||
(cChar == '_') ||
(cChar == 0x20) ||
(cChar == GLOS_DELIM) )
{
continue;
}
throw lang::IllegalArgumentException(u"group name must contain a-z, A-z, '_', ' ' only"_ustr, nullptr, 0);
}
OUString sGroup(aGroupName);
if (sGroup.indexOf(GLOS_DELIM)<0)
{
sGroup += OUStringChar(GLOS_DELIM) + "0";
}
m_pGlossaries->NewGroupDoc(sGroup, sGroup.getToken(0, GLOS_DELIM));
uno::Reference< text::XAutoTextGroup > xGroup = m_pGlossaries->GetAutoTextGroup( sGroup );
OSL_ENSURE( xGroup.is(), "SwXAutoTextContainer::insertNewByName: no UNO object created? How this?" );
// We just inserted the group into the glossaries, so why doesn't it exist?
return xGroup;
}
void SwXAutoTextContainer::removeByName(const OUString& aGroupName)
{
SolarMutexGuard aGuard;
// At first find the name with path extension
OUString sGroupName = m_pGlossaries->GetCompleteGroupName( aGroupName );
if(sGroupName.isEmpty())
throw container::NoSuchElementException();
m_pGlossaries->DelGroupDoc(sGroupName);
}
OUString SwXAutoTextContainer::getImplementationName()
{
return u"SwXAutoTextContainer"_ustr;
}
sal_Bool SwXAutoTextContainer::supportsService(const OUString& rServiceName)
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence< OUString > SwXAutoTextContainer::getSupportedServiceNames()
{
return { u"com.sun.star.text.AutoTextContainer"_ustr };
}
SwXAutoTextGroup::SwXAutoTextGroup(const OUString& rName,
SwGlossaries* pGlos) :
m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_AUTO_TEXT_GROUP)),
m_pGlossaries(pGlos),
m_sName(rName),
m_sGroupName(rName)
{
OSL_ENSURE( -1 != rName.indexOf( GLOS_DELIM ),
"SwXAutoTextGroup::SwXAutoTextGroup: to be constructed with a complete name only!" );
}
SwXAutoTextGroup::~SwXAutoTextGroup()
{
}
uno::Sequence< OUString > SwXAutoTextGroup::getTitles()
{
SolarMutexGuard aGuard;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
const sal_uInt16 nCount = pGlosGroup->GetCount();
uno::Sequence< OUString > aEntryTitles(nCount);
OUString *pArr = aEntryTitles.getArray();
for ( sal_uInt16 i = 0; i < nCount; i++ )
pArr[i] = pGlosGroup->GetLongName(i);
return aEntryTitles;
}
void SwXAutoTextGroup::renameByName(const OUString& aElementName,
const OUString& aNewElementName, const OUString& aNewElementTitle)
{
SolarMutexGuard aGuard;
// throw exception only if the programmatic name is to be changed into an existing name
if(aNewElementName != aElementName && hasByName(aNewElementName))
throw container::ElementExistException();
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if(!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
const sal_uInt16 nIdx = pGlosGroup->GetIndex( aElementName);
if(USHRT_MAX == nIdx)
throw lang::IllegalArgumentException();
const OUString& aNewShort(aNewElementName);
const OUString& aNewName(aNewElementTitle);
sal_uInt16 nOldLongIdx = pGlosGroup->GetLongIndex( aNewShort );
sal_uInt16 nOldIdx = pGlosGroup->GetIndex( aNewName );
if ((nOldLongIdx == USHRT_MAX || nOldLongIdx == nIdx)
&& (nOldIdx == USHRT_MAX || nOldIdx == nIdx))
{
pGlosGroup->Rename( nIdx, &aNewShort, &aNewName );
if(pGlosGroup->GetError() != ERRCODE_NONE)
throw io::IOException();
}
}
static bool lcl_CopySelToDoc(SwDoc& rInsDoc, OTextCursorHelper* pxCursor, SwXTextRange* pxRange)
{
SwNodes& rNds = rInsDoc.GetNodes();
SwNodeIndex aIdx( rNds.GetEndOfContent(), -1 );
SwContentNode * pNd = aIdx.GetNode().GetContentNode();
SwPosition aPos(aIdx, pNd, pNd ? pNd->Len() : 0);
bool bRet = false;
rInsDoc.getIDocumentFieldsAccess().LockExpFields();
{
SwDoc *const pDoc(pxCursor ? pxCursor->GetDoc() : &pxRange->GetDoc());
SwPaM aPam(pDoc->GetNodes());
SwPaM * pPam(nullptr);
if(pxCursor)
{
pPam = pxCursor->GetPaM();
}
else
{
if (pxRange->GetPositions(aPam))
{
pPam = & aPam;
}
}
if (!pPam) { return false; }
bRet = pDoc->getIDocumentContentOperations().CopyRange(*pPam, aPos, SwCopyFlags::CheckPosInFly)
|| bRet;
}
rInsDoc.getIDocumentFieldsAccess().UnlockExpFields();
if( !rInsDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() )
rInsDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
return bRet;
}
uno::Reference< text::XAutoTextEntry > SwXAutoTextGroup::insertNewByName(const OUString& aName,
const OUString& aTitle, const uno::Reference< text::XTextRange > & xTextRange)
{
SolarMutexGuard aGuard;
if(hasByName(aName))
throw container::ElementExistException();
if(!xTextRange.is())
throw uno::RuntimeException();
std::unique_ptr<SwTextBlocks> pGlosGroup;
if (m_pGlossaries)
pGlosGroup = m_pGlossaries->GetGroupDoc(m_sGroupName);
const OUString& sShortName(aName);
const OUString& sLongName(aTitle);
if (pGlosGroup && !pGlosGroup->GetError())
{
SwXTextRange* pxRange = dynamic_cast<SwXTextRange*>(xTextRange.get());
OTextCursorHelper* pxCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get());
OUString sOnlyText;
OUString* pOnlyText = nullptr;
bool bNoAttr = !pxCursor && !pxRange;
if(bNoAttr)
{
sOnlyText = xTextRange->getString();
pOnlyText = &sOnlyText;
}
const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
SwDoc* pGDoc = pGlosGroup->GetDoc();
// Until there is an option for that, delete base util::URL
if(rCfg.IsSaveRelFile())
{
INetURLObject aTemp(pGlosGroup->GetFileName());
pGlosGroup->SetBaseURL( aTemp.GetMainURL(INetURLObject::DecodeMechanism::NONE));
}
else
pGlosGroup->SetBaseURL( OUString() );
sal_uInt16 nRet = USHRT_MAX;
if( pOnlyText )
nRet = pGlosGroup->PutText( sShortName, sLongName, *pOnlyText );
else
{
pGlosGroup->ClearDoc();
if( pGlosGroup->BeginPutDoc( sShortName, sLongName ) )
{
pGDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
lcl_CopySelToDoc(*pGDoc, pxCursor, pxRange);
pGDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern(RedlineFlags::NONE);
nRet = pGlosGroup->PutDoc();
}
}
if (nRet == USHRT_MAX)
{
throw uno::RuntimeException();
}
}
pGlosGroup.reset();
uno::Reference< text::XAutoTextEntry > xEntry;
try
{
xEntry = m_pGlossaries ?
m_pGlossaries->GetAutoTextEntry( m_sGroupName, m_sName, sShortName ) :
uno::Reference< text::XAutoTextEntry >();
OSL_ENSURE( xEntry.is(), "SwXAutoTextGroup::insertNewByName: no UNO object created? How this?" );
// we just inserted the entry into the group, so why doesn't it exist?
}
catch (const container::ElementExistException&)
{
throw;
}
catch (const uno::RuntimeException&)
{
throw;
}
catch (const uno::Exception&)
{
css::uno::Any anyEx = cppu::getCaughtException();
throw css::lang::WrappedTargetRuntimeException(
u"Error Getting AutoText!"_ustr,
getXWeak(),
anyEx );
}
return xEntry;
}
void SwXAutoTextGroup::removeByName(const OUString& aEntryName)
{
SolarMutexGuard aGuard;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if(!pGlosGroup || pGlosGroup->GetError())
throw container::NoSuchElementException();
sal_uInt16 nIdx = pGlosGroup->GetIndex(aEntryName);
if ( nIdx == USHRT_MAX )
throw container::NoSuchElementException();
pGlosGroup->Delete(nIdx);
}
OUString SwXAutoTextGroup::getName()
{
SolarMutexGuard aGuard;
return m_sName;
}
void SwXAutoTextGroup::setName(const OUString& rName)
{
SolarMutexGuard aGuard;
if( !m_pGlossaries )
throw uno::RuntimeException();
sal_Int32 nNewDelimPos = rName.lastIndexOf( GLOS_DELIM );
sal_Int32 nOldDelimPos = m_sName.lastIndexOf( GLOS_DELIM );
OUString aNewSuffix;
if (nNewDelimPos > -1)
aNewSuffix = rName.copy( nNewDelimPos + 1 );
OUString aOldSuffix;
if (nOldDelimPos > -1)
aOldSuffix = m_sName.copy( nOldDelimPos + 1 );
sal_Int32 nNewNumeric = aNewSuffix.toInt32();
sal_Int32 nOldNumeric = aOldSuffix.toInt32();
OUString aNewPrefix( (nNewDelimPos > 1) ? rName.copy( 0, nNewDelimPos ) : rName );
OUString aOldPrefix( (nOldDelimPos > 1) ? m_sName.copy( 0, nOldDelimPos ) : m_sName );
if ( m_sName == rName ||
( nNewNumeric == nOldNumeric && aNewPrefix == aOldPrefix ) )
return;
OUString sNewGroup(rName);
if (sNewGroup.indexOf(GLOS_DELIM)<0)
{
sNewGroup += OUStringChar(GLOS_DELIM) + "0";
}
//the name must be saved, the group may be invalidated while in RenameGroupDoc()
SwGlossaries* pTempGlossaries = m_pGlossaries;
OUString sPreserveTitle( m_pGlossaries->GetGroupTitle( m_sName ) );
if ( !m_pGlossaries->RenameGroupDoc( m_sName, sNewGroup, sPreserveTitle ) )
throw uno::RuntimeException();
m_sName = rName;
m_sGroupName = sNewGroup;
m_pGlossaries = pTempGlossaries;
}
sal_Int32 SwXAutoTextGroup::getCount()
{
SolarMutexGuard aGuard;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
return static_cast<sal_Int32>(pGlosGroup->GetCount());
}
uno::Any SwXAutoTextGroup::getByIndex(sal_Int32 nIndex)
{
SolarMutexGuard aGuard;
if (!m_pGlossaries)
throw uno::RuntimeException();
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries->GetGroupDoc(m_sGroupName));
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
const sal_uInt16 nCount = pGlosGroup->GetCount();
if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= nCount)
throw lang::IndexOutOfBoundsException();
return getByName(pGlosGroup->GetShortName(o3tl::narrowing<sal_uInt16>(nIndex)));
}
uno::Type SwXAutoTextGroup::getElementType()
{
return cppu::UnoType<text::XAutoTextEntry>::get();
}
sal_Bool SwXAutoTextGroup::hasElements()
{
SolarMutexGuard aGuard;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
return pGlosGroup->GetCount() > 0;
}
uno::Any SwXAutoTextGroup::getByName(const OUString& _rName)
{
SolarMutexGuard aGuard;
uno::Reference< text::XAutoTextEntry > xEntry = m_pGlossaries->GetAutoTextEntry( m_sGroupName, m_sName, _rName );
OSL_ENSURE( xEntry.is(), "SwXAutoTextGroup::getByName: GetAutoTextEntry is fractious!" );
// we told it to create the object, so why didn't it?
return css::uno::Any( xEntry );
}
uno::Sequence< OUString > SwXAutoTextGroup::getElementNames()
{
SolarMutexGuard aGuard;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
const sal_uInt16 nCount = pGlosGroup->GetCount();
uno::Sequence< OUString > aEntryNames(nCount);
OUString *pArr = aEntryNames.getArray();
for ( sal_uInt16 i = 0; i < nCount; i++ )
pArr[i] = pGlosGroup->GetShortName(i);
return aEntryNames;
}
sal_Bool SwXAutoTextGroup::hasByName(const OUString& rName)
{
SolarMutexGuard aGuard;
bool bRet = false;
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if (!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
const sal_uInt16 nCount = pGlosGroup->GetCount();
for( sal_uInt16 i = 0; i < nCount; ++i )
{
OUString sCompare(pGlosGroup->GetShortName(i));
if(sCompare.equalsIgnoreAsciiCase(rName))
{
bRet = true;
break;
}
}
return bRet;
}
uno::Reference< beans::XPropertySetInfo > SwXAutoTextGroup::getPropertySetInfo()
{
static uno::Reference< beans::XPropertySetInfo > xRet = m_pPropSet->getPropertySetInfo();
return xRet;
}
void SwXAutoTextGroup::setPropertyValue(
const OUString& rPropertyName, const uno::Any& aValue)
{
SolarMutexGuard aGuard;
const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName );
if(!pEntry)
throw beans::UnknownPropertyException(rPropertyName);
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if(!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
switch(pEntry->nWID)
{
case WID_GROUP_TITLE:
{
OUString sNewTitle;
aValue >>= sNewTitle;
if(sNewTitle.isEmpty())
throw lang::IllegalArgumentException();
bool bChanged = sNewTitle != pGlosGroup->GetName();
pGlosGroup->SetName(sNewTitle);
if(bChanged && HasGlossaryList())
GetGlossaryList()->ClearGroups();
}
break;
}
}
uno::Any SwXAutoTextGroup::getPropertyValue(const OUString& rPropertyName)
{
SolarMutexGuard aGuard;
const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName);
if(!pEntry)
throw beans::UnknownPropertyException(rPropertyName);
std::unique_ptr<SwTextBlocks> pGlosGroup(m_pGlossaries ? m_pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
if(!pGlosGroup || pGlosGroup->GetError())
throw uno::RuntimeException();
uno::Any aAny;
switch(pEntry->nWID)
{
case WID_GROUP_PATH:
aAny <<= pGlosGroup->GetFileName();
break;
case WID_GROUP_TITLE:
aAny <<= pGlosGroup->GetName();
break;
}
return aAny;
}
void SwXAutoTextGroup::addPropertyChangeListener(
const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
{
}
void SwXAutoTextGroup::removePropertyChangeListener(
const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
{
}
void SwXAutoTextGroup::addVetoableChangeListener(
const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
{
}
void SwXAutoTextGroup::removeVetoableChangeListener(
const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
{
}
void SwXAutoTextGroup::Invalidate()
{
m_pGlossaries = nullptr;
m_sName.clear();
m_sGroupName.clear();
}
OUString SwXAutoTextGroup::getImplementationName()
{
return u"SwXAutoTextGroup"_ustr;
}
sal_Bool SwXAutoTextGroup::supportsService(const OUString& rServiceName)
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence< OUString > SwXAutoTextGroup::getSupportedServiceNames()
{
uno::Sequence<OUString> aRet { u"com.sun.star.text.AutoTextGroup"_ustr };
return aRet;
}
SwXAutoTextEntry::SwXAutoTextEntry(SwGlossaries* pGlss, OUString aGroupName,
OUString aEntryName) :
m_pGlossaries(pGlss),
m_sGroupName(std::move(aGroupName)),
m_sEntryName(std::move(aEntryName))
{
}
SwXAutoTextEntry::~SwXAutoTextEntry()
{
SolarMutexGuard aGuard;
// ensure that any pending modifications are written
implFlushDocument( true );
}
void SwXAutoTextEntry::implFlushDocument( bool _bCloseDoc )
{
if ( !m_xDocSh.is() )
return;
if ( m_xDocSh->GetDoc()->getIDocumentState().IsModified () )
m_xDocSh->Save();
if ( _bCloseDoc )
{
// stop listening at the document
EndListening( *m_xDocSh );
m_xDocSh->DoClose();
m_xDocSh.clear();
}
}
void SwXAutoTextEntry::Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint )
{
if ( &_rBC != m_xDocSh.get() )
return;
// it's our document
if (_rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
{
const SfxEventHint& rEventHint = static_cast<const SfxEventHint&>(_rHint);
if (SfxEventHintId::PrepareCloseDoc == rEventHint.GetEventId())
{
implFlushDocument();
mxBodyText.clear();
EndListening( *m_xDocSh );
m_xDocSh.clear();
}
}
else
{
if ( SfxHintId::Deinitializing == _rHint.GetId() )
{
// our document is dying (possibly because we're shutting down, and the document was notified
// earlier than we are?)
// stop listening at the docu
EndListening( *m_xDocSh );
// and release our reference
m_xDocSh.clear();
}
}
}
void SwXAutoTextEntry::GetBodyText ()
{
SolarMutexGuard aGuard;
m_xDocSh = m_pGlossaries->EditGroupDoc ( m_sGroupName, m_sEntryName, false );
OSL_ENSURE( m_xDocSh.is(), "SwXAutoTextEntry::GetBodyText: unexpected: no doc returned by EditGroupDoc!" );
// start listening at the document
StartListening( *m_xDocSh );
mxBodyText = new SwXBodyText ( m_xDocSh->GetDoc() );
}
void SwXAutoTextEntry::disposing(std::unique_lock<std::mutex>&)
{
SolarMutexGuard g;
implFlushDocument(true);
}
uno::Reference< text::XTextCursor > SwXAutoTextEntry::createTextCursor()
{
SolarMutexGuard aGuard;
EnsureBodyText();
return mxBodyText->createTextCursor();
}
uno::Reference< text::XTextCursor > SwXAutoTextEntry::createTextCursorByRange(
const uno::Reference< text::XTextRange > & aTextPosition)
{
SolarMutexGuard aGuard;
EnsureBodyText();
return mxBodyText->createTextCursorByRange ( aTextPosition );
}
void SwXAutoTextEntry::insertString(const uno::Reference< text::XTextRange > & xRange, const OUString& aString, sal_Bool bAbsorb)
{
SolarMutexGuard aGuard;
EnsureBodyText();
mxBodyText->insertString ( xRange, aString, bAbsorb );
}
void SwXAutoTextEntry::insertControlCharacter(const uno::Reference< text::XTextRange > & xRange,
sal_Int16 nControlCharacter, sal_Bool bAbsorb)
{
SolarMutexGuard aGuard;
EnsureBodyText();
mxBodyText->insertControlCharacter ( xRange, nControlCharacter, bAbsorb );
}
void SwXAutoTextEntry::insertTextContent(
const uno::Reference< text::XTextRange > & xRange,
const uno::Reference< text::XTextContent > & xContent, sal_Bool bAbsorb)
{
SolarMutexGuard aGuard;
EnsureBodyText();
mxBodyText->insertTextContent ( xRange, xContent, bAbsorb );
}
void SwXAutoTextEntry::removeTextContent(
const uno::Reference< text::XTextContent > & xContent)
{
SolarMutexGuard aGuard;
EnsureBodyText();
mxBodyText->removeTextContent ( xContent );
}
uno::Reference< text::XText > SwXAutoTextEntry::getText()
{
SolarMutexGuard aGuard;
uno::Reference< text::XText > xRet = static_cast<text::XText*>(this);
return xRet;
}
uno::Reference< text::XTextRange > SwXAutoTextEntry::getStart()
{
SolarMutexGuard aGuard;
EnsureBodyText();
return mxBodyText->getStart();
}
uno::Reference< text::XTextRange > SwXAutoTextEntry::getEnd()
{
SolarMutexGuard aGuard;
EnsureBodyText();
return mxBodyText->getEnd();
}
OUString SwXAutoTextEntry::getString()
{
SolarMutexGuard aGuard;
EnsureBodyText();
return mxBodyText->getString();
}
void SwXAutoTextEntry::setString(const OUString& aString)
{
SolarMutexGuard aGuard;
EnsureBodyText();
mxBodyText->setString( aString );
}
void SwXAutoTextEntry::applyTo(const uno::Reference< text::XTextRange > & xTextRange)
{
SolarMutexGuard aGuard;
// ensure that any pending modifications are written
// reason is that we're holding the _copy_ of the auto text, while the real auto text
// is stored somewhere. And below, we're not working with our copy, but only tell the target
// TextRange to work with the stored version.
// #96380# - 2003-03-03 - fs@openoffice.org
implFlushDocument();
// TODO: think about if we should pass "true" here
// The difference would be that when the next modification is made to this instance here, then
// we would be forced to open the document again, instead of working on our current copy.
// This means that we would reflect any changes which were done to the AutoText by foreign instances
// in the meantime
// The reference to xKeepAlive is needed during the whole call, likely because it could be a
// different object, not xTextRange itself, and the reference guards it from preliminary death
auto xKeepAlive( xTextRange );
SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get());
OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get());
SwXText *pText = dynamic_cast<SwXText*>(xTextRange.get());
SwDoc* pDoc = nullptr;
if (pRange)
pDoc = &pRange->GetDoc();
else if ( pCursor )
pDoc = pCursor->GetDoc();
else if ( pText && pText->GetDoc() )
{
xKeepAlive = pText->getStart();
pCursor = dynamic_cast<OTextCursorHelper*>(xKeepAlive.get());
if (pCursor)
pDoc = pText->GetDoc();
}
if(!pDoc)
throw uno::RuntimeException();
SwPaM InsertPaM(pDoc->GetNodes());
if (pRange)
{
if (!pRange->GetPositions(InsertPaM))
{
throw uno::RuntimeException();
}
}
else
{
InsertPaM = *pCursor->GetPaM();
}
std::unique_ptr<SwTextBlocks> pBlock(m_pGlossaries->GetGroupDoc(m_sGroupName));
const bool bResult = pBlock && !pBlock->GetError()
&& pDoc->InsertGlossary( *pBlock, m_sEntryName, InsertPaM);
if(!bResult)
throw uno::RuntimeException();
}
OUString SwXAutoTextEntry::getImplementationName()
{
return u"SwXAutoTextEntry"_ustr;
}
sal_Bool SwXAutoTextEntry::supportsService(const OUString& rServiceName)
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence< OUString > SwXAutoTextEntry::getSupportedServiceNames()
{
uno::Sequence<OUString> aRet { u"com.sun.star.text.AutoTextEntry"_ustr };
return aRet;
}
uno::Reference< container::XNameReplace > SwXAutoTextEntry::getEvents()
{
return new SwAutoTextEventDescriptor( *this );
}
const struct SvEventDescription aAutotextEvents[] =
{
{ SvMacroItemId::SwStartInsGlossary, "OnInsertStart" },
{ SvMacroItemId::SwEndInsGlossary, "OnInsertDone" },
{ SvMacroItemId::NONE, nullptr }
};
SwAutoTextEventDescriptor::SwAutoTextEventDescriptor(
SwXAutoTextEntry& rAutoText ) :
SvBaseEventDescriptor(aAutotextEvents),
m_rAutoTextEntry(rAutoText)
{
}
SwAutoTextEventDescriptor::~SwAutoTextEventDescriptor()
{
}
OUString SwAutoTextEventDescriptor::getImplementationName()
{
return u"SwAutoTextEventDescriptor"_ustr;
}
void SwAutoTextEventDescriptor::replaceByName(
const SvMacroItemId nEvent,
const SvxMacro& rMacro)
{
OSL_ENSURE( nullptr != m_rAutoTextEntry.GetGlossaries(),
"Strangely enough, the AutoText vanished!" );
OSL_ENSURE( (nEvent == SvMacroItemId::SwEndInsGlossary) ||
(nEvent == SvMacroItemId::SwStartInsGlossary) ,
"Unknown event ID" );
SwGlossaries *const pGlossaries =
const_cast<SwGlossaries*>(m_rAutoTextEntry.GetGlossaries());
std::unique_ptr<SwTextBlocks> pBlocks(
pGlossaries->GetGroupDoc( m_rAutoTextEntry.GetGroupName() ));
OSL_ENSURE( pBlocks,
"can't get autotext group; SwAutoTextEntry has illegal name?");
if( !pBlocks || pBlocks->GetError())
return;
sal_uInt16 nIndex = pBlocks->GetIndex( m_rAutoTextEntry.GetEntryName() );
if( nIndex != USHRT_MAX )
{
SvxMacroTableDtor aMacroTable;
if( pBlocks->GetMacroTable( nIndex, aMacroTable ) )
{
aMacroTable.Insert( nEvent, rMacro );
pBlocks->SetMacroTable( nIndex, aMacroTable );
}
}
// else: ignore
}
void SwAutoTextEventDescriptor::getByName(
SvxMacro& rMacro,
const SvMacroItemId nEvent )
{
OSL_ENSURE( nullptr != m_rAutoTextEntry.GetGlossaries(), "no AutoText" );
OSL_ENSURE( (nEvent == SvMacroItemId::SwEndInsGlossary) ||
(nEvent == SvMacroItemId::SwStartInsGlossary) ,
"Unknown event ID" );
SwGlossaries *const pGlossaries =
const_cast<SwGlossaries*>(m_rAutoTextEntry.GetGlossaries());
std::unique_ptr<SwTextBlocks> pBlocks(
pGlossaries->GetGroupDoc( m_rAutoTextEntry.GetGroupName() ));
OSL_ENSURE( pBlocks,
"can't get autotext group; SwAutoTextEntry has illegal name?");
// return empty macro, unless macro is found
OUString sEmptyStr;
rMacro = SvxMacro(sEmptyStr, sEmptyStr);
if ( !pBlocks || pBlocks->GetError())
return;
sal_uInt16 nIndex = pBlocks->GetIndex( m_rAutoTextEntry.GetEntryName() );
if( nIndex != USHRT_MAX )
{
SvxMacroTableDtor aMacroTable;
if( pBlocks->GetMacroTable( nIndex, aMacroTable ) )
{
SvxMacro *pMacro = aMacroTable.Get( nEvent );
if( pMacro )
rMacro = *pMacro;
}
}
}
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
SwXAutoTextContainer_get_implementation(css::uno::XComponentContext*,
css::uno::Sequence<css::uno::Any> const &)
{
//the module may not be loaded
SolarMutexGuard aGuard;
SwGlobals::ensure();
return cppu::acquire(new SwXAutoTextContainer());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1048 The 'm_pGlossaries' variable was assigned the same value.