1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <com/sun/star/io/IOException.hpp>
23 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
24 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
25 #include <com/sun/star/container/ElementExistException.hpp>
26 #include <o3tl/safeint.hxx>
27 #include <osl/diagnose.h>
28 #include <rtl/character.hxx>
29 #include <vcl/svapp.hxx>
30 #include <svtools/unoevent.hxx>
31 #include <sfx2/event.hxx>
32 #include <glosdoc.hxx>
33 #include <shellio.hxx>
34 #include <initui.hxx>
35 #include <gloslst.hxx>
36 #include <unoatxt.hxx>
37 #include <unomap.hxx>
38 #include <unotextbodyhf.hxx>
39 #include <unotextrange.hxx>
40 #include <TextCursorHelper.hxx>
41 #include <doc.hxx>
42 #include <IDocumentContentOperations.hxx>
43 #include <IDocumentRedlineAccess.hxx>
44 #include <IDocumentFieldsAccess.hxx>
45 #include <IDocumentState.hxx>
46 #include <docsh.hxx>
47 #include <swdll.hxx>
48 #include <svl/hint.hxx>
49 #include <tools/urlobj.hxx>
50 #include <svl/macitem.hxx>
51 #include <editeng/acorrcfg.hxx>
52 #include <comphelper/servicehelper.hxx>
53 #include <cppuhelper/exc_hlp.hxx>
54 #include <cppuhelper/supportsservice.hxx>
55 
56 #include <memory>
57 
58 using namespace ::com::sun::star;
59 
SwXAutoTextContainer()60 SwXAutoTextContainer::SwXAutoTextContainer()
61 {
62     pGlossaries = ::GetGlossaries();
63 
64 }
65 
~SwXAutoTextContainer()66 SwXAutoTextContainer::~SwXAutoTextContainer()
67 {
68 
69 }
70 
getCount()71 sal_Int32 SwXAutoTextContainer::getCount()
72 {
73     OSL_ENSURE(pGlossaries->GetGroupCnt() < o3tl::make_unsigned(SAL_MAX_INT32),
74                "SwXAutoTextContainer::getCount: too many items");
75     return static_cast<sal_Int32>(pGlossaries->GetGroupCnt());
76 }
77 
getByIndex(sal_Int32 nIndex)78 uno::Any SwXAutoTextContainer::getByIndex(sal_Int32 nIndex)
79 {
80     SolarMutexGuard aGuard;
81     const size_t nCount = pGlossaries->GetGroupCnt();
82     if ( nIndex < 0 || o3tl::make_unsigned(nIndex) >= nCount )
83         throw lang::IndexOutOfBoundsException();
84     return getByName(pGlossaries->GetGroupName( static_cast<size_t>(nIndex) ));
85 }
86 
getElementType()87 uno::Type SwXAutoTextContainer::getElementType()
88 {
89     return cppu::UnoType<text::XAutoTextGroup>::get();
90 
91 }
92 
hasElements()93 sal_Bool SwXAutoTextContainer::hasElements()
94 {
95     // At least standard should always exists!
96     return true;
97 }
98 
getByName(const OUString & GroupName)99 uno::Any SwXAutoTextContainer::getByName(const OUString& GroupName)
100 {
101     SolarMutexGuard aGuard;
102 
103     uno::Reference< text::XAutoTextGroup > xGroup;
104     if ( pGlossaries && hasByName( GroupName ) )    // group name already known?
105         // true = create group if not already available
106         xGroup = pGlossaries->GetAutoTextGroup( GroupName );
107 
108     if ( !xGroup.is() )
109         throw container::NoSuchElementException();
110 
111     return makeAny( xGroup );
112 }
113 
getElementNames()114 uno::Sequence< OUString > SwXAutoTextContainer::getElementNames()
115 {
116     SolarMutexGuard aGuard;
117     const size_t nCount = pGlossaries->GetGroupCnt();
118     OSL_ENSURE(nCount < o3tl::make_unsigned(SAL_MAX_INT32),
119                "SwXAutoTextContainer::getElementNames: too many groups");
120 
121     uno::Sequence< OUString > aGroupNames(static_cast<sal_Int32>(nCount));
122     OUString *pArr = aGroupNames.getArray();
123 
124     for ( size_t i = 0; i < nCount; ++i )
125     {
126         // The names will be passed without a path extension.
127         pArr[i] = pGlossaries->GetGroupName(i).getToken(0, GLOS_DELIM);
128     }
129     return aGroupNames;
130 }
131 // Finds group names with or without path index.
hasByName(const OUString & Name)132 sal_Bool SwXAutoTextContainer::hasByName(const OUString& Name)
133 {
134     SolarMutexGuard aGuard;
135     OUString sGroupName( pGlossaries->GetCompleteGroupName( Name ) );
136     if(!sGroupName.isEmpty())
137         return true;
138     return false;
139 }
140 
insertNewByName(const OUString & aGroupName)141 uno::Reference< text::XAutoTextGroup >  SwXAutoTextContainer::insertNewByName(
142     const OUString& aGroupName)
143 {
144     SolarMutexGuard aGuard;
145     if(hasByName(aGroupName))
146         throw container::ElementExistException();
147     //check for non-ASCII characters
148     if(aGroupName.isEmpty())
149     {
150         lang::IllegalArgumentException aIllegal;
151         aIllegal.Message = "group name must not be empty";
152         throw aIllegal;
153     }
154     for(sal_Int32 nPos = 0; nPos < aGroupName.getLength(); nPos++)
155     {
156         sal_Unicode cChar = aGroupName[nPos];
157         if (rtl::isAsciiAlphanumeric(cChar) ||
158             (cChar == '_') ||
159             (cChar == 0x20) ||
160             (cChar == GLOS_DELIM) )
161         {
162             continue;
163         }
164         lang::IllegalArgumentException aIllegal;
165         aIllegal.Message = "group name must contain a-z, A-z, '_', ' ' only";
166         throw aIllegal;
167     }
168     OUString sGroup(aGroupName);
169     if (sGroup.indexOf(GLOS_DELIM)<0)
170     {
171         sGroup += OUStringChar(GLOS_DELIM) + "0";
172     }
173     pGlossaries->NewGroupDoc(sGroup, sGroup.getToken(0, GLOS_DELIM));
174 
175     uno::Reference< text::XAutoTextGroup > xGroup = pGlossaries->GetAutoTextGroup( sGroup );
176     OSL_ENSURE( xGroup.is(), "SwXAutoTextContainer::insertNewByName: no UNO object created? How this?" );
177         // We just inserted the group into the glossaries, so why doesn't it exist?
178 
179     return xGroup;
180 }
181 
removeByName(const OUString & aGroupName)182 void SwXAutoTextContainer::removeByName(const OUString& aGroupName)
183 {
184     SolarMutexGuard aGuard;
185     // At first find the name with path extension
186     OUString sGroupName = pGlossaries->GetCompleteGroupName( aGroupName );
187     if(sGroupName.isEmpty())
188         throw container::NoSuchElementException();
189     pGlossaries->DelGroupDoc(sGroupName);
190 }
191 
getImplementationName()192 OUString SwXAutoTextContainer::getImplementationName()
193 {
194     return "SwXAutoTextContainer";
195 }
196 
supportsService(const OUString & rServiceName)197 sal_Bool SwXAutoTextContainer::supportsService(const OUString& rServiceName)
198 {
199     return cppu::supportsService(this, rServiceName);
200 }
201 
getSupportedServiceNames()202 uno::Sequence< OUString > SwXAutoTextContainer::getSupportedServiceNames()
203 {
204     return { "com.sun.star.text.AutoTextContainer" };
205 }
206 
getUnoTunnelId()207 const uno::Sequence< sal_Int8 > & SwXAutoTextGroup::getUnoTunnelId()
208 {
209     static const UnoTunnelIdInit theSwXAutoTextGroupUnoTunnelId;
210     return theSwXAutoTextGroupUnoTunnelId.getSeq();
211 }
212 
getSomething(const uno::Sequence<sal_Int8> & rId)213 sal_Int64 SAL_CALL SwXAutoTextGroup::getSomething( const uno::Sequence< sal_Int8 >& rId )
214 {
215     if( isUnoTunnelId<SwXAutoTextGroup>(rId) )
216     {
217         return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ));
218     }
219     return 0;
220 }
221 
SwXAutoTextGroup(const OUString & rName,SwGlossaries * pGlos)222 SwXAutoTextGroup::SwXAutoTextGroup(const OUString& rName,
223             SwGlossaries*   pGlos) :
224     pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_AUTO_TEXT_GROUP)),
225     pGlossaries(pGlos),
226     sName(rName),
227     m_sGroupName(rName)
228 {
229     OSL_ENSURE( -1 != rName.indexOf( GLOS_DELIM ),
230         "SwXAutoTextGroup::SwXAutoTextGroup: to be constructed with a complete name only!" );
231 }
232 
~SwXAutoTextGroup()233 SwXAutoTextGroup::~SwXAutoTextGroup()
234 {
235 }
236 
getTitles()237 uno::Sequence< OUString > SwXAutoTextGroup::getTitles()
238 {
239     SolarMutexGuard aGuard;
240     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
241     if (!pGlosGroup || pGlosGroup->GetError())
242         throw uno::RuntimeException();
243     const sal_uInt16 nCount = pGlosGroup->GetCount();
244 
245     uno::Sequence< OUString > aEntryTitles(nCount);
246     OUString *pArr = aEntryTitles.getArray();
247 
248     for ( sal_uInt16 i = 0; i < nCount; i++ )
249         pArr[i] = pGlosGroup->GetLongName(i);
250     return aEntryTitles;
251 }
252 
renameByName(const OUString & aElementName,const OUString & aNewElementName,const OUString & aNewElementTitle)253 void SwXAutoTextGroup::renameByName(const OUString& aElementName,
254     const OUString& aNewElementName, const OUString& aNewElementTitle)
255 {
256     SolarMutexGuard aGuard;
257     // throw exception only if the programmatic name is to be changed into an existing name
258     if(aNewElementName != aElementName && hasByName(aNewElementName))
259         throw container::ElementExistException();
260     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
261     if(!pGlosGroup || pGlosGroup->GetError())
262         throw uno::RuntimeException();
263 
264     const sal_uInt16 nIdx = pGlosGroup->GetIndex( aElementName);
265     if(USHRT_MAX == nIdx)
266         throw lang::IllegalArgumentException();
267     OUString aNewShort(aNewElementName);
268     OUString aNewName(aNewElementTitle);
269     sal_uInt16 nOldLongIdx = pGlosGroup->GetLongIndex( aNewShort );
270     sal_uInt16 nOldIdx = pGlosGroup->GetIndex( aNewName );
271 
272     if ((nOldLongIdx == USHRT_MAX || nOldLongIdx == nIdx)
273         && (nOldIdx == USHRT_MAX || nOldIdx == nIdx))
274     {
275         pGlosGroup->Rename( nIdx, &aNewShort, &aNewName );
276         if(pGlosGroup->GetError() != ERRCODE_NONE)
277             throw io::IOException();
278     }
279 
280 }
281 
lcl_CopySelToDoc(SwDoc & rInsDoc,OTextCursorHelper * pxCursor,SwXTextRange * pxRange)282 static bool lcl_CopySelToDoc(SwDoc& rInsDoc, OTextCursorHelper* pxCursor, SwXTextRange* pxRange)
283 {
284     SwNodes& rNds = rInsDoc.GetNodes();
285 
286     SwNodeIndex aIdx( rNds.GetEndOfContent(), -1 );
287     SwContentNode * pNd = aIdx.GetNode().GetContentNode();
288     SwPosition aPos(aIdx, SwIndex(pNd, pNd ? pNd->Len() : 0));
289 
290     bool bRet = false;
291     rInsDoc.getIDocumentFieldsAccess().LockExpFields();
292     {
293         SwDoc *const pDoc(pxCursor ? pxCursor->GetDoc() : &pxRange->GetDoc());
294         SwPaM aPam(pDoc->GetNodes());
295         SwPaM * pPam(nullptr);
296         if(pxCursor)
297         {
298             pPam = pxCursor->GetPaM();
299         }
300         else
301         {
302             if (pxRange->GetPositions(aPam))
303             {
304                 pPam = & aPam;
305             }
306         }
307         if (!pPam) { return false; }
308         bRet = pDoc->getIDocumentContentOperations().CopyRange(*pPam, aPos, SwCopyFlags::CheckPosInFly)
309             || bRet;
310     }
311 
312     rInsDoc.getIDocumentFieldsAccess().UnlockExpFields();
313     if( !rInsDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() )
314         rInsDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
315 
316     return bRet;
317 }
318 
insertNewByName(const OUString & aName,const OUString & aTitle,const uno::Reference<text::XTextRange> & xTextRange)319 uno::Reference< text::XAutoTextEntry >  SwXAutoTextGroup::insertNewByName(const OUString& aName,
320         const OUString& aTitle, const uno::Reference< text::XTextRange > & xTextRange)
321 {
322     SolarMutexGuard aGuard;
323     if(hasByName(aName))
324         throw container::ElementExistException();
325     if(!xTextRange.is())
326         throw uno::RuntimeException();
327 
328     std::unique_ptr<SwTextBlocks> pGlosGroup;
329     if (pGlossaries)
330         pGlosGroup = pGlossaries->GetGroupDoc(m_sGroupName);
331     const OUString& sShortName(aName);
332     const OUString& sLongName(aTitle);
333     if (pGlosGroup && !pGlosGroup->GetError())
334     {
335         uno::Reference<lang::XUnoTunnel> xRangeTunnel( xTextRange, uno::UNO_QUERY);
336         SwXTextRange* pxRange = nullptr;
337         OTextCursorHelper* pxCursor = nullptr;
338         if(xRangeTunnel.is())
339         {
340             pxRange = reinterpret_cast<SwXTextRange*>(xRangeTunnel->getSomething(
341                                     SwXTextRange::getUnoTunnelId()));
342             pxCursor = reinterpret_cast<OTextCursorHelper*>(xRangeTunnel->getSomething(
343                                     OTextCursorHelper::getUnoTunnelId()));
344         }
345 
346         OUString sOnlyText;
347         OUString* pOnlyText = nullptr;
348         bool bNoAttr = !pxCursor && !pxRange;
349         if(bNoAttr)
350         {
351             sOnlyText = xTextRange->getString();
352             pOnlyText = &sOnlyText;
353         }
354 
355         const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
356 
357         SwDoc* pGDoc = pGlosGroup->GetDoc();
358 
359         // Until there is an option for that, delete base util::URL
360         if(rCfg.IsSaveRelFile())
361         {
362             INetURLObject aTemp(pGlosGroup->GetFileName());
363             pGlosGroup->SetBaseURL( aTemp.GetMainURL(INetURLObject::DecodeMechanism::NONE));
364         }
365         else
366             pGlosGroup->SetBaseURL( OUString() );
367 
368         sal_uInt16 nRet = USHRT_MAX;
369         if( pOnlyText )
370             nRet = pGlosGroup->PutText( sShortName, sLongName, *pOnlyText );
371         else
372         {
373             pGlosGroup->ClearDoc();
374             if( pGlosGroup->BeginPutDoc( sShortName, sLongName ) )
375             {
376                 pGDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
377                 lcl_CopySelToDoc(*pGDoc, pxCursor, pxRange);
378                 pGDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern(RedlineFlags::NONE);
379                 nRet = pGlosGroup->PutDoc();
380             }
381         }
382 
383         if (nRet == USHRT_MAX)
384         {
385             throw uno::RuntimeException();
386         }
387     }
388     pGlosGroup.reset();
389 
390     uno::Reference< text::XAutoTextEntry > xEntry;
391 
392     try
393     {
394         xEntry = pGlossaries ?
395             pGlossaries->GetAutoTextEntry( m_sGroupName, sName, sShortName ) :
396             uno::Reference< text::XAutoTextEntry >();
397         OSL_ENSURE( xEntry.is(), "SwXAutoTextGroup::insertNewByName: no UNO object created? How this?" );
398             // we just inserted the entry into the group, so why doesn't it exist?
399     }
400     catch (const container::ElementExistException&)
401     {
402         throw;
403     }
404     catch (const uno::RuntimeException&)
405     {
406         throw;
407     }
408     catch (const uno::Exception&)
409     {
410         css::uno::Any anyEx = cppu::getCaughtException();
411         throw css::lang::WrappedTargetRuntimeException(
412                "Error Getting AutoText!",
413                static_cast < OWeakObject * > ( this ),
414                anyEx );
415     }
416 
417     return xEntry;
418 }
419 
removeByName(const OUString & aEntryName)420 void SwXAutoTextGroup::removeByName(const OUString& aEntryName)
421 {
422     SolarMutexGuard aGuard;
423     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
424     if(!pGlosGroup || pGlosGroup->GetError())
425         throw container::NoSuchElementException();
426 
427     sal_uInt16 nIdx = pGlosGroup->GetIndex(aEntryName);
428     if ( nIdx == USHRT_MAX )
429         throw container::NoSuchElementException();
430 
431     pGlosGroup->Delete(nIdx);
432 }
433 
getName()434 OUString SwXAutoTextGroup::getName()
435 {
436     SolarMutexGuard aGuard;
437     return sName;
438 }
439 
setName(const OUString & rName)440 void SwXAutoTextGroup::setName(const OUString& rName)
441 {
442     SolarMutexGuard aGuard;
443     if( !pGlossaries )
444         throw uno::RuntimeException();
445 
446     sal_Int32 nNewDelimPos = rName.lastIndexOf( GLOS_DELIM );
447     sal_Int32 nOldDelimPos = sName.lastIndexOf( GLOS_DELIM );
448 
449     OUString aNewSuffix;
450     if (nNewDelimPos > -1)
451         aNewSuffix = rName.copy( nNewDelimPos + 1 );
452     OUString aOldSuffix;
453     if (nOldDelimPos > -1)
454         aOldSuffix = sName.copy( nOldDelimPos + 1 );
455 
456     sal_Int32 nNewNumeric = aNewSuffix.toInt32();
457     sal_Int32 nOldNumeric = aOldSuffix.toInt32();
458 
459     OUString aNewPrefix( (nNewDelimPos > 1) ? rName.copy( 0, nNewDelimPos ) : rName );
460     OUString aOldPrefix( (nOldDelimPos > 1) ? sName.copy( 0, nOldDelimPos ) : sName );
461 
462     if ( sName == rName ||
463        ( nNewNumeric == nOldNumeric && aNewPrefix == aOldPrefix ) )
464         return;
465     OUString sNewGroup(rName);
466     if (sNewGroup.indexOf(GLOS_DELIM)<0)
467     {
468         sNewGroup += OUStringChar(GLOS_DELIM) + "0";
469     }
470 
471     //the name must be saved, the group may be invalidated while in RenameGroupDoc()
472     SwGlossaries* pTempGlossaries = pGlossaries;
473 
474     OUString sPreserveTitle( pGlossaries->GetGroupTitle( sName ) );
475     if ( !pGlossaries->RenameGroupDoc( sName, sNewGroup, sPreserveTitle ) )
476         throw uno::RuntimeException();
477     sName = rName;
478     m_sGroupName = sNewGroup;
479     pGlossaries = pTempGlossaries;
480 }
481 
getCount()482 sal_Int32 SwXAutoTextGroup::getCount()
483 {
484     SolarMutexGuard aGuard;
485     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
486     if (!pGlosGroup || pGlosGroup->GetError())
487         throw uno::RuntimeException();
488     return static_cast<sal_Int32>(pGlosGroup->GetCount());
489 }
490 
getByIndex(sal_Int32 nIndex)491 uno::Any SwXAutoTextGroup::getByIndex(sal_Int32 nIndex)
492 {
493     SolarMutexGuard aGuard;
494     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
495     if (!pGlosGroup || pGlosGroup->GetError())
496         throw uno::RuntimeException();
497     const sal_uInt16 nCount = pGlosGroup->GetCount();
498     if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(nCount))
499         throw lang::IndexOutOfBoundsException();
500     return getByName(pGlosGroup->GetShortName(o3tl::narrowing<sal_uInt16>(nIndex)));
501 }
502 
getElementType()503 uno::Type SwXAutoTextGroup::getElementType()
504 {
505     return cppu::UnoType<text::XAutoTextEntry>::get();
506 
507 }
508 
hasElements()509 sal_Bool SwXAutoTextGroup::hasElements()
510 {
511     SolarMutexGuard aGuard;
512     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
513     if (!pGlosGroup || pGlosGroup->GetError())
514         throw uno::RuntimeException();
515     return pGlosGroup->GetCount() > 0;
516 
517 }
518 
getByName(const OUString & _rName)519 uno::Any SwXAutoTextGroup::getByName(const OUString& _rName)
520 {
521     SolarMutexGuard aGuard;
522     uno::Reference< text::XAutoTextEntry > xEntry = pGlossaries->GetAutoTextEntry( m_sGroupName, sName, _rName );
523     OSL_ENSURE( xEntry.is(), "SwXAutoTextGroup::getByName: GetAutoTextEntry is fractious!" );
524         // we told it to create the object, so why didn't it?
525     return makeAny( xEntry );
526 }
527 
getElementNames()528 uno::Sequence< OUString > SwXAutoTextGroup::getElementNames()
529 {
530     SolarMutexGuard aGuard;
531     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
532     if (!pGlosGroup || pGlosGroup->GetError())
533         throw uno::RuntimeException();
534 
535     const sal_uInt16 nCount = pGlosGroup->GetCount();
536     uno::Sequence< OUString > aEntryNames(nCount);
537     OUString *pArr = aEntryNames.getArray();
538 
539     for ( sal_uInt16 i = 0; i < nCount; i++ )
540         pArr[i] = pGlosGroup->GetShortName(i);
541     return aEntryNames;
542 }
543 
hasByName(const OUString & rName)544 sal_Bool SwXAutoTextGroup::hasByName(const OUString& rName)
545 {
546     SolarMutexGuard aGuard;
547     bool bRet = false;
548     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
549     if (!pGlosGroup || pGlosGroup->GetError())
550         throw uno::RuntimeException();
551 
552     const sal_uInt16 nCount = pGlosGroup->GetCount();
553     for( sal_uInt16 i = 0; i < nCount; ++i )
554     {
555         OUString sCompare(pGlosGroup->GetShortName(i));
556         if(sCompare.equalsIgnoreAsciiCase(rName))
557         {
558             bRet = true;
559             break;
560         }
561     }
562     return bRet;
563 }
564 
getPropertySetInfo()565 uno::Reference< beans::XPropertySetInfo >  SwXAutoTextGroup::getPropertySetInfo()
566 {
567     static uno::Reference< beans::XPropertySetInfo >  xRet = pPropSet->getPropertySetInfo();
568     return xRet;
569 }
570 
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)571 void SwXAutoTextGroup::setPropertyValue(
572     const OUString& rPropertyName, const uno::Any& aValue)
573 {
574     SolarMutexGuard aGuard;
575     const SfxItemPropertyMapEntry*   pEntry = pPropSet->getPropertyMap().getByName( rPropertyName );
576 
577     if(!pEntry)
578         throw beans::UnknownPropertyException(rPropertyName);
579 
580     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
581     if(!pGlosGroup || pGlosGroup->GetError())
582         throw uno::RuntimeException();
583     switch(pEntry->nWID)
584     {
585         case  WID_GROUP_TITLE:
586         {
587             OUString sNewTitle;
588             aValue >>= sNewTitle;
589             if(sNewTitle.isEmpty())
590                 throw lang::IllegalArgumentException();
591             bool bChanged = sNewTitle != pGlosGroup->GetName();
592             pGlosGroup->SetName(sNewTitle);
593             if(bChanged && HasGlossaryList())
594                 GetGlossaryList()->ClearGroups();
595         }
596         break;
597     }
598 }
599 
getPropertyValue(const OUString & rPropertyName)600 uno::Any SwXAutoTextGroup::getPropertyValue(const OUString& rPropertyName)
601 {
602     SolarMutexGuard aGuard;
603     const SfxItemPropertyMapEntry*   pEntry = pPropSet->getPropertyMap().getByName( rPropertyName);
604 
605     if(!pEntry)
606         throw beans::UnknownPropertyException(rPropertyName);
607     std::unique_ptr<SwTextBlocks> pGlosGroup(pGlossaries ? pGlossaries->GetGroupDoc(m_sGroupName) : nullptr);
608     if(!pGlosGroup  || pGlosGroup->GetError())
609         throw uno::RuntimeException();
610 
611     uno::Any aAny;
612     switch(pEntry->nWID)
613     {
614         case  WID_GROUP_PATH:
615             aAny <<= pGlosGroup->GetFileName();
616         break;
617         case  WID_GROUP_TITLE:
618             aAny <<= pGlosGroup->GetName();
619         break;
620     }
621     return aAny;
622 }
623 
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)624 void SwXAutoTextGroup::addPropertyChangeListener(
625     const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
626 {
627 }
628 
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)629 void SwXAutoTextGroup::removePropertyChangeListener(
630     const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
631 {
632 }
633 
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)634 void SwXAutoTextGroup::addVetoableChangeListener(
635     const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
636 {
637 }
638 
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)639 void SwXAutoTextGroup::removeVetoableChangeListener(
640     const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
641 {
642 }
643 
Invalidate()644 void SwXAutoTextGroup::Invalidate()
645 {
646     pGlossaries = nullptr;
647     sName.clear();
648     m_sGroupName.clear();
649 }
650 
getImplementationName()651 OUString SwXAutoTextGroup::getImplementationName()
652 {
653     return "SwXAutoTextGroup";
654 }
655 
supportsService(const OUString & rServiceName)656 sal_Bool SwXAutoTextGroup::supportsService(const OUString& rServiceName)
657 {
658     return cppu::supportsService(this, rServiceName);
659 }
660 
getSupportedServiceNames()661 uno::Sequence< OUString > SwXAutoTextGroup::getSupportedServiceNames()
662 {
663     uno::Sequence<OUString> aRet { "com.sun.star.text.AutoTextGroup" };
664     return aRet;
665 }
666 
getUnoTunnelId()667 const uno::Sequence< sal_Int8 > & SwXAutoTextEntry::getUnoTunnelId()
668 {
669     static const UnoTunnelIdInit theSwXAutoTextEntryUnoTunnelId;
670     return theSwXAutoTextEntryUnoTunnelId.getSeq();
671 }
672 
getSomething(const uno::Sequence<sal_Int8> & rId)673 sal_Int64 SAL_CALL SwXAutoTextEntry::getSomething( const uno::Sequence< sal_Int8 >& rId )
674 {
675     if( isUnoTunnelId<SwXAutoTextEntry>(rId) )
676     {
677         return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ));
678     }
679     return 0;
680 }
681 
SwXAutoTextEntry(SwGlossaries * pGlss,const OUString & rGroupName,const OUString & rEntryName)682 SwXAutoTextEntry::SwXAutoTextEntry(SwGlossaries* pGlss, const OUString& rGroupName,
683                                             const OUString& rEntryName) :
684     WeakComponentImplHelper(m_aMutex),
685     pGlossaries(pGlss),
686     sGroupName(rGroupName),
687     sEntryName(rEntryName)
688 {
689 }
690 
~SwXAutoTextEntry()691 SwXAutoTextEntry::~SwXAutoTextEntry()
692 {
693     SolarMutexGuard aGuard;
694 
695     // ensure that any pending modifications are written
696     implFlushDocument( true );
697 }
698 
implFlushDocument(bool _bCloseDoc)699 void SwXAutoTextEntry::implFlushDocument( bool _bCloseDoc )
700 {
701     if ( !xDocSh.is() )
702         return;
703 
704     if ( xDocSh->GetDoc()->getIDocumentState().IsModified () )
705         xDocSh->Save();
706 
707     if ( _bCloseDoc )
708     {
709         // stop listening at the document
710         EndListening( *xDocSh );
711 
712         xDocSh->DoClose();
713         xDocSh.clear();
714     }
715 }
716 
Notify(SfxBroadcaster & _rBC,const SfxHint & _rHint)717 void SwXAutoTextEntry::Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint )
718 {
719     if ( &_rBC != xDocSh.get() )
720         return;
721 
722 // it's our document
723     if (const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&_rHint))
724     {
725         if (SfxEventHintId::PrepareCloseDoc == pEventHint->GetEventId())
726         {
727             implFlushDocument();
728             mxBodyText.clear();
729             EndListening( *xDocSh );
730             xDocSh.clear();
731         }
732     }
733     else
734     {
735         if ( SfxHintId::Deinitializing == _rHint.GetId() )
736         {
737             // our document is dying (possibly because we're shutting down, and the document was notified
738             // earlier than we are?)
739             // stop listening at the docu
740             EndListening( *xDocSh );
741             // and release our reference
742             xDocSh.clear();
743         }
744     }
745 }
746 
GetBodyText()747 void SwXAutoTextEntry::GetBodyText ()
748 {
749     SolarMutexGuard aGuard;
750 
751     xDocSh = pGlossaries->EditGroupDoc ( sGroupName, sEntryName, false );
752     OSL_ENSURE( xDocSh.is(), "SwXAutoTextEntry::GetBodyText: unexpected: no doc returned by EditGroupDoc!" );
753 
754     // start listening at the document
755     StartListening( *xDocSh );
756 
757     mxBodyText = new SwXBodyText ( xDocSh->GetDoc() );
758 }
759 
disposing()760 void SwXAutoTextEntry::disposing()
761 {
762     SolarMutexGuard g;
763     implFlushDocument(true);
764 }
765 
createTextCursor()766 uno::Reference< text::XTextCursor >  SwXAutoTextEntry::createTextCursor()
767 {
768     SolarMutexGuard aGuard;
769     EnsureBodyText();
770     return mxBodyText->createTextCursor();
771 }
772 
createTextCursorByRange(const uno::Reference<text::XTextRange> & aTextPosition)773 uno::Reference< text::XTextCursor >  SwXAutoTextEntry::createTextCursorByRange(
774     const uno::Reference< text::XTextRange > & aTextPosition)
775 {
776     SolarMutexGuard aGuard;
777     EnsureBodyText();
778     return mxBodyText->createTextCursorByRange ( aTextPosition );
779 }
780 
insertString(const uno::Reference<text::XTextRange> & xRange,const OUString & aString,sal_Bool bAbsorb)781 void SwXAutoTextEntry::insertString(const uno::Reference< text::XTextRange > & xRange, const OUString& aString, sal_Bool bAbsorb)
782 {
783     SolarMutexGuard aGuard;
784     EnsureBodyText();
785     mxBodyText->insertString ( xRange, aString, bAbsorb );
786 }
787 
insertControlCharacter(const uno::Reference<text::XTextRange> & xRange,sal_Int16 nControlCharacter,sal_Bool bAbsorb)788 void SwXAutoTextEntry::insertControlCharacter(const uno::Reference< text::XTextRange > & xRange,
789     sal_Int16 nControlCharacter, sal_Bool bAbsorb)
790 {
791     SolarMutexGuard aGuard;
792     EnsureBodyText();
793     mxBodyText->insertControlCharacter ( xRange, nControlCharacter, bAbsorb );
794 }
795 
insertTextContent(const uno::Reference<text::XTextRange> & xRange,const uno::Reference<text::XTextContent> & xContent,sal_Bool bAbsorb)796 void SwXAutoTextEntry::insertTextContent(
797     const uno::Reference< text::XTextRange > & xRange,
798     const uno::Reference< text::XTextContent > & xContent, sal_Bool bAbsorb)
799 {
800     SolarMutexGuard aGuard;
801     EnsureBodyText();
802     mxBodyText->insertTextContent ( xRange, xContent, bAbsorb );
803 }
804 
removeTextContent(const uno::Reference<text::XTextContent> & xContent)805 void SwXAutoTextEntry::removeTextContent(
806     const uno::Reference< text::XTextContent > & xContent)
807 {
808     SolarMutexGuard aGuard;
809     EnsureBodyText();
810     mxBodyText->removeTextContent ( xContent );
811 }
812 
getText()813 uno::Reference< text::XText >  SwXAutoTextEntry::getText()
814 {
815     SolarMutexGuard aGuard;
816     uno::Reference< text::XText >  xRet =  static_cast<text::XText*>(this);
817     return xRet;
818 }
819 
getStart()820 uno::Reference< text::XTextRange >  SwXAutoTextEntry::getStart()
821 {
822     SolarMutexGuard aGuard;
823     EnsureBodyText();
824     return mxBodyText->getStart();
825 }
826 
getEnd()827 uno::Reference< text::XTextRange >  SwXAutoTextEntry::getEnd()
828 {
829     SolarMutexGuard aGuard;
830     EnsureBodyText();
831     return mxBodyText->getEnd();
832 }
833 
getString()834 OUString SwXAutoTextEntry::getString()
835 {
836     SolarMutexGuard aGuard;
837     EnsureBodyText();
838     return mxBodyText->getString();
839 }
840 
setString(const OUString & aString)841 void SwXAutoTextEntry::setString(const OUString& aString)
842 {
843     SolarMutexGuard aGuard;
844     EnsureBodyText();
845     mxBodyText->setString( aString );
846 }
847 
applyTo(const uno::Reference<text::XTextRange> & xTextRange)848 void SwXAutoTextEntry::applyTo(const uno::Reference< text::XTextRange > & xTextRange)
849 {
850     SolarMutexGuard aGuard;
851 
852     // ensure that any pending modifications are written
853     // reason is that we're holding the _copy_ of the auto text, while the real auto text
854     // is stored somewhere. And below, we're not working with our copy, but only tell the target
855     // TextRange to work with the stored version.
856     // #96380# - 2003-03-03 - fs@openoffice.org
857     implFlushDocument();
858         // TODO: think about if we should pass "true" here
859         // The difference would be that when the next modification is made to this instance here, then
860         // we would be forced to open the document again, instead of working on our current copy.
861         // This means that we would reflect any changes which were done to the AutoText by foreign instances
862         // in the meantime
863 
864     uno::Reference<lang::XUnoTunnel> xTunnel( xTextRange, uno::UNO_QUERY);
865     SwXTextRange* pRange = nullptr;
866     OTextCursorHelper* pCursor = nullptr;
867     SwXText *pText = nullptr;
868 
869     if(xTunnel.is())
870     {
871         pRange = reinterpret_cast < SwXTextRange* >
872                 ( xTunnel->getSomething( SwXTextRange::getUnoTunnelId() ) );
873         pCursor = reinterpret_cast < OTextCursorHelper*>
874                 ( xTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() ) );
875         pText = reinterpret_cast < SwXText* >
876                 ( xTunnel->getSomething( SwXText::getUnoTunnelId() ) );
877     }
878 
879     SwDoc* pDoc = nullptr;
880     if (pRange)
881         pDoc = &pRange->GetDoc();
882     else if ( pCursor )
883         pDoc = pCursor->GetDoc();
884     else if ( pText && pText->GetDoc() )
885     {
886         xTunnel.set(pText->getStart(), uno::UNO_QUERY);
887         if (xTunnel.is())
888         {
889             pCursor = reinterpret_cast < OTextCursorHelper* >
890                 ( xTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() ) );
891             if (pCursor)
892                 pDoc = pText->GetDoc();
893         }
894     }
895 
896     if(!pDoc)
897         throw uno::RuntimeException();
898 
899     SwPaM InsertPaM(pDoc->GetNodes());
900     if (pRange)
901     {
902         if (!pRange->GetPositions(InsertPaM))
903         {
904             throw uno::RuntimeException();
905         }
906     }
907     else
908     {
909         InsertPaM = *pCursor->GetPaM();
910     }
911 
912     std::unique_ptr<SwTextBlocks> pBlock(pGlossaries->GetGroupDoc(sGroupName));
913     const bool bResult = pBlock && !pBlock->GetError()
914                     && pDoc->InsertGlossary( *pBlock, sEntryName, InsertPaM);
915 
916     if(!bResult)
917         throw uno::RuntimeException();
918 }
919 
getImplementationName()920 OUString SwXAutoTextEntry::getImplementationName()
921 {
922     return "SwXAutoTextEntry";
923 }
924 
supportsService(const OUString & rServiceName)925 sal_Bool SwXAutoTextEntry::supportsService(const OUString& rServiceName)
926 {
927     return cppu::supportsService(this, rServiceName);
928 }
929 
getSupportedServiceNames()930 uno::Sequence< OUString > SwXAutoTextEntry::getSupportedServiceNames()
931 {
932     uno::Sequence<OUString> aRet { "com.sun.star.text.AutoTextEntry" };
933     return aRet;
934 }
935 
getEvents()936 uno::Reference< container::XNameReplace > SwXAutoTextEntry::getEvents()
937 {
938     return new SwAutoTextEventDescriptor( *this );
939 }
940 
941 const struct SvEventDescription aAutotextEvents[] =
942 {
943     { SvMacroItemId::SwStartInsGlossary,  "OnInsertStart" },
944     { SvMacroItemId::SwEndInsGlossary,    "OnInsertDone" },
945     { SvMacroItemId::NONE, nullptr }
946 };
947 
SwAutoTextEventDescriptor(SwXAutoTextEntry & rAutoText)948 SwAutoTextEventDescriptor::SwAutoTextEventDescriptor(
949     SwXAutoTextEntry& rAutoText ) :
950         SvBaseEventDescriptor(aAutotextEvents),
951         rAutoTextEntry(rAutoText)
952 {
953 }
954 
~SwAutoTextEventDescriptor()955 SwAutoTextEventDescriptor::~SwAutoTextEventDescriptor()
956 {
957 }
958 
getImplementationName()959 OUString SwAutoTextEventDescriptor::getImplementationName()
960 {
961     return "SwAutoTextEventDescriptor";
962 }
963 
replaceByName(const SvMacroItemId nEvent,const SvxMacro & rMacro)964 void SwAutoTextEventDescriptor::replaceByName(
965     const SvMacroItemId nEvent,
966     const SvxMacro& rMacro)
967 {
968     OSL_ENSURE( nullptr != rAutoTextEntry.GetGlossaries(),
969                 "Strangely enough, the AutoText vanished!" );
970     OSL_ENSURE( (nEvent == SvMacroItemId::SwEndInsGlossary) ||
971                 (nEvent == SvMacroItemId::SwStartInsGlossary) ,
972                 "Unknown event ID" );
973 
974     SwGlossaries *const pGlossaries =
975         const_cast<SwGlossaries*>(rAutoTextEntry.GetGlossaries());
976     std::unique_ptr<SwTextBlocks> pBlocks(
977         pGlossaries->GetGroupDoc( rAutoTextEntry.GetGroupName() ));
978     OSL_ENSURE( pBlocks,
979                 "can't get autotext group; SwAutoTextEntry has illegal name?");
980 
981     if( !pBlocks || pBlocks->GetError())
982         return;
983 
984     sal_uInt16 nIndex = pBlocks->GetIndex( rAutoTextEntry.GetEntryName() );
985     if( nIndex != USHRT_MAX )
986     {
987         SvxMacroTableDtor aMacroTable;
988         if( pBlocks->GetMacroTable( nIndex, aMacroTable ) )
989         {
990             aMacroTable.Insert( nEvent, rMacro );
991             pBlocks->SetMacroTable( nIndex, aMacroTable );
992         }
993     }
994     // else: ignore
995 }
996 
getByName(SvxMacro & rMacro,const SvMacroItemId nEvent)997 void SwAutoTextEventDescriptor::getByName(
998     SvxMacro& rMacro,
999     const SvMacroItemId nEvent )
1000 {
1001     OSL_ENSURE( nullptr != rAutoTextEntry.GetGlossaries(), "no AutoText" );
1002     OSL_ENSURE( (nEvent == SvMacroItemId::SwEndInsGlossary) ||
1003                 (nEvent == SvMacroItemId::SwStartInsGlossary) ,
1004                 "Unknown event ID" );
1005 
1006     SwGlossaries *const pGlossaries =
1007         const_cast<SwGlossaries*>(rAutoTextEntry.GetGlossaries());
1008     std::unique_ptr<SwTextBlocks> pBlocks(
1009         pGlossaries->GetGroupDoc( rAutoTextEntry.GetGroupName() ));
1010     OSL_ENSURE( pBlocks,
1011                 "can't get autotext group; SwAutoTextEntry has illegal name?");
1012 
1013     // return empty macro, unless macro is found
1014     OUString sEmptyStr;
1015     SvxMacro aEmptyMacro(sEmptyStr, sEmptyStr);
1016     rMacro = aEmptyMacro;
1017 
1018     if ( !pBlocks || pBlocks->GetError())
1019         return;
1020 
1021     sal_uInt16 nIndex = pBlocks->GetIndex( rAutoTextEntry.GetEntryName() );
1022     if( nIndex != USHRT_MAX )
1023     {
1024         SvxMacroTableDtor aMacroTable;
1025         if( pBlocks->GetMacroTable( nIndex, aMacroTable ) )
1026         {
1027             SvxMacro *pMacro = aMacroTable.Get( nEvent );
1028             if( pMacro )
1029                 rMacro = *pMacro;
1030         }
1031     }
1032 }
1033 
1034 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
SwXAutoTextContainer_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)1035 SwXAutoTextContainer_get_implementation(css::uno::XComponentContext*,
1036         css::uno::Sequence<css::uno::Any> const &)
1037 {
1038     //the module may not be loaded
1039     SolarMutexGuard aGuard;
1040     SwGlobals::ensure();
1041     return cppu::acquire(new SwXAutoTextContainer());
1042 }
1043 
1044 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1045