xref: /core/sfx2/source/doc/doctempl.cxx (revision 74d0fe2b2186d9802798f07cbf4ad71865f4e081)
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