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