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
21 #include <limits.h>
22 #include <mutex>
23 #include <string_view>
24
25 #include <com/sun/star/uno/Any.h>
26 #include <sal/log.hxx>
27
28 #include <unotools/pathoptions.hxx>
29 #include <tools/urlobj.hxx>
30 #include <tools/debug.hxx>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/propertyvalue.hxx>
34 #include <ucbhelper/content.hxx>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/beans/XPropertySetInfo.hpp>
38 #include <com/sun/star/document/XTypeDetection.hpp>
39 #include <com/sun/star/document/DocumentProperties.hpp>
40 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
41 #include <com/sun/star/frame/Desktop.hpp>
42 #include <com/sun/star/frame/DocumentTemplates.hpp>
43 #include <com/sun/star/frame/XDocumentTemplates.hpp>
44 #include <com/sun/star/io/IOException.hpp>
45 #include <com/sun/star/io/XPersist.hpp>
46 #include <com/sun/star/lang/XLocalizable.hpp>
47 #include <com/sun/star/sdbc/XResultSet.hpp>
48 #include <com/sun/star/sdbc/XRow.hpp>
49 #include <com/sun/star/ucb/ContentCreationException.hpp>
50 #include <com/sun/star/ucb/NameClash.hpp>
51 #include <com/sun/star/ucb/TransferInfo.hpp>
52 #include <com/sun/star/ucb/XContent.hpp>
53 #include <com/sun/star/ucb/XContentAccess.hpp>
54 #include <com/sun/star/ucb/AnyCompareFactory.hpp>
55 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
56
57 #include "doctemplateslocal.hxx"
58 #include <sfxurlrelocator.hxx>
59
60 #include <sfx2/doctempl.hxx>
61 #include <sfx2/objsh.hxx>
62 #include <sfx2/sfxresid.hxx>
63 #include <sfx2/strings.hrc>
64 #include <strings.hxx>
65 #include <svtools/templatefoldercache.hxx>
66
67 #include <memory>
68 #include <utility>
69 #include <vector>
70
71
72 using namespace ::com::sun::star;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::frame;
75 using namespace ::com::sun::star::io;
76 using namespace ::com::sun::star::lang;
77 using namespace ::com::sun::star::sdbc;
78 using namespace ::com::sun::star::uno;
79 using namespace ::com::sun::star::ucb;
80 using namespace ::com::sun::star::document;
81 using namespace ::rtl;
82 using namespace ::ucbhelper;
83
84 constexpr OUString TITLE = u"Title"_ustr;
85 constexpr OUString TARGET_URL = u"TargetURL"_ustr;
86
87 constexpr OUStringLiteral COMMAND_TRANSFER = u"transfer";
88
89 namespace {
90
91 class RegionData_Impl;
92
93 }
94
95 namespace DocTempl {
96
97 namespace {
98
99 class DocTempl_EntryData_Impl
100 {
101 // the following member must be SfxObjectShellLock since it controls that SfxObjectShell lifetime by design
102 // and users of this class expect it to be so.
103 SfxObjectShellLock mxObjShell;
104
105 OUString maTitle;
106 OUString maOwnURL;
107 OUString maTargetURL;
108
109 public:
110 DocTempl_EntryData_Impl(const OUString& rTitle);
111
GetTitle() const112 const OUString& GetTitle() const { return maTitle; }
113 const OUString& GetTargetURL(const INetURLObject& rRootURL);
114 const OUString& GetHierarchyURL(const INetURLObject& rRootURL);
115
SetTitle(const OUString & rTitle)116 void SetTitle( const OUString& rTitle ) { maTitle = rTitle; }
SetTargetURL(const OUString & rURL)117 void SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
SetHierarchyURL(const OUString & rURL)118 void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; }
119
120 int Compare( std::u16string_view rTitle ) const;
121 };
122
123 }
124
125 }
126
127 using namespace ::DocTempl;
128
129 namespace {
130
131 class RegionData_Impl
132 {
133 std::vector<std::unique_ptr<DocTempl_EntryData_Impl>> maEntries;
134 OUString maTitle;
135 OUString maOwnURL;
136
137 private:
138 size_t GetEntryPos( std::u16string_view rTitle,
139 bool& rFound ) const;
140
141 public:
142 RegionData_Impl(OUString aTitle);
143
SetHierarchyURL(const OUString & rURL)144 void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; }
145
146 DocTempl_EntryData_Impl* GetEntry( size_t nIndex ) const;
147 DocTempl_EntryData_Impl* GetEntry( std::u16string_view rName ) const;
148
GetTitle() const149 const OUString& GetTitle() const { return maTitle; }
150 const OUString& GetHierarchyURL(const INetURLObject& rRootURL);
151
152 size_t GetCount() const;
153
SetTitle(const OUString & rTitle)154 void SetTitle( const OUString& rTitle ) { maTitle = rTitle; }
155
156 void AddEntry(const INetURLObject& rRootURL,
157 const OUString& rTitle,
158 const OUString& rTargetURL,
159 const size_t *pPos);
160 void DeleteEntry( size_t nIndex );
161
162 int Compare( RegionData_Impl const * pCompareWith ) const;
163 };
164
165 }
166
167 class SfxDocTemplate_Impl : public SvRefBase
168 {
169 uno::Reference< XPersist > mxInfo;
170 uno::Reference< XDocumentTemplates > mxTemplates;
171
172 mutable std::mutex maMutex;
173 OUString maRootURL;
174 OUString maStandardGroup;
175 std::vector<std::unique_ptr<RegionData_Impl>> maRegions;
176 bool mbConstructed;
177
178 uno::Reference< XAnyCompareFactory > m_rCompareFactory;
179
180 // the following member is intended to prevent clearing of the global data when it is in use
181 // TODO/LATER: it still does not make the implementation complete thread-safe
182 sal_Int32 mnLockCounter;
183
184 private:
185 void Clear();
186
187 public:
188 SfxDocTemplate_Impl();
189 virtual ~SfxDocTemplate_Impl() override;
190
191 void IncrementLock();
192 void DecrementLock();
193
194 bool Construct( );
195 void CreateFromHierarchy( std::unique_lock<std::mutex>& rGuard, Content &rTemplRoot );
196 void ReInitFromComponent();
197 void AddRegion( std::unique_lock<std::mutex>& rGuard,
198 const OUString& rTitle,
199 Content& rContent );
200
201 void Rescan();
202
203 void DeleteRegion( size_t nIndex );
204
GetRegionCount() const205 size_t GetRegionCount() const
206 { return maRegions.size(); }
207 RegionData_Impl* GetRegion( std::u16string_view rName ) const;
208 RegionData_Impl* GetRegion( size_t nIndex ) const;
209
210 bool GetTitleFromURL( const OUString& rURL, OUString& aTitle );
211 bool InsertRegion( std::unique_ptr<RegionData_Impl> pData, size_t nPos );
212
GetRootURL() const213 INetURLObject GetRootURL() const
214 {
215 std::unique_lock aGuard(maMutex);
216 return INetURLObject(maRootURL);
217 }
218
getDocTemplates() const219 uno::Reference<XDocumentTemplates> getDocTemplates() const
220 {
221 std::unique_lock aGuard(maMutex);
222 return mxTemplates;
223 }
224 };
225
226 namespace {
227
228 class DocTemplLocker_Impl
229 {
230 SfxDocTemplate_Impl& m_aDocTempl;
231 public:
DocTemplLocker_Impl(SfxDocTemplate_Impl & aDocTempl)232 explicit DocTemplLocker_Impl( SfxDocTemplate_Impl& aDocTempl )
233 : m_aDocTempl( aDocTempl )
234 {
235 m_aDocTempl.IncrementLock();
236 }
237
~DocTemplLocker_Impl()238 ~DocTemplLocker_Impl()
239 {
240 m_aDocTempl.DecrementLock();
241 }
242 };
243
244 }
245
246 static SfxDocTemplate_Impl *gpTemplateData = nullptr;
247
248
249 static bool getTextProperty_Impl( Content& rContent,
250 const OUString& rPropName,
251 OUString& rPropValue );
252
253
GetFullRegionName(sal_uInt16 nIdx) const254 OUString SfxDocumentTemplates::GetFullRegionName
255 (
256 sal_uInt16 nIdx // Region Index
257 ) const
258
259 /* [Description]
260
261 Returns the logical name of a region and its path
262
263 [Return value] Reference to the Region name
264
265 */
266
267 {
268 // First: find the RegionData for the index
269
270 DocTemplLocker_Impl aLocker( *pImp );
271
272 if ( pImp->Construct() )
273 {
274 RegionData_Impl *pData1 = pImp->GetRegion( nIdx );
275
276 if ( pData1 )
277 return pData1->GetTitle();
278
279 // --**-- here was some code which appended the path to the
280 // group if there was more than one with the same name.
281 // this should not happen anymore
282 }
283
284 return OUString();
285 }
286
287
GetRegionName(sal_uInt16 nIdx) const288 OUString SfxDocumentTemplates::GetRegionName
289 (
290 sal_uInt16 nIdx // Region Index
291 ) const
292
293 /* [Description]
294
295 Returns the logical name of a region
296
297 [Return value]
298
299 const String& Reference to the Region name
300
301 */
302 {
303 DocTemplLocker_Impl aLocker( *pImp );
304
305 if ( pImp->Construct() )
306 {
307 RegionData_Impl *pData = pImp->GetRegion( nIdx );
308
309 if ( pData )
310 return pData->GetTitle();
311 }
312
313 return OUString();
314 }
315
316
GetRegionCount() const317 sal_uInt16 SfxDocumentTemplates::GetRegionCount() const
318
319 /* [Description]
320
321 Returns the number of Regions
322
323 [Return value]
324
325 sal_uInt16 Number of Regions
326 */
327 {
328 DocTemplLocker_Impl aLocker( *pImp );
329
330 if ( !pImp->Construct() )
331 return 0;
332
333 return pImp->GetRegionCount();
334 }
335
336
GetCount(sal_uInt16 nRegion) const337 sal_uInt16 SfxDocumentTemplates::GetCount
338 (
339 sal_uInt16 nRegion /* Region index whose number is
340 to be determined */
341
342 ) const
343
344 /* [Description]
345
346 Number of entries in Region
347
348 [Return value] Number of entries
349 */
350
351 {
352 DocTemplLocker_Impl aLocker( *pImp );
353
354 if ( !pImp->Construct() )
355 return 0;
356
357 RegionData_Impl *pData = pImp->GetRegion( nRegion );
358
359 if ( !pData )
360 return 0;
361
362 return pData->GetCount();
363 }
364
365
GetName(sal_uInt16 nRegion,sal_uInt16 nIdx) const366 OUString SfxDocumentTemplates::GetName
367 (
368 sal_uInt16 nRegion, // Region Index, in which the entry lies
369 sal_uInt16 nIdx // Index of the entry
370 ) const
371
372 /* [Description]
373
374 Returns the logical name of an entry in Region
375
376 [Return value]
377
378 const String& Entry Name
379 */
380
381 {
382 DocTemplLocker_Impl aLocker( *pImp );
383
384 if ( pImp->Construct() )
385 {
386 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
387
388 if ( pRegion )
389 {
390 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
391 if ( pEntry )
392 return pEntry->GetTitle();
393 }
394 }
395
396 return OUString();
397 }
398
399
GetPath(sal_uInt16 nRegion,sal_uInt16 nIdx) const400 OUString SfxDocumentTemplates::GetPath
401 (
402 sal_uInt16 nRegion, // Region Index, in which the entry lies
403 sal_uInt16 nIdx // Index of the entry
404 ) const
405
406 /* [Description]
407
408 Returns the file name with full path to the file assigned to an entry
409
410 [Return value]
411
412 String File name with full path
413 */
414 {
415 DocTemplLocker_Impl aLocker( *pImp );
416
417 if ( !pImp->Construct() )
418 return OUString();
419
420 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
421
422 if ( pRegion )
423 {
424 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
425 if ( pEntry )
426 return pEntry->GetTargetURL(pImp->GetRootURL());
427 }
428
429 return OUString();
430 }
431
GetTemplateTargetURLFromComponent(std::u16string_view aGroupName,std::u16string_view aTitle)432 OUString SfxDocumentTemplates::GetTemplateTargetURLFromComponent( std::u16string_view aGroupName,
433 std::u16string_view aTitle )
434 {
435 DocTemplLocker_Impl aLocker( *pImp );
436
437 INetURLObject aTemplateObj( pImp->GetRootURL() );
438
439 aTemplateObj.insertName( aGroupName, false,
440 INetURLObject::LAST_SEGMENT,
441 INetURLObject::EncodeMechanism::All );
442
443 aTemplateObj.insertName( aTitle, false,
444 INetURLObject::LAST_SEGMENT,
445 INetURLObject::EncodeMechanism::All );
446
447
448 Content aTemplate;
449 uno::Reference< XCommandEnvironment > aCmdEnv;
450 if ( Content::create( aTemplateObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
451 {
452 OUString aResult;
453 getTextProperty_Impl( aTemplate, TARGET_URL, aResult );
454 return SvtPathOptions().SubstituteVariable( aResult );
455 }
456
457 return OUString();
458 }
459
460
461 /** Convert a template name to its localised pair if it exists.
462 @param rString
463 Name to be translated.
464 @return
465 The localised pair of rString or rString if the former does not exist.
466 */
ConvertResourceString(const OUString & rString)467 OUString SfxDocumentTemplates::ConvertResourceString(const OUString& rString)
468 {
469 static constexpr OUString aTemplateNames[] =
470 {
471 STR_TEMPLATE_NAME1_DEF,
472 STR_TEMPLATE_NAME2_DEF,
473 STR_TEMPLATE_NAME3_DEF,
474 STR_TEMPLATE_NAME4_DEF,
475 STR_TEMPLATE_NAME5_DEF,
476 STR_TEMPLATE_NAME6_DEF,
477 STR_TEMPLATE_NAME7_DEF,
478 STR_TEMPLATE_NAME8_DEF,
479 STR_TEMPLATE_NAME9_DEF,
480 STR_TEMPLATE_NAME10_DEF,
481 STR_TEMPLATE_NAME11_DEF,
482 STR_TEMPLATE_NAME12_DEF,
483 STR_TEMPLATE_NAME13_DEF,
484 STR_TEMPLATE_NAME14_DEF,
485 STR_TEMPLATE_NAME15_DEF,
486 STR_TEMPLATE_NAME16_DEF,
487 STR_TEMPLATE_NAME17_DEF,
488 STR_TEMPLATE_NAME18_DEF,
489 STR_TEMPLATE_NAME19_DEF,
490 STR_TEMPLATE_NAME20_DEF,
491 STR_TEMPLATE_NAME21_DEF,
492 STR_TEMPLATE_NAME22_DEF,
493 STR_TEMPLATE_NAME23_DEF,
494 STR_TEMPLATE_NAME24_DEF,
495 STR_TEMPLATE_NAME25_DEF,
496 STR_TEMPLATE_NAME26_DEF,
497 STR_TEMPLATE_NAME27_DEF,
498 STR_TEMPLATE_NAME28_DEF,
499 STR_TEMPLATE_NAME29_DEF,
500 STR_TEMPLATE_NAME30_DEF,
501 STR_TEMPLATE_NAME31_DEF,
502 STR_TEMPLATE_NAME32_DEF,
503 STR_TEMPLATE_NAME33_DEF,
504 STR_TEMPLATE_NAME34_DEF
505 };
506
507 TranslateId STR_TEMPLATE_NAME[] =
508 {
509 STR_TEMPLATE_NAME1,
510 STR_TEMPLATE_NAME2,
511 STR_TEMPLATE_NAME3,
512 STR_TEMPLATE_NAME4,
513 STR_TEMPLATE_NAME5,
514 STR_TEMPLATE_NAME6,
515 STR_TEMPLATE_NAME7,
516 STR_TEMPLATE_NAME8,
517 STR_TEMPLATE_NAME9,
518 STR_TEMPLATE_NAME10,
519 STR_TEMPLATE_NAME11,
520 STR_TEMPLATE_NAME12,
521 STR_TEMPLATE_NAME13,
522 STR_TEMPLATE_NAME14,
523 STR_TEMPLATE_NAME15,
524 STR_TEMPLATE_NAME16,
525 STR_TEMPLATE_NAME17,
526 STR_TEMPLATE_NAME18,
527 STR_TEMPLATE_NAME19,
528 STR_TEMPLATE_NAME20,
529 STR_TEMPLATE_NAME21,
530 STR_TEMPLATE_NAME22,
531 STR_TEMPLATE_NAME23,
532 STR_TEMPLATE_NAME24,
533 STR_TEMPLATE_NAME25,
534 STR_TEMPLATE_NAME26,
535 STR_TEMPLATE_NAME27,
536 STR_TEMPLATE_NAME28,
537 STR_TEMPLATE_NAME29,
538 STR_TEMPLATE_NAME30,
539 STR_TEMPLATE_NAME31,
540 STR_TEMPLATE_NAME32,
541 STR_TEMPLATE_NAME33,
542 STR_TEMPLATE_NAME34
543 };
544
545 static_assert(SAL_N_ELEMENTS(aTemplateNames) == SAL_N_ELEMENTS(STR_TEMPLATE_NAME));
546
547 for (size_t i = 0; i < SAL_N_ELEMENTS(STR_TEMPLATE_NAME); ++i)
548 {
549 if (rString == aTemplateNames[i])
550 return SfxResId(STR_TEMPLATE_NAME[i]);
551 }
552 return rString;
553 }
554
555
CopyOrMove(sal_uInt16 nTargetRegion,sal_uInt16 nTargetIdx,sal_uInt16 nSourceRegion,sal_uInt16 nSourceIdx,bool bMove)556 bool SfxDocumentTemplates::CopyOrMove
557 (
558 sal_uInt16 nTargetRegion, // Target Region Index
559 sal_uInt16 nTargetIdx, // Target position Index
560 sal_uInt16 nSourceRegion, // Source Region Index
561 sal_uInt16 nSourceIdx, /* Index to be copied / to moved template */
562 bool bMove // Copy / Move
563 )
564
565 /* [Description]
566
567 Copy or move a document template
568
569 [Return value]
570
571 sal_Bool sal_True, Action could be performed
572 sal_False, Action could not be performed
573
574 [Cross-references]
575
576 <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
577 <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
578 */
579
580 {
581 /* to perform a copy or move, we need to send a transfer command to
582 the destination folder with the URL of the source as parameter.
583 ( If the destination content doesn't support the transfer command,
584 we could try a copy ( and delete ) instead. )
585 We need two transfers ( one for the real template and one for its
586 representation in the hierarchy )
587 ...
588 */
589
590 DocTemplLocker_Impl aLocker( *pImp );
591
592 if ( !pImp->Construct() )
593 return false;
594
595 // Don't copy or move any folders
596 if( nSourceIdx == USHRT_MAX )
597 return false ;
598
599 if ( nSourceRegion == nTargetRegion )
600 {
601 SAL_WARN( "sfx.doc", "Don't know, what to do!" );
602 return false;
603 }
604
605 RegionData_Impl *pSourceRgn = pImp->GetRegion( nSourceRegion );
606 if ( !pSourceRgn )
607 return false;
608
609 DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nSourceIdx );
610 if ( !pSource )
611 return false;
612
613 RegionData_Impl *pTargetRgn = pImp->GetRegion( nTargetRegion );
614 if ( !pTargetRgn )
615 return false;
616
617 const OUString aTitle = pSource->GetTitle();
618
619 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
620
621 if ( xTemplates->addTemplate( pTargetRgn->GetTitle(),
622 aTitle,
623 pSource->GetTargetURL(pImp->GetRootURL()) ) )
624 {
625 const OUString aNewTargetURL = GetTemplateTargetURLFromComponent( pTargetRgn->GetTitle(), aTitle );
626 if ( aNewTargetURL.isEmpty() )
627 return false;
628
629 if ( bMove )
630 {
631 // --**-- delete the original file
632 bool bDeleted = xTemplates->removeTemplate( pSourceRgn->GetTitle(),
633 pSource->GetTitle() );
634 if ( bDeleted )
635 pSourceRgn->DeleteEntry( nSourceIdx );
636 else
637 {
638 if ( xTemplates->removeTemplate( pTargetRgn->GetTitle(), aTitle ) )
639 return false; // will trigger retry with copy instead of move
640
641 // if it is not possible to remove just created template ( must be possible! )
642 // it is better to report success here, since at least the copy has succeeded
643 // TODO/LATER: solve it more gracefully in future
644 }
645 }
646
647 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
648 size_t temp_nTargetIdx = nTargetIdx;
649 pTargetRgn->AddEntry(pImp->GetRootURL(), aTitle, aNewTargetURL, &temp_nTargetIdx);
650
651 return true;
652 }
653
654 // --**-- if the current file is opened,
655 // it must be re-opened afterwards.
656
657 return false;
658 }
659
Move(sal_uInt16 nTargetRegion,sal_uInt16 nTargetIdx,sal_uInt16 nSourceRegion,sal_uInt16 nSourceIdx)660 bool SfxDocumentTemplates::Move
661 (
662 sal_uInt16 nTargetRegion, // Target Region Index
663 sal_uInt16 nTargetIdx, // Target position Index
664 sal_uInt16 nSourceRegion, // Source Region Index
665 sal_uInt16 nSourceIdx /* Index to be copied / to moved template */
666 )
667
668 /* [Description]
669
670 Moving a template
671
672 [Return value]
673
674 sal_Bool sal_True, Action could be performed
675 sal_False, Action could not be performed
676
677 [Cross-references]
678
679 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
680 */
681 {
682 DocTemplLocker_Impl aLocker( *pImp );
683
684 return CopyOrMove( nTargetRegion, nTargetIdx,
685 nSourceRegion, nSourceIdx, true );
686 }
687
688
Copy(sal_uInt16 nTargetRegion,sal_uInt16 nTargetIdx,sal_uInt16 nSourceRegion,sal_uInt16 nSourceIdx)689 bool SfxDocumentTemplates::Copy
690 (
691 sal_uInt16 nTargetRegion, // Target Region Index
692 sal_uInt16 nTargetIdx, // Target position Index
693 sal_uInt16 nSourceRegion, // Source Region Index
694 sal_uInt16 nSourceIdx /* Index to be copied / to moved template */
695 )
696
697 /* [Description]
698
699 Copying a template
700
701 [Return value]
702
703 sal_Bool sal_True, Action could be performed
704 sal_False, Action could not be performed
705
706 [Cross-references]
707
708 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
709 */
710
711 {
712 DocTemplLocker_Impl aLocker( *pImp );
713
714 return CopyOrMove( nTargetRegion, nTargetIdx,
715 nSourceRegion, nSourceIdx, false );
716 }
717
718
CopyTo(sal_uInt16 nRegion,sal_uInt16 nIdx,std::u16string_view rName) const719 bool SfxDocumentTemplates::CopyTo
720 (
721 sal_uInt16 nRegion, // Region of the template to be exported
722 sal_uInt16 nIdx, // Index of the template to be exported
723 std::u16string_view rName /* File name under which the template is to
724 be created */
725 ) const
726
727 /* [Description]
728
729 Exporting a template into the file system
730
731 [Return value]
732
733 sal_Bool sal_True, Action could be performed
734 sal_False, Action could not be performed
735
736 [Cross-references]
737
738 <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
739 */
740
741 {
742 DocTemplLocker_Impl aLocker( *pImp );
743
744 if ( ! pImp->Construct() )
745 return false;
746
747 RegionData_Impl *pSourceRgn = pImp->GetRegion( nRegion );
748 if ( !pSourceRgn )
749 return false;
750
751 DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nIdx );
752 if ( !pSource )
753 return false;
754
755 INetURLObject aTargetURL( rName );
756
757 const OUString aTitle( aTargetURL.getName( INetURLObject::LAST_SEGMENT, true,
758 INetURLObject::DecodeMechanism::WithCharset ) );
759 aTargetURL.removeSegment();
760
761 const OUString aParentURL = aTargetURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
762
763 uno::Reference< XCommandEnvironment > aCmdEnv;
764 Content aTarget;
765
766 try
767 {
768 aTarget = Content( aParentURL, aCmdEnv, comphelper::getProcessComponentContext() );
769
770 TransferInfo aTransferInfo;
771 aTransferInfo.MoveData = false;
772 aTransferInfo.SourceURL = pSource->GetTargetURL(pImp->GetRootURL());
773 aTransferInfo.NewTitle = aTitle;
774 aTransferInfo.NameClash = NameClash::RENAME;
775
776 Any aArg( aTransferInfo );
777 aTarget.executeCommand( COMMAND_TRANSFER, aArg );
778 }
779 catch ( ContentCreationException& )
780 { return false; }
781 catch ( Exception& )
782 { return false; }
783
784 return true;
785 }
786
787
CopyFrom(sal_uInt16 nRegion,sal_uInt16 nIdx,OUString & rName)788 bool SfxDocumentTemplates::CopyFrom
789 (
790 sal_uInt16 nRegion, /* Region in which the template is to be
791 imported */
792 sal_uInt16 nIdx, // Index of the new template in this Region
793 OUString& rName /* File name of the template to be imported
794 as an out parameter of the (automatically
795 generated from the file name) logical name
796 of the template */
797 )
798
799 /* [Description]
800
801 Import a template from the file system
802
803 [Return value] Success (sal_True) or serfpTargetDirectory->GetContent());
804
805 sal_Bool sal_True, Action could be performed
806 sal_False, Action could not be performed
807
808 [Cross-references]
809
810 <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
811 */
812
813 {
814 DocTemplLocker_Impl aLocker( *pImp );
815
816 if ( ! pImp->Construct() )
817 return false;
818
819 RegionData_Impl *pTargetRgn = pImp->GetRegion( nRegion );
820
821 if ( !pTargetRgn )
822 return false;
823
824 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
825 if ( !xTemplates.is() )
826 return false;
827
828 OUString aTitle;
829 bool bTemplateAdded = false;
830
831 if( pImp->GetTitleFromURL( rName, aTitle ) )
832 {
833 bTemplateAdded = xTemplates->addTemplate( pTargetRgn->GetTitle(), aTitle, rName );
834 }
835 else
836 {
837 uno::Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
838
839 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(u"Hidden"_ustr, true) };
840
841 INetURLObject aTemplURL( rName );
842 uno::Reference< XDocumentPropertiesSupplier > xDocPropsSupplier;
843 uno::Reference< XStorable > xStorable;
844 try
845 {
846 xStorable.set(
847 xDesktop->loadComponentFromURL( aTemplURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
848 u"_blank"_ustr,
849 0,
850 aArgs ),
851 UNO_QUERY );
852
853 xDocPropsSupplier.set( xStorable, UNO_QUERY );
854 }
855 catch( Exception& )
856 {
857 }
858
859 if( xStorable.is() )
860 {
861 // get Title from XDocumentPropertiesSupplier
862 if( xDocPropsSupplier.is() )
863 {
864 uno::Reference< XDocumentProperties > xDocProps
865 = xDocPropsSupplier->getDocumentProperties();
866 if (xDocProps.is() ) {
867 aTitle = xDocProps->getTitle();
868 }
869 }
870
871 if( aTitle.isEmpty() )
872 {
873 INetURLObject aURL(std::move(aTemplURL));
874 aURL.CutExtension();
875 aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
876 INetURLObject::DecodeMechanism::WithCharset );
877 }
878
879 // write a template using XStorable interface
880 bTemplateAdded = xTemplates->storeTemplate( pTargetRgn->GetTitle(), aTitle, xStorable );
881 }
882 }
883
884
885 if( bTemplateAdded )
886 {
887 INetURLObject aTemplObj(pTargetRgn->GetHierarchyURL(pImp->GetRootURL()));
888 aTemplObj.insertName( aTitle, false,
889 INetURLObject::LAST_SEGMENT,
890 INetURLObject::EncodeMechanism::All );
891 const OUString aTemplURL = aTemplObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
892
893 uno::Reference< XCommandEnvironment > aCmdEnv;
894 Content aTemplCont;
895
896 if( Content::create( aTemplURL, aCmdEnv, comphelper::getProcessComponentContext(), aTemplCont ) )
897 {
898 OUString aTemplName;
899 if( getTextProperty_Impl( aTemplCont, TARGET_URL, aTemplName ) )
900 {
901 if ( nIdx == USHRT_MAX )
902 nIdx = 0;
903 else
904 ++nIdx;
905
906 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
907 size_t temp_nIdx = nIdx;
908 pTargetRgn->AddEntry(pImp->GetRootURL(), aTitle, aTemplName, &temp_nIdx);
909 rName = aTitle;
910 return true;
911 }
912 else
913 {
914 SAL_WARN( "sfx.doc", "CopyFrom(): The content should contain target URL!" );
915 }
916 }
917 else
918 {
919 SAL_WARN( "sfx.doc", "CopyFrom(): The content just was created!" );
920 }
921 }
922
923 return false;
924 }
925
926
Delete(sal_uInt16 nRegion,sal_uInt16 nIdx)927 bool SfxDocumentTemplates::Delete
928 (
929 sal_uInt16 nRegion, // Region Index
930 sal_uInt16 nIdx /* Index of the entry or USHRT_MAX,
931 if a directory is meant. */
932 )
933
934 /* [Description]
935
936 Deleting an entry or a directory
937
938 [Return value]
939
940 sal_Bool sal_True, Action could be performed
941 sal_False, Action could not be performed
942
943 [Cross-references]
944
945 <SfxDocumentTemplates::InsertDir(const String&,sal_uInt16)>
946 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
947 */
948
949 {
950 DocTemplLocker_Impl aLocker( *pImp );
951
952 /* delete the template or folder in the hierarchy and in the
953 template folder by sending a delete command to the content.
954 Then remove the data from the lists
955 */
956 if ( ! pImp->Construct() )
957 return false;
958
959 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
960
961 if ( !pRegion )
962 return false;
963
964 bool bRet;
965 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
966
967 if ( nIdx == USHRT_MAX )
968 {
969 bRet = xTemplates->removeGroup( pRegion->GetTitle() );
970 if ( bRet )
971 pImp->DeleteRegion( nRegion );
972 }
973 else
974 {
975 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
976
977 if ( !pEntry )
978 return false;
979
980 bRet = xTemplates->removeTemplate( pRegion->GetTitle(),
981 pEntry->GetTitle() );
982 if( bRet )
983 pRegion->DeleteEntry( nIdx );
984 }
985
986 return bRet;
987 }
988
989
InsertDir(const OUString & rText,sal_uInt16 nRegion)990 bool SfxDocumentTemplates::InsertDir
991 (
992 const OUString& rText, // the logical name of the new Region
993 sal_uInt16 nRegion // Region Index
994 )
995
996 /* [Description]
997
998 Insert an index
999
1000 [Return value]
1001
1002 sal_Bool sal_True, Action could be performed
1003 sal_False, Action could not be performed
1004
1005 [Cross-references]
1006
1007 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
1008 */
1009 {
1010 DocTemplLocker_Impl aLocker( *pImp );
1011
1012 if ( ! pImp->Construct() )
1013 return false;
1014
1015 RegionData_Impl *pRegion = pImp->GetRegion( rText );
1016
1017 if ( pRegion )
1018 return false;
1019
1020 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
1021
1022 if (xTemplates->addGroup(rText))
1023 return pImp->InsertRegion(std::make_unique<RegionData_Impl>(rText), nRegion);
1024
1025 return false;
1026 }
1027
InsertTemplate(sal_uInt16 nSourceRegion,sal_uInt16 nIdx,const OUString & rName,const OUString & rPath)1028 bool SfxDocumentTemplates::InsertTemplate(sal_uInt16 nSourceRegion, sal_uInt16 nIdx, const OUString &rName, const OUString &rPath)
1029 {
1030 DocTemplLocker_Impl aLocker( *pImp );
1031
1032 if ( ! pImp->Construct() )
1033 return false;
1034
1035 RegionData_Impl *pRegion = pImp->GetRegion( nSourceRegion );
1036
1037 if ( !pRegion )
1038 return false;
1039
1040 size_t pos = nIdx;
1041 pRegion->AddEntry(pImp->GetRootURL(), rName, rPath, &pos);
1042
1043 return true;
1044 }
1045
SetName(const OUString & rName,sal_uInt16 nRegion,sal_uInt16 nIdx)1046 bool SfxDocumentTemplates::SetName( const OUString& rName, sal_uInt16 nRegion, sal_uInt16 nIdx )
1047
1048 {
1049 DocTemplLocker_Impl aLocker( *pImp );
1050
1051 if ( ! pImp->Construct() )
1052 return false;
1053
1054 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
1055
1056 if ( !pRegion )
1057 return false;
1058
1059 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
1060
1061 if ( nIdx == USHRT_MAX )
1062 {
1063 if ( pRegion->GetTitle() == rName )
1064 return true;
1065
1066 // we have to rename a region
1067 if ( xTemplates->renameGroup( pRegion->GetTitle(), rName ) )
1068 {
1069 pRegion->SetTitle( rName );
1070 pRegion->SetHierarchyURL( u""_ustr );
1071 return true;
1072 }
1073 }
1074 else
1075 {
1076 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
1077
1078 if ( !pEntry )
1079 return false;
1080
1081 if ( pEntry->GetTitle() == rName )
1082 return true;
1083
1084 if ( xTemplates->renameTemplate( pRegion->GetTitle(),
1085 pEntry->GetTitle(),
1086 rName ) )
1087 {
1088 pEntry->SetTitle( rName );
1089 pEntry->SetTargetURL( u""_ustr );
1090 pEntry->SetHierarchyURL( u""_ustr );
1091 return true;
1092 }
1093 }
1094
1095 return false;
1096 }
1097
1098
GetFull(std::u16string_view rRegion,std::u16string_view rName,OUString & rPath)1099 bool SfxDocumentTemplates::GetFull
1100 (
1101 std::u16string_view rRegion, // Region Name
1102 std::u16string_view rName, // Template Name
1103 OUString &rPath // Out: Path + File name
1104 )
1105
1106 /* [Description]
1107
1108 Returns Path + File name of the template specified by rRegion and rName.
1109
1110 [Return value]
1111
1112 sal_Bool sal_True, Action could be performed
1113 sal_False, Action could not be performed
1114
1115 [Cross-references]
1116
1117 <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1118 */
1119
1120 {
1121 DocTemplLocker_Impl aLocker( *pImp );
1122
1123 // We don't search for empty names!
1124 if ( rName.empty() )
1125 return false;
1126
1127 if ( ! pImp->Construct() )
1128 return false;
1129
1130 DocTempl_EntryData_Impl* pEntry = nullptr;
1131 const sal_uInt16 nCount = GetRegionCount();
1132
1133 for ( sal_uInt16 i = 0; i < nCount; ++i )
1134 {
1135 RegionData_Impl *pRegion = pImp->GetRegion( i );
1136
1137 if( pRegion &&
1138 ( rRegion.empty() || ( rRegion == pRegion->GetTitle() ) ) )
1139 {
1140 pEntry = pRegion->GetEntry( rName );
1141
1142 if ( pEntry )
1143 {
1144 rPath = pEntry->GetTargetURL(pImp->GetRootURL());
1145 break;
1146 }
1147 }
1148 }
1149
1150 return ( pEntry != nullptr );
1151 }
1152
1153
GetLogicNames(std::u16string_view rPath,OUString & rRegion,OUString & rName) const1154 bool SfxDocumentTemplates::GetLogicNames
1155 (
1156 std::u16string_view rPath, // Full Path to the template
1157 OUString &rRegion, // Out: Region name
1158 OUString &rName // Out: Template name
1159 ) const
1160
1161 /* [Description]
1162
1163 Returns and logical path name to the template specified by rPath
1164
1165 [Return value]
1166
1167 sal_Bool sal_True, Action could be performed
1168 sal_False, Action could not be performed
1169
1170 [Cross-references]
1171
1172 <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1173 */
1174
1175 {
1176 DocTemplLocker_Impl aLocker( *pImp );
1177
1178 if ( ! pImp->Construct() )
1179 return false;
1180
1181 INetURLObject aFullPath;
1182
1183 aFullPath.SetSmartProtocol( INetProtocol::File );
1184 aFullPath.SetURL( rPath );
1185 const OUString aPath( aFullPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1186
1187 const sal_uInt16 nCount = GetRegionCount();
1188
1189 for ( sal_uInt16 i=0; i<nCount; ++i )
1190 {
1191 RegionData_Impl *pData = pImp->GetRegion( i );
1192 if ( pData )
1193 {
1194 const sal_uInt16 nChildCount = pData->GetCount();
1195
1196 for ( sal_uInt16 j=0; j<nChildCount; ++j )
1197 {
1198 DocTempl_EntryData_Impl *pEntry = pData->GetEntry( j );
1199 if ( pEntry && pEntry->GetTargetURL(pImp->GetRootURL()) == aPath )
1200 {
1201 rRegion = pData->GetTitle();
1202 rName = pEntry->GetTitle();
1203 return true;
1204 }
1205 }
1206 }
1207 }
1208
1209 return false;
1210 }
1211
1212
SfxDocumentTemplates()1213 SfxDocumentTemplates::SfxDocumentTemplates()
1214
1215 /* [Description]
1216
1217 Constructor
1218 */
1219 {
1220 if ( !gpTemplateData )
1221 gpTemplateData = new SfxDocTemplate_Impl;
1222
1223 pImp = gpTemplateData;
1224 }
1225
1226
~SfxDocumentTemplates()1227 SfxDocumentTemplates::~SfxDocumentTemplates()
1228
1229 /* [Description]
1230
1231 Destructor
1232 Release of administrative data
1233 */
1234
1235 {
1236 pImp = nullptr;
1237 }
1238
Update()1239 void SfxDocumentTemplates::Update( )
1240 {
1241 if ( ::svt::TemplateFolderCache( true ).needsUpdate() ) // update is really necessary
1242 {
1243 if ( pImp->Construct() )
1244 pImp->Rescan();
1245 }
1246 }
1247
ReInitFromComponent()1248 void SfxDocumentTemplates::ReInitFromComponent()
1249 {
1250 pImp->ReInitFromComponent();
1251 }
1252
DocTempl_EntryData_Impl(const OUString & rTitle)1253 DocTempl_EntryData_Impl::DocTempl_EntryData_Impl(const OUString& rTitle)
1254 : maTitle(SfxDocumentTemplates::ConvertResourceString(rTitle))
1255 {
1256 }
1257
Compare(std::u16string_view rTitle) const1258 int DocTempl_EntryData_Impl::Compare( std::u16string_view rTitle ) const
1259 {
1260 return maTitle.compareTo( rTitle );
1261 }
1262
GetHierarchyURL(const INetURLObject & rRootURL)1263 const OUString& DocTempl_EntryData_Impl::GetHierarchyURL(const INetURLObject& rRootURL)
1264 {
1265 if ( maOwnURL.isEmpty() )
1266 {
1267 INetURLObject aTemplateObj(rRootURL);
1268
1269 aTemplateObj.insertName( GetTitle(), false,
1270 INetURLObject::LAST_SEGMENT,
1271 INetURLObject::EncodeMechanism::All );
1272
1273 maOwnURL = aTemplateObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1274 DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1275 }
1276
1277 return maOwnURL;
1278 }
1279
GetTargetURL(const INetURLObject & rRootURL)1280 const OUString& DocTempl_EntryData_Impl::GetTargetURL(const INetURLObject& rRootURL)
1281 {
1282 if ( maTargetURL.isEmpty() )
1283 {
1284 uno::Reference< XCommandEnvironment > aCmdEnv;
1285 Content aRegion;
1286
1287 if ( Content::create( GetHierarchyURL(rRootURL), aCmdEnv, comphelper::getProcessComponentContext(), aRegion ) )
1288 {
1289 getTextProperty_Impl( aRegion, TARGET_URL, maTargetURL );
1290 }
1291 else
1292 {
1293 SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1294 }
1295 }
1296
1297 return maTargetURL;
1298 }
1299
RegionData_Impl(OUString aTitle)1300 RegionData_Impl::RegionData_Impl(OUString aTitle)
1301 : maTitle(std::move(aTitle))
1302 {
1303 }
1304
1305
GetEntryPos(std::u16string_view rTitle,bool & rFound) const1306 size_t RegionData_Impl::GetEntryPos( std::u16string_view rTitle, bool& rFound ) const
1307 {
1308 const size_t nCount = maEntries.size();
1309
1310 for ( size_t i=0; i<nCount; ++i )
1311 {
1312 auto &pData = maEntries[ i ];
1313
1314 if ( pData->Compare( rTitle ) == 0 )
1315 {
1316 rFound = true;
1317 return i;
1318 }
1319 }
1320
1321 rFound = false;
1322 return nCount;
1323 }
1324
AddEntry(const INetURLObject & rRootURL,const OUString & rTitle,const OUString & rTargetURL,const size_t * pPos)1325 void RegionData_Impl::AddEntry(const INetURLObject& rRootURL,
1326 const OUString& rTitle,
1327 const OUString& rTargetURL,
1328 const size_t *pPos)
1329 {
1330 INetURLObject aLinkObj( GetHierarchyURL(rRootURL) );
1331 aLinkObj.insertName( rTitle, false,
1332 INetURLObject::LAST_SEGMENT,
1333 INetURLObject::EncodeMechanism::All );
1334 const OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1335
1336 bool bFound = false;
1337 size_t nPos = GetEntryPos( rTitle, bFound );
1338
1339 if ( bFound )
1340 return;
1341
1342 if ( pPos )
1343 nPos = *pPos;
1344
1345 auto pEntry = std::make_unique<DocTempl_EntryData_Impl>(rTitle);
1346 pEntry->SetTargetURL( rTargetURL );
1347 pEntry->SetHierarchyURL( aLinkURL );
1348 if ( nPos < maEntries.size() ) {
1349 auto it = maEntries.begin();
1350 std::advance( it, nPos );
1351 maEntries.insert( it, std::move(pEntry) );
1352 }
1353 else
1354 maEntries.push_back( std::move(pEntry) );
1355 }
1356
GetCount() const1357 size_t RegionData_Impl::GetCount() const
1358 {
1359 return maEntries.size();
1360 }
1361
GetHierarchyURL(const INetURLObject & rRootURL)1362 const OUString& RegionData_Impl::GetHierarchyURL(const INetURLObject& rRootURL)
1363 {
1364 if ( maOwnURL.isEmpty() )
1365 {
1366 INetURLObject aRegionObj(rRootURL);
1367
1368 aRegionObj.insertName( GetTitle(), false,
1369 INetURLObject::LAST_SEGMENT,
1370 INetURLObject::EncodeMechanism::All );
1371
1372 maOwnURL = aRegionObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1373 DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1374 }
1375
1376 return maOwnURL;
1377 }
1378
GetEntry(std::u16string_view rName) const1379 DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( std::u16string_view rName ) const
1380 {
1381 bool bFound = false;
1382 tools::Long nPos = GetEntryPos( rName, bFound );
1383
1384 if ( bFound )
1385 return maEntries[ nPos ].get();
1386 return nullptr;
1387 }
1388
1389
GetEntry(size_t nIndex) const1390 DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( size_t nIndex ) const
1391 {
1392 if ( nIndex < maEntries.size() )
1393 return maEntries[ nIndex ].get();
1394 return nullptr;
1395 }
1396
DeleteEntry(size_t nIndex)1397 void RegionData_Impl::DeleteEntry( size_t nIndex )
1398 {
1399 if ( nIndex < maEntries.size() )
1400 {
1401 auto it = maEntries.begin();
1402 std::advance( it, nIndex );
1403 maEntries.erase( it );
1404 }
1405 }
1406
Compare(RegionData_Impl const * pCompare) const1407 int RegionData_Impl::Compare( RegionData_Impl const * pCompare ) const
1408 {
1409 return maTitle.compareTo( pCompare->maTitle );
1410 }
1411
SfxDocTemplate_Impl()1412 SfxDocTemplate_Impl::SfxDocTemplate_Impl()
1413 : maStandardGroup(DocTemplLocaleHelper::GetStandardGroupString())
1414 , mbConstructed(false)
1415 , mnLockCounter(0)
1416 {
1417 }
1418
~SfxDocTemplate_Impl()1419 SfxDocTemplate_Impl::~SfxDocTemplate_Impl()
1420 {
1421 gpTemplateData = nullptr;
1422 }
1423
IncrementLock()1424 void SfxDocTemplate_Impl::IncrementLock()
1425 {
1426 std::unique_lock aGuard( maMutex );
1427 mnLockCounter++;
1428 }
1429
DecrementLock()1430 void SfxDocTemplate_Impl::DecrementLock()
1431 {
1432 std::unique_lock aGuard( maMutex );
1433 if ( mnLockCounter )
1434 mnLockCounter--;
1435 }
1436
GetRegion(size_t nIndex) const1437 RegionData_Impl* SfxDocTemplate_Impl::GetRegion( size_t nIndex ) const
1438 {
1439 if ( nIndex < maRegions.size() )
1440 return maRegions[ nIndex ].get();
1441 return nullptr;
1442 }
1443
GetRegion(std::u16string_view rName) const1444 RegionData_Impl* SfxDocTemplate_Impl::GetRegion( std::u16string_view rName )
1445 const
1446 {
1447 for (auto& pData : maRegions)
1448 {
1449 if( pData->GetTitle() == rName )
1450 return pData.get();
1451 }
1452 return nullptr;
1453 }
1454
1455
DeleteRegion(size_t nIndex)1456 void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex )
1457 {
1458 if ( nIndex < maRegions.size() )
1459 {
1460 auto it = maRegions.begin();
1461 std::advance( it, nIndex );
1462 maRegions.erase( it );
1463 }
1464 }
1465
1466
1467 /* AddRegion adds a Region to the RegionList
1468 */
AddRegion(std::unique_lock<std::mutex> &,const OUString & rTitle,Content & rContent)1469 void SfxDocTemplate_Impl::AddRegion( std::unique_lock<std::mutex>& /*rGuard*/,
1470 const OUString& rTitle,
1471 Content& rContent )
1472 {
1473 auto pRegion = std::make_unique<RegionData_Impl>(rTitle);
1474 auto pRegionTmp = pRegion.get();
1475
1476 if ( ! InsertRegion( std::move(pRegion), size_t(-1) ) )
1477 {
1478 return;
1479 }
1480
1481 // now get the content of the region
1482 uno::Reference< XResultSet > xResultSet;
1483
1484 try
1485 {
1486 xResultSet = rContent.createSortedCursor( { TITLE, TARGET_URL }, { { 1, true } }, m_rCompareFactory, INCLUDE_DOCUMENTS_ONLY );
1487 }
1488 catch ( Exception& ) {}
1489
1490 if ( !xResultSet.is() )
1491 return;
1492
1493 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
1494
1495 try
1496 {
1497 while ( xResultSet->next() )
1498 {
1499 pRegionTmp->AddEntry(INetURLObject(maRootURL), xRow->getString( 1 ), xRow->getString( 2 ), nullptr);
1500 }
1501 }
1502 catch ( Exception& ) {}
1503 }
1504
CreateFromHierarchy(std::unique_lock<std::mutex> & rGuard,Content & rTemplRoot)1505 void SfxDocTemplate_Impl::CreateFromHierarchy( std::unique_lock<std::mutex>& rGuard, Content &rTemplRoot )
1506 {
1507 uno::Reference< XResultSet > xResultSet;
1508 Sequence< OUString > aProps { TITLE };
1509
1510 try
1511 {
1512 xResultSet = rTemplRoot.createSortedCursor(
1513 aProps,
1514 { // Sequence
1515 { // NumberedSortingInfo
1516 /* ColumnIndex */ 1, /* Ascending */ true
1517 }
1518 },
1519 m_rCompareFactory,
1520 INCLUDE_FOLDERS_ONLY
1521 );
1522 }
1523 catch ( Exception& ) {}
1524
1525 if ( !xResultSet.is() )
1526 return;
1527
1528 uno::Reference< XCommandEnvironment > aCmdEnv;
1529 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
1530 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
1531
1532 try
1533 {
1534 while ( xResultSet->next() )
1535 {
1536 const OUString aId = xContentAccess->queryContentIdentifierString();
1537 Content aContent( aId, aCmdEnv, comphelper::getProcessComponentContext() );
1538
1539 AddRegion( rGuard, xRow->getString( 1 ), aContent );
1540 }
1541 }
1542 catch ( Exception& ) {}
1543 }
1544
1545
Construct()1546 bool SfxDocTemplate_Impl::Construct( )
1547 {
1548 std::unique_lock aGuard( maMutex );
1549
1550 if ( mbConstructed )
1551 return true;
1552
1553 const uno::Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
1554
1555 mxInfo.set(document::DocumentProperties::create(xContext), UNO_QUERY);
1556
1557 mxTemplates = frame::DocumentTemplates::create(xContext);
1558
1559 uno::Reference< XLocalizable > xLocalizable( mxTemplates, UNO_QUERY );
1560
1561 m_rCompareFactory = AnyCompareFactory::createWithLocale(xContext, xLocalizable->getLocale());
1562
1563 uno::Reference < XContent > aRootContent = mxTemplates->getContent();
1564 uno::Reference < XCommandEnvironment > aCmdEnv;
1565
1566 if ( ! aRootContent.is() )
1567 return false;
1568
1569 mbConstructed = true;
1570 maRootURL = aRootContent->getIdentifier()->getContentIdentifier();
1571
1572 Content aTemplRoot( aRootContent, aCmdEnv, xContext );
1573 CreateFromHierarchy( aGuard, aTemplRoot );
1574
1575 return true;
1576 }
1577
1578
ReInitFromComponent()1579 void SfxDocTemplate_Impl::ReInitFromComponent()
1580 {
1581 uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates();
1582 if ( xTemplates.is() )
1583 {
1584 uno::Reference < XContent > aRootContent = xTemplates->getContent();
1585 uno::Reference < XCommandEnvironment > aCmdEnv;
1586 Content aTemplRoot( aRootContent, aCmdEnv, comphelper::getProcessComponentContext() );
1587 Clear();
1588 std::unique_lock aGuard(maMutex);
1589 CreateFromHierarchy( aGuard, aTemplRoot );
1590 }
1591 }
1592
1593
InsertRegion(std::unique_ptr<RegionData_Impl> pNew,size_t nPos)1594 bool SfxDocTemplate_Impl::InsertRegion( std::unique_ptr<RegionData_Impl> pNew, size_t nPos )
1595 {
1596 // return false (not inserted) if the entry already exists
1597 for (auto const& pRegion : maRegions)
1598 if ( pRegion->Compare( pNew.get() ) == 0 )
1599 return false;
1600
1601 size_t newPos = nPos;
1602 if ( pNew->GetTitle() == maStandardGroup )
1603 newPos = 0;
1604
1605 if ( newPos < maRegions.size() )
1606 {
1607 auto it = maRegions.begin();
1608 std::advance( it, newPos );
1609 maRegions.emplace( it, std::move(pNew) );
1610 }
1611 else
1612 maRegions.emplace_back( std::move(pNew) );
1613
1614 return true;
1615 }
1616
1617
Rescan()1618 void SfxDocTemplate_Impl::Rescan()
1619 {
1620 Clear();
1621
1622 try
1623 {
1624 uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates();
1625 DBG_ASSERT( xTemplates.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" );
1626 if ( xTemplates.is() )
1627 {
1628 xTemplates->update();
1629
1630 uno::Reference < XContent > aRootContent = xTemplates->getContent();
1631 uno::Reference < XCommandEnvironment > aCmdEnv;
1632
1633 Content aTemplRoot( aRootContent, aCmdEnv, comphelper::getProcessComponentContext() );
1634 std::unique_lock aGuard(maMutex);
1635 CreateFromHierarchy( aGuard, aTemplRoot );
1636 }
1637 }
1638 catch( const Exception& )
1639 {
1640 TOOLS_WARN_EXCEPTION( "sfx.doc", "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update" );
1641 }
1642 }
1643
1644
GetTitleFromURL(const OUString & rURL,OUString & aTitle)1645 bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString& rURL,
1646 OUString& aTitle )
1647 {
1648 if ( mxInfo.is() )
1649 {
1650 try
1651 {
1652 mxInfo->read( rURL );
1653 }
1654 catch ( Exception& )
1655 {
1656 // the document is not a StarOffice document
1657 return false;
1658 }
1659
1660
1661 try
1662 {
1663 uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY );
1664 if ( aPropSet.is() )
1665 {
1666 Any aValue = aPropSet->getPropertyValue( TITLE );
1667 aValue >>= aTitle;
1668 }
1669 }
1670 catch ( IOException& ) {}
1671 catch ( UnknownPropertyException& ) {}
1672 catch ( Exception& ) {}
1673 }
1674
1675 if ( aTitle.isEmpty() )
1676 {
1677 INetURLObject aURL( rURL );
1678 aURL.CutExtension();
1679 aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
1680 INetURLObject::DecodeMechanism::WithCharset );
1681 }
1682
1683 return true;
1684 }
1685
1686
Clear()1687 void SfxDocTemplate_Impl::Clear()
1688 {
1689 std::unique_lock aGuard( maMutex );
1690 if ( mnLockCounter )
1691 return;
1692 maRegions.clear();
1693 }
1694
1695
getTextProperty_Impl(Content & rContent,const OUString & rPropName,OUString & rPropValue)1696 bool getTextProperty_Impl( Content& rContent,
1697 const OUString& rPropName,
1698 OUString& rPropValue )
1699 {
1700 bool bGotProperty = false;
1701
1702 // Get the property
1703 try
1704 {
1705 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1706
1707 // check, whether or not the property exists
1708 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1709 {
1710 return false;
1711 }
1712
1713 // now get the property
1714 Any aAnyValue = rContent.getPropertyValue( rPropName );
1715 aAnyValue >>= rPropValue;
1716
1717 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1718 {
1719 SfxURLRelocator_Impl aRelocImpl( ::comphelper::getProcessComponentContext() );
1720 aRelocImpl.makeAbsoluteURL( rPropValue );
1721 }
1722
1723 bGotProperty = true;
1724 }
1725 catch ( RuntimeException& ) {}
1726 catch ( Exception& ) {}
1727
1728 return bGotProperty;
1729 }
1730
1731 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1732