1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <string_view>
24 #include <com/sun/star/uno/Any.h>
25 #include <osl/mutex.hxx>
26 #include <sal/log.hxx>
28 #include <unotools/pathoptions.hxx>
29 #include <tools/urlobj.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <comphelper/processfactory.hxx>
33 #include <ucbhelper/content.hxx>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/document/XTypeDetection.hpp>
38 #include <com/sun/star/document/DocumentProperties.hpp>
39 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
40 #include <com/sun/star/frame/Desktop.hpp>
41 #include <com/sun/star/frame/DocumentTemplates.hpp>
42 #include <com/sun/star/frame/XDocumentTemplates.hpp>
43 #include <com/sun/star/io/IOException.hpp>
44 #include <com/sun/star/io/XPersist.hpp>
45 #include <com/sun/star/lang/XLocalizable.hpp>
46 #include <com/sun/star/sdbc/XResultSet.hpp>
47 #include <com/sun/star/sdbc/XRow.hpp>
48 #include <com/sun/star/ucb/ContentCreationException.hpp>
49 #include <com/sun/star/ucb/NameClash.hpp>
50 #include <com/sun/star/ucb/TransferInfo.hpp>
51 #include <com/sun/star/ucb/XContent.hpp>
52 #include <com/sun/star/ucb/XContentAccess.hpp>
53 #include <com/sun/star/ucb/AnyCompareFactory.hpp>
54 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
56 #include "doctemplateslocal.hxx"
57 #include <sfxurlrelocator.hxx>
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::beans
;
61 using namespace ::com::sun::star::frame
;
62 using namespace ::com::sun::star::io
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::sdbc
;
65 using namespace ::com::sun::star::uno
;
66 using namespace ::com::sun::star::ucb
;
67 using namespace ::com::sun::star::document
;
68 using namespace ::rtl
;
69 using namespace ::ucbhelper
;
72 #include <sfx2/doctempl.hxx>
73 #include <sfx2/objsh.hxx>
74 #include <sfx2/sfxresid.hxx>
75 #include <sfx2/strings.hrc>
76 #include <strings.hxx>
77 #include <svtools/templatefoldercache.hxx>
84 #define TARGET_URL "TargetURL"
86 #define COMMAND_TRANSFER "transfer"
90 class RegionData_Impl
;
98 class DocTempl_EntryData_Impl
100 RegionData_Impl
* mpParent
;
102 // the following member must be SfxObjectShellLock since it controls that SfxObjectShell lifetime by design
103 // and users of this class expect it to be so.
104 SfxObjectShellLock mxObjShell
;
108 OUString maTargetURL
;
111 DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
112 const OUString
& rTitle
);
114 const OUString
& GetTitle() const { return maTitle
; }
115 const OUString
& GetTargetURL();
116 const OUString
& GetHierarchyURL();
118 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
119 void SetTargetURL( const OUString
& rURL
) { maTargetURL
= rURL
; }
120 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
122 int Compare( const OUString
& rTitle
) const;
129 using namespace ::DocTempl
;
133 class RegionData_Impl
135 const SfxDocTemplate_Impl
* mpParent
;
136 std::vector
<std::unique_ptr
<DocTempl_EntryData_Impl
>> maEntries
;
141 size_t GetEntryPos( const OUString
& rTitle
,
142 bool& rFound
) const;
145 RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
146 const OUString
& rTitle
);
148 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
150 DocTempl_EntryData_Impl
* GetEntry( size_t nIndex
) const;
151 DocTempl_EntryData_Impl
* GetEntry( const OUString
& rName
) const;
153 const OUString
& GetTitle() const { return maTitle
; }
154 const OUString
& GetHierarchyURL();
156 size_t GetCount() const;
158 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
160 void AddEntry( const OUString
& rTitle
,
161 const OUString
& rTargetURL
,
162 const size_t *pPos
);
163 void DeleteEntry( size_t nIndex
);
165 int Compare( RegionData_Impl
const * pCompareWith
) const;
170 class SfxDocTemplate_Impl
: public SvRefBase
172 uno::Reference
< XPersist
> mxInfo
;
173 uno::Reference
< XDocumentTemplates
> mxTemplates
;
175 ::osl::Mutex maMutex
;
177 OUString maStandardGroup
;
178 std::vector
<std::unique_ptr
<RegionData_Impl
>> maRegions
;
181 uno::Reference
< XAnyCompareFactory
> m_rCompareFactory
;
183 // the following member is intended to prevent clearing of the global data when it is in use
184 // TODO/LATER: it still does not make the implementation complete thread-safe
185 sal_Int32 mnLockCounter
;
191 SfxDocTemplate_Impl();
192 virtual ~SfxDocTemplate_Impl() override
;
194 void IncrementLock();
195 void DecrementLock();
198 void CreateFromHierarchy( Content
&rTemplRoot
);
199 void ReInitFromComponent();
200 void AddRegion( const OUString
& rTitle
,
205 void DeleteRegion( size_t nIndex
);
207 size_t GetRegionCount() const
208 { return maRegions
.size(); }
209 RegionData_Impl
* GetRegion( const OUString
& rName
) const;
210 RegionData_Impl
* GetRegion( size_t nIndex
) const;
212 bool GetTitleFromURL( const OUString
& rURL
, OUString
& aTitle
);
213 bool InsertRegion( std::unique_ptr
<RegionData_Impl
> pData
, size_t nPos
);
214 const OUString
& GetRootURL() const { return maRootURL
; }
216 const uno::Reference
< XDocumentTemplates
>& getDocTemplates() const { return mxTemplates
; }
221 class DocTemplLocker_Impl
223 SfxDocTemplate_Impl
& m_aDocTempl
;
225 explicit DocTemplLocker_Impl( SfxDocTemplate_Impl
& aDocTempl
)
226 : m_aDocTempl( aDocTempl
)
228 m_aDocTempl
.IncrementLock();
231 ~DocTemplLocker_Impl()
233 m_aDocTempl
.DecrementLock();
239 static SfxDocTemplate_Impl
*gpTemplateData
= nullptr;
242 static bool getTextProperty_Impl( Content
& rContent
,
243 const OUString
& rPropName
,
244 OUString
& rPropValue
);
247 OUString
SfxDocumentTemplates::GetFullRegionName
249 sal_uInt16 nIdx
// Region Index
254 Returns the logical name of a region and its path
256 [Return value] Reference to the Region name
261 // First: find the RegionData for the index
263 DocTemplLocker_Impl
aLocker( *pImp
);
265 if ( pImp
->Construct() )
267 RegionData_Impl
*pData1
= pImp
->GetRegion( nIdx
);
270 return pData1
->GetTitle();
272 // --**-- here was some code which appended the path to the
273 // group if there was more than one with the same name.
274 // this should not happen anymore
281 OUString
SfxDocumentTemplates::GetRegionName
283 sal_uInt16 nIdx
// Region Index
288 Returns the logical name of a region
292 const String& Reference to the Region name
296 DocTemplLocker_Impl
aLocker( *pImp
);
298 if ( pImp
->Construct() )
300 RegionData_Impl
*pData
= pImp
->GetRegion( nIdx
);
303 return pData
->GetTitle();
310 sal_uInt16
SfxDocumentTemplates::GetRegionCount() const
314 Returns the number of Regions
318 sal_uInt16 Number of Regions
321 DocTemplLocker_Impl
aLocker( *pImp
);
323 if ( !pImp
->Construct() )
326 return pImp
->GetRegionCount();
330 sal_uInt16
SfxDocumentTemplates::GetCount
332 sal_uInt16 nRegion
/* Region index whose number is
339 Number of entries in Region
341 [Return value] Number of entries
345 DocTemplLocker_Impl
aLocker( *pImp
);
347 if ( !pImp
->Construct() )
350 RegionData_Impl
*pData
= pImp
->GetRegion( nRegion
);
355 return pData
->GetCount();
359 OUString
SfxDocumentTemplates::GetName
361 sal_uInt16 nRegion
, // Region Index, in which the entry lies
362 sal_uInt16 nIdx
// Index of the entry
367 Returns the logical name of an entry in Region
371 const String& Entry Name
375 DocTemplLocker_Impl
aLocker( *pImp
);
377 if ( pImp
->Construct() )
379 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
383 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
385 return pEntry
->GetTitle();
393 OUString
SfxDocumentTemplates::GetPath
395 sal_uInt16 nRegion
, // Region Index, in which the entry lies
396 sal_uInt16 nIdx
// Index of the entry
401 Returns the file name with full path to the file assigned to an entry
405 String File name with full path
408 DocTemplLocker_Impl
aLocker( *pImp
);
410 if ( !pImp
->Construct() )
413 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
417 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
419 return pEntry
->GetTargetURL();
426 OUString
SfxDocumentTemplates::GetTemplateTargetURLFromComponent( const OUString
& aGroupName
,
427 const OUString
& aTitle
)
429 DocTemplLocker_Impl
aLocker( *pImp
);
431 INetURLObject
aTemplateObj( pImp
->GetRootURL() );
433 aTemplateObj
.insertName( aGroupName
, false,
434 INetURLObject::LAST_SEGMENT
,
435 INetURLObject::EncodeMechanism::All
);
437 aTemplateObj
.insertName( aTitle
, false,
438 INetURLObject::LAST_SEGMENT
,
439 INetURLObject::EncodeMechanism::All
);
443 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
444 if ( Content::create( aTemplateObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aCmdEnv
, comphelper::getProcessComponentContext(), aTemplate
) )
447 getTextProperty_Impl( aTemplate
, TARGET_URL
, aResult
);
448 return SvtPathOptions().SubstituteVariable( aResult
);
455 /** Convert a template name to its localised pair if it exists.
457 Name to be translated.
459 The localised pair of rString or rString if the former does not exist.
461 OUString
SfxDocumentTemplates::ConvertResourceString(const OUString
& rString
)
463 static const std::u16string_view aTemplateNames
[] =
465 u
"" STR_TEMPLATE_NAME1_DEF
,
466 u
"" STR_TEMPLATE_NAME2_DEF
,
467 u
"" STR_TEMPLATE_NAME3_DEF
,
468 u
"" STR_TEMPLATE_NAME4_DEF
,
469 u
"" STR_TEMPLATE_NAME5_DEF
,
470 u
"" STR_TEMPLATE_NAME6_DEF
,
471 u
"" STR_TEMPLATE_NAME7_DEF
,
472 u
"" STR_TEMPLATE_NAME8_DEF
,
473 u
"" STR_TEMPLATE_NAME9_DEF
,
474 u
"" STR_TEMPLATE_NAME10_DEF
,
475 u
"" STR_TEMPLATE_NAME11_DEF
,
476 u
"" STR_TEMPLATE_NAME12_DEF
,
477 u
"" STR_TEMPLATE_NAME13_DEF
,
478 u
"" STR_TEMPLATE_NAME14_DEF
,
479 u
"" STR_TEMPLATE_NAME15_DEF
,
480 u
"" STR_TEMPLATE_NAME16_DEF
,
481 u
"" STR_TEMPLATE_NAME17_DEF
,
482 u
"" STR_TEMPLATE_NAME18_DEF
,
483 u
"" STR_TEMPLATE_NAME19_DEF
,
484 u
"" STR_TEMPLATE_NAME20_DEF
,
485 u
"" STR_TEMPLATE_NAME21_DEF
,
486 u
"" STR_TEMPLATE_NAME22_DEF
,
487 u
"" STR_TEMPLATE_NAME23_DEF
,
488 u
"" STR_TEMPLATE_NAME24_DEF
,
489 u
"" STR_TEMPLATE_NAME25_DEF
,
490 u
"" STR_TEMPLATE_NAME26_DEF
,
491 u
"" STR_TEMPLATE_NAME27_DEF
,
492 u
"" STR_TEMPLATE_NAME28_DEF
,
493 u
"" STR_TEMPLATE_NAME29_DEF
,
494 u
"" STR_TEMPLATE_NAME30_DEF
497 const char* STR_TEMPLATE_NAME
[] =
531 assert(SAL_N_ELEMENTS(aTemplateNames
) == SAL_N_ELEMENTS(STR_TEMPLATE_NAME
));
533 for (size_t i
= 0; i
< SAL_N_ELEMENTS(STR_TEMPLATE_NAME
); ++i
)
535 if (rString
== aTemplateNames
[i
])
536 return SfxResId(STR_TEMPLATE_NAME
[i
]);
542 bool SfxDocumentTemplates::CopyOrMove
544 sal_uInt16 nTargetRegion
, // Target Region Index
545 sal_uInt16 nTargetIdx
, // Target position Index
546 sal_uInt16 nSourceRegion
, // Source Region Index
547 sal_uInt16 nSourceIdx
, /* Index to be copied / to moved template */
548 bool bMove
// Copy / Move
553 Copy or move a document template
557 sal_Bool sal_True, Action could be performed
558 sal_False, Action could not be performed
562 <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
563 <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
567 /* to perform a copy or move, we need to send a transfer command to
568 the destination folder with the URL of the source as parameter.
569 ( If the destination content doesn't support the transfer command,
570 we could try a copy ( and delete ) instead. )
571 We need two transfers ( one for the real template and one for its
572 representation in the hierarchy )
576 DocTemplLocker_Impl
aLocker( *pImp
);
578 if ( !pImp
->Construct() )
581 // Don't copy or move any folders
582 if( nSourceIdx
== USHRT_MAX
)
585 if ( nSourceRegion
== nTargetRegion
)
587 SAL_WARN( "sfx.doc", "Don't know, what to do!" );
591 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nSourceRegion
);
595 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nSourceIdx
);
599 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nTargetRegion
);
603 const OUString aTitle
= pSource
->GetTitle();
605 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
607 if ( xTemplates
->addTemplate( pTargetRgn
->GetTitle(),
609 pSource
->GetTargetURL() ) )
611 const OUString aNewTargetURL
= GetTemplateTargetURLFromComponent( pTargetRgn
->GetTitle(), aTitle
);
612 if ( aNewTargetURL
.isEmpty() )
617 // --**-- delete the original file
618 bool bDeleted
= xTemplates
->removeTemplate( pSourceRgn
->GetTitle(),
619 pSource
->GetTitle() );
621 pSourceRgn
->DeleteEntry( nSourceIdx
);
624 if ( xTemplates
->removeTemplate( pTargetRgn
->GetTitle(), aTitle
) )
625 return false; // will trigger retry with copy instead of move
627 // if it is not possible to remove just created template ( must be possible! )
628 // it is better to report success here, since at least the copy has succeeded
629 // TODO/LATER: solve it more gracefully in future
633 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
634 size_t temp_nTargetIdx
= nTargetIdx
;
635 pTargetRgn
->AddEntry( aTitle
, aNewTargetURL
, &temp_nTargetIdx
);
640 // --**-- if the current file is opened,
641 // it must be re-opened afterwards.
647 bool SfxDocumentTemplates::Move
649 sal_uInt16 nTargetRegion
, // Target Region Index
650 sal_uInt16 nTargetIdx
, // Target position Index
651 sal_uInt16 nSourceRegion
, // Source Region Index
652 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
661 sal_Bool sal_True, Action could be performed
662 sal_False, Action could not be performed
666 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
669 DocTemplLocker_Impl
aLocker( *pImp
);
671 return CopyOrMove( nTargetRegion
, nTargetIdx
,
672 nSourceRegion
, nSourceIdx
, true );
676 bool SfxDocumentTemplates::Copy
678 sal_uInt16 nTargetRegion
, // Target Region Index
679 sal_uInt16 nTargetIdx
, // Target position Index
680 sal_uInt16 nSourceRegion
, // Source Region Index
681 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
690 sal_Bool sal_True, Action could be performed
691 sal_False, Action could not be performed
695 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
699 DocTemplLocker_Impl
aLocker( *pImp
);
701 return CopyOrMove( nTargetRegion
, nTargetIdx
,
702 nSourceRegion
, nSourceIdx
, false );
706 bool SfxDocumentTemplates::CopyTo
708 sal_uInt16 nRegion
, // Region of the template to be exported
709 sal_uInt16 nIdx
, // Index of the template to be exported
710 const OUString
& rName
/* File name under which the template is to
716 Exporting a template into the file system
720 sal_Bool sal_True, Action could be performed
721 sal_False, Action could not be performed
725 <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
729 DocTemplLocker_Impl
aLocker( *pImp
);
731 if ( ! pImp
->Construct() )
734 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nRegion
);
738 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nIdx
);
742 INetURLObject
aTargetURL( rName
);
744 const OUString
aTitle( aTargetURL
.getName( INetURLObject::LAST_SEGMENT
, true,
745 INetURLObject::DecodeMechanism::WithCharset
) );
746 aTargetURL
.removeSegment();
748 const OUString aParentURL
= aTargetURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
750 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
755 aTarget
= Content( aParentURL
, aCmdEnv
, comphelper::getProcessComponentContext() );
757 TransferInfo aTransferInfo
;
758 aTransferInfo
.MoveData
= false;
759 aTransferInfo
.SourceURL
= pSource
->GetTargetURL();
760 aTransferInfo
.NewTitle
= aTitle
;
761 aTransferInfo
.NameClash
= NameClash::RENAME
;
763 Any aArg
= makeAny( aTransferInfo
);
764 aTarget
.executeCommand( COMMAND_TRANSFER
, aArg
);
766 catch ( ContentCreationException
& )
775 bool SfxDocumentTemplates::CopyFrom
777 sal_uInt16 nRegion
, /* Region in which the template is to be
779 sal_uInt16 nIdx
, // Index of the new template in this Region
780 OUString
& rName
/* File name of the template to be imported
781 as an out parameter of the (automatically
782 generated from the file name) logical name
788 Import a template from the file system
790 [Return value] Success (sal_True) or serfpTargetDirectory->GetContent());
792 sal_Bool sal_True, Action could be performed
793 sal_False, Action could not be performed
797 <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
801 DocTemplLocker_Impl
aLocker( *pImp
);
803 if ( ! pImp
->Construct() )
806 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nRegion
);
811 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
812 if ( !xTemplates
.is() )
816 bool bTemplateAdded
= false;
818 if( pImp
->GetTitleFromURL( rName
, aTitle
) )
820 bTemplateAdded
= xTemplates
->addTemplate( pTargetRgn
->GetTitle(), aTitle
, rName
);
824 uno::Reference
< XDesktop2
> xDesktop
= Desktop::create( ::comphelper::getProcessComponentContext() );
826 Sequence
< PropertyValue
> aArgs( 1 );
827 aArgs
[0].Name
= "Hidden";
828 aArgs
[0].Value
<<= true;
830 INetURLObject
aTemplURL( rName
);
831 uno::Reference
< XDocumentPropertiesSupplier
> xDocPropsSupplier
;
832 uno::Reference
< XStorable
> xStorable
;
836 xDesktop
->loadComponentFromURL( aTemplURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),
842 xDocPropsSupplier
.set( xStorable
, UNO_QUERY
);
850 // get Title from XDocumentPropertiesSupplier
851 if( xDocPropsSupplier
.is() )
853 uno::Reference
< XDocumentProperties
> xDocProps
854 = xDocPropsSupplier
->getDocumentProperties();
855 if (xDocProps
.is() ) {
856 aTitle
= xDocProps
->getTitle();
860 if( aTitle
.isEmpty() )
862 INetURLObject
aURL( aTemplURL
);
864 aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true,
865 INetURLObject::DecodeMechanism::WithCharset
);
868 // write a template using XStorable interface
869 bTemplateAdded
= xTemplates
->storeTemplate( pTargetRgn
->GetTitle(), aTitle
, xStorable
);
876 INetURLObject
aTemplObj( pTargetRgn
->GetHierarchyURL() );
877 aTemplObj
.insertName( aTitle
, false,
878 INetURLObject::LAST_SEGMENT
,
879 INetURLObject::EncodeMechanism::All
);
880 const OUString aTemplURL
= aTemplObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
882 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
885 if( Content::create( aTemplURL
, aCmdEnv
, comphelper::getProcessComponentContext(), aTemplCont
) )
888 if( getTextProperty_Impl( aTemplCont
, TARGET_URL
, aTemplName
) )
890 if ( nIdx
== USHRT_MAX
)
895 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
896 size_t temp_nIdx
= nIdx
;
897 pTargetRgn
->AddEntry( aTitle
, aTemplName
, &temp_nIdx
);
903 SAL_WARN( "sfx.doc", "CopyFrom(): The content should contain target URL!" );
908 SAL_WARN( "sfx.doc", "CopyFrom(): The content just was created!" );
916 bool SfxDocumentTemplates::Delete
918 sal_uInt16 nRegion
, // Region Index
919 sal_uInt16 nIdx
/* Index of the entry or USHRT_MAX,
920 if a directory is meant. */
925 Deleting an entry or a directory
929 sal_Bool sal_True, Action could be performed
930 sal_False, Action could not be performed
934 <SfxDocumentTemplates::InsertDir(const String&,sal_uInt16)>
935 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
939 DocTemplLocker_Impl
aLocker( *pImp
);
941 /* delete the template or folder in the hierarchy and in the
942 template folder by sending a delete command to the content.
943 Then remove the data from the lists
945 if ( ! pImp
->Construct() )
948 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
954 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
956 if ( nIdx
== USHRT_MAX
)
958 bRet
= xTemplates
->removeGroup( pRegion
->GetTitle() );
960 pImp
->DeleteRegion( nRegion
);
964 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
969 bRet
= xTemplates
->removeTemplate( pRegion
->GetTitle(),
970 pEntry
->GetTitle() );
972 pRegion
->DeleteEntry( nIdx
);
979 bool SfxDocumentTemplates::InsertDir
981 const OUString
& rText
, // the logical name of the new Region
982 sal_uInt16 nRegion
// Region Index
991 sal_Bool sal_True, Action could be performed
992 sal_False, Action could not be performed
996 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
999 DocTemplLocker_Impl
aLocker( *pImp
);
1001 if ( ! pImp
->Construct() )
1004 RegionData_Impl
*pRegion
= pImp
->GetRegion( rText
);
1009 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1011 if ( xTemplates
->addGroup( rText
) )
1013 return pImp
->InsertRegion( std::make_unique
<RegionData_Impl
>( pImp
.get(), rText
), nRegion
);
1019 bool SfxDocumentTemplates::InsertTemplate(sal_uInt16 nSourceRegion
, sal_uInt16 nIdx
, const OUString
&rName
, const OUString
&rPath
)
1021 DocTemplLocker_Impl
aLocker( *pImp
);
1023 if ( ! pImp
->Construct() )
1026 RegionData_Impl
*pRegion
= pImp
->GetRegion( nSourceRegion
);
1032 pRegion
->AddEntry( rName
, rPath
, &pos
);
1037 bool SfxDocumentTemplates::SetName( const OUString
& rName
, sal_uInt16 nRegion
, sal_uInt16 nIdx
)
1040 DocTemplLocker_Impl
aLocker( *pImp
);
1042 if ( ! pImp
->Construct() )
1045 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
1050 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1052 if ( nIdx
== USHRT_MAX
)
1054 if ( pRegion
->GetTitle() == rName
)
1057 // we have to rename a region
1058 if ( xTemplates
->renameGroup( pRegion
->GetTitle(), rName
) )
1060 pRegion
->SetTitle( rName
);
1061 pRegion
->SetHierarchyURL( "" );
1067 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
1072 if ( pEntry
->GetTitle() == rName
)
1075 if ( xTemplates
->renameTemplate( pRegion
->GetTitle(),
1079 pEntry
->SetTitle( rName
);
1080 pEntry
->SetTargetURL( "" );
1081 pEntry
->SetHierarchyURL( "" );
1090 bool SfxDocumentTemplates::GetFull
1092 const OUString
&rRegion
, // Region Name
1093 const OUString
&rName
, // Template Name
1094 OUString
&rPath
// Out: Path + File name
1099 Returns Path + File name of the template specified by rRegion and rName.
1103 sal_Bool sal_True, Action could be performed
1104 sal_False, Action could not be performed
1108 <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1112 DocTemplLocker_Impl
aLocker( *pImp
);
1114 // We don't search for empty names!
1115 if ( rName
.isEmpty() )
1118 if ( ! pImp
->Construct() )
1121 DocTempl_EntryData_Impl
* pEntry
= nullptr;
1122 const sal_uInt16 nCount
= GetRegionCount();
1124 for ( sal_uInt16 i
= 0; i
< nCount
; ++i
)
1126 RegionData_Impl
*pRegion
= pImp
->GetRegion( i
);
1129 ( rRegion
.isEmpty() || ( rRegion
== pRegion
->GetTitle() ) ) )
1131 pEntry
= pRegion
->GetEntry( rName
);
1135 rPath
= pEntry
->GetTargetURL();
1141 return ( pEntry
!= nullptr );
1145 bool SfxDocumentTemplates::GetLogicNames
1147 const OUString
&rPath
, // Full Path to the template
1148 OUString
&rRegion
, // Out: Region name
1149 OUString
&rName
// Out: Template name
1154 Returns and logical path name to the template specified by rPath
1158 sal_Bool sal_True, Action could be performed
1159 sal_False, Action could not be performed
1163 <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1167 DocTemplLocker_Impl
aLocker( *pImp
);
1169 if ( ! pImp
->Construct() )
1172 INetURLObject aFullPath
;
1174 aFullPath
.SetSmartProtocol( INetProtocol::File
);
1175 aFullPath
.SetURL( rPath
);
1176 const OUString
aPath( aFullPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1178 const sal_uInt16 nCount
= GetRegionCount();
1180 for ( sal_uInt16 i
=0; i
<nCount
; ++i
)
1182 RegionData_Impl
*pData
= pImp
->GetRegion( i
);
1185 const sal_uInt16 nChildCount
= pData
->GetCount();
1187 for ( sal_uInt16 j
=0; j
<nChildCount
; ++j
)
1189 DocTempl_EntryData_Impl
*pEntry
= pData
->GetEntry( j
);
1190 if ( pEntry
&& pEntry
->GetTargetURL() == aPath
)
1192 rRegion
= pData
->GetTitle();
1193 rName
= pEntry
->GetTitle();
1204 SfxDocumentTemplates::SfxDocumentTemplates()
1211 if ( !gpTemplateData
)
1212 gpTemplateData
= new SfxDocTemplate_Impl
;
1214 pImp
= gpTemplateData
;
1218 SfxDocumentTemplates::~SfxDocumentTemplates()
1223 Release of administrative data
1230 void SfxDocumentTemplates::Update( )
1232 if ( ::svt::TemplateFolderCache( true ).needsUpdate() ) // update is really necessary
1234 if ( pImp
->Construct() )
1239 void SfxDocumentTemplates::ReInitFromComponent()
1241 pImp
->ReInitFromComponent();
1244 DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
1245 const OUString
& rTitle
)
1248 maTitle
= SfxDocumentTemplates::ConvertResourceString(rTitle
);
1252 int DocTempl_EntryData_Impl::Compare( const OUString
& rTitle
) const
1254 return maTitle
.compareTo( rTitle
);
1258 const OUString
& DocTempl_EntryData_Impl::GetHierarchyURL()
1260 if ( maOwnURL
.isEmpty() )
1262 INetURLObject
aTemplateObj( mpParent
->GetHierarchyURL() );
1264 aTemplateObj
.insertName( GetTitle(), false,
1265 INetURLObject::LAST_SEGMENT
,
1266 INetURLObject::EncodeMechanism::All
);
1268 maOwnURL
= aTemplateObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1269 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1276 const OUString
& DocTempl_EntryData_Impl::GetTargetURL()
1278 if ( maTargetURL
.isEmpty() )
1280 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1283 if ( Content::create( GetHierarchyURL(), aCmdEnv
, comphelper::getProcessComponentContext(), aRegion
) )
1285 getTextProperty_Impl( aRegion
, TARGET_URL
, maTargetURL
);
1289 SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1297 RegionData_Impl::RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
1298 const OUString
& rTitle
)
1299 : mpParent(pParent
), maTitle(rTitle
)
1304 size_t RegionData_Impl::GetEntryPos( const OUString
& rTitle
, bool& rFound
) const
1306 const size_t nCount
= maEntries
.size();
1308 for ( size_t i
=0; i
<nCount
; ++i
)
1310 auto &pData
= maEntries
[ i
];
1312 if ( pData
->Compare( rTitle
) == 0 )
1324 void RegionData_Impl::AddEntry( const OUString
& rTitle
,
1325 const OUString
& rTargetURL
,
1326 const size_t *pPos
)
1328 INetURLObject
aLinkObj( GetHierarchyURL() );
1329 aLinkObj
.insertName( rTitle
, false,
1330 INetURLObject::LAST_SEGMENT
,
1331 INetURLObject::EncodeMechanism::All
);
1332 const OUString aLinkURL
= aLinkObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1334 bool bFound
= false;
1335 size_t nPos
= GetEntryPos( rTitle
, bFound
);
1343 auto pEntry
= std::make_unique
<DocTempl_EntryData_Impl
>(
1345 pEntry
->SetTargetURL( rTargetURL
);
1346 pEntry
->SetHierarchyURL( aLinkURL
);
1347 if ( nPos
< maEntries
.size() ) {
1348 auto it
= maEntries
.begin();
1349 std::advance( it
, nPos
);
1350 maEntries
.insert( it
, std::move(pEntry
) );
1353 maEntries
.push_back( std::move(pEntry
) );
1357 size_t RegionData_Impl::GetCount() const
1359 return maEntries
.size();
1363 const OUString
& RegionData_Impl::GetHierarchyURL()
1365 if ( maOwnURL
.isEmpty() )
1367 INetURLObject
aRegionObj( mpParent
->GetRootURL() );
1369 aRegionObj
.insertName( GetTitle(), false,
1370 INetURLObject::LAST_SEGMENT
,
1371 INetURLObject::EncodeMechanism::All
);
1373 maOwnURL
= aRegionObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1374 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1381 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( const OUString
& rName
) const
1383 bool bFound
= false;
1384 tools::Long nPos
= GetEntryPos( rName
, bFound
);
1387 return maEntries
[ nPos
].get();
1392 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( size_t nIndex
) const
1394 if ( nIndex
< maEntries
.size() )
1395 return maEntries
[ nIndex
].get();
1400 void RegionData_Impl::DeleteEntry( size_t nIndex
)
1402 if ( nIndex
< maEntries
.size() )
1404 auto it
= maEntries
.begin();
1405 std::advance( it
, nIndex
);
1406 maEntries
.erase( it
);
1411 int RegionData_Impl::Compare( RegionData_Impl
const * pCompare
) const
1413 return maTitle
.compareTo( pCompare
->maTitle
);
1417 SfxDocTemplate_Impl::SfxDocTemplate_Impl()
1418 : mbConstructed( false )
1419 , mnLockCounter( 0 )
1424 SfxDocTemplate_Impl::~SfxDocTemplate_Impl()
1426 gpTemplateData
= nullptr;
1430 void SfxDocTemplate_Impl::IncrementLock()
1432 ::osl::MutexGuard
aGuard( maMutex
);
1437 void SfxDocTemplate_Impl::DecrementLock()
1439 ::osl::MutexGuard
aGuard( maMutex
);
1440 if ( mnLockCounter
)
1445 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( size_t nIndex
) const
1447 if ( nIndex
< maRegions
.size() )
1448 return maRegions
[ nIndex
].get();
1453 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( const OUString
& rName
)
1456 for (auto& pData
: maRegions
)
1458 if( pData
->GetTitle() == rName
)
1465 void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex
)
1467 if ( nIndex
< maRegions
.size() )
1469 auto it
= maRegions
.begin();
1470 std::advance( it
, nIndex
);
1471 maRegions
.erase( it
);
1476 /* AddRegion adds a Region to the RegionList
1478 void SfxDocTemplate_Impl::AddRegion( const OUString
& rTitle
,
1481 auto pRegion
= std::make_unique
<RegionData_Impl
>( this, rTitle
);
1482 auto pRegionTmp
= pRegion
.get();
1484 if ( ! InsertRegion( std::move(pRegion
), size_t(-1) ) )
1489 // now get the content of the region
1490 uno::Reference
< XResultSet
> xResultSet
;
1491 Sequence
< OUString
> aProps(2);
1493 aProps
[1] = TARGET_URL
;
1497 Sequence
< NumberedSortingInfo
> aSortingInfo(1);
1498 aSortingInfo
.getArray()->ColumnIndex
= 1;
1499 aSortingInfo
.getArray()->Ascending
= true;
1500 xResultSet
= rContent
.createSortedCursor( aProps
, aSortingInfo
, m_rCompareFactory
, INCLUDE_DOCUMENTS_ONLY
);
1502 catch ( Exception
& ) {}
1504 if ( !xResultSet
.is() )
1507 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1511 while ( xResultSet
->next() )
1513 pRegionTmp
->AddEntry( xRow
->getString( 1 ), xRow
->getString( 2 ), nullptr );
1516 catch ( Exception
& ) {}
1520 void SfxDocTemplate_Impl::CreateFromHierarchy( Content
&rTemplRoot
)
1522 uno::Reference
< XResultSet
> xResultSet
;
1523 Sequence
< OUString
> aProps
{ TITLE
};
1527 Sequence
< NumberedSortingInfo
> aSortingInfo(1);
1528 aSortingInfo
.getArray()->ColumnIndex
= 1;
1529 aSortingInfo
.getArray()->Ascending
= true;
1530 xResultSet
= rTemplRoot
.createSortedCursor( aProps
, aSortingInfo
, m_rCompareFactory
, INCLUDE_FOLDERS_ONLY
);
1532 catch ( Exception
& ) {}
1534 if ( !xResultSet
.is() )
1537 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1538 uno::Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1539 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1543 while ( xResultSet
->next() )
1545 const OUString aId
= xContentAccess
->queryContentIdentifierString();
1546 Content
aContent( aId
, aCmdEnv
, comphelper::getProcessComponentContext() );
1548 AddRegion( xRow
->getString( 1 ), aContent
);
1551 catch ( Exception
& ) {}
1555 bool SfxDocTemplate_Impl::Construct( )
1557 ::osl::MutexGuard
aGuard( maMutex
);
1559 if ( mbConstructed
)
1562 uno::Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1564 uno::Reference
< XPersist
> xInfo( document::DocumentProperties::create(xContext
), UNO_QUERY
);
1567 mxTemplates
= frame::DocumentTemplates::create(xContext
);
1569 uno::Reference
< XLocalizable
> xLocalizable( mxTemplates
, UNO_QUERY
);
1571 m_rCompareFactory
= AnyCompareFactory::createWithLocale(xContext
, xLocalizable
->getLocale());
1573 uno::Reference
< XContent
> aRootContent
= mxTemplates
->getContent();
1574 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1576 if ( ! aRootContent
.is() )
1579 mbConstructed
= true;
1580 maRootURL
= aRootContent
->getIdentifier()->getContentIdentifier();
1582 maStandardGroup
= DocTemplLocaleHelper::GetStandardGroupString();
1583 Content
aTemplRoot( aRootContent
, aCmdEnv
, xContext
);
1584 CreateFromHierarchy( aTemplRoot
);
1590 void SfxDocTemplate_Impl::ReInitFromComponent()
1592 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1593 if ( xTemplates
.is() )
1595 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1596 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1597 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1599 CreateFromHierarchy( aTemplRoot
);
1604 bool SfxDocTemplate_Impl::InsertRegion( std::unique_ptr
<RegionData_Impl
> pNew
, size_t nPos
)
1606 ::osl::MutexGuard
aGuard( maMutex
);
1608 // return false (not inserted) if the entry already exists
1609 for (auto const& pRegion
: maRegions
)
1610 if ( pRegion
->Compare( pNew
.get() ) == 0 )
1613 size_t newPos
= nPos
;
1614 if ( pNew
->GetTitle() == maStandardGroup
)
1617 if ( newPos
< maRegions
.size() )
1619 auto it
= maRegions
.begin();
1620 std::advance( it
, newPos
);
1621 maRegions
.emplace( it
, std::move(pNew
) );
1624 maRegions
.emplace_back( std::move(pNew
) );
1630 void SfxDocTemplate_Impl::Rescan()
1636 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1637 DBG_ASSERT( xTemplates
.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" );
1638 if ( xTemplates
.is() )
1640 xTemplates
->update();
1642 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1643 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1645 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1646 CreateFromHierarchy( aTemplRoot
);
1649 catch( const Exception
& )
1651 TOOLS_WARN_EXCEPTION( "sfx.doc", "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update" );
1656 bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString
& rURL
,
1663 mxInfo
->read( rURL
);
1665 catch ( Exception
& )
1667 // the document is not a StarOffice document
1674 uno::Reference
< XPropertySet
> aPropSet( mxInfo
, UNO_QUERY
);
1675 if ( aPropSet
.is() )
1677 Any aValue
= aPropSet
->getPropertyValue( TITLE
);
1681 catch ( IOException
& ) {}
1682 catch ( UnknownPropertyException
& ) {}
1683 catch ( Exception
& ) {}
1686 if ( aTitle
.isEmpty() )
1688 INetURLObject
aURL( rURL
);
1689 aURL
.CutExtension();
1690 aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true,
1691 INetURLObject::DecodeMechanism::WithCharset
);
1698 void SfxDocTemplate_Impl::Clear()
1700 ::osl::MutexGuard
aGuard( maMutex
);
1701 if ( mnLockCounter
)
1707 bool getTextProperty_Impl( Content
& rContent
,
1708 const OUString
& rPropName
,
1709 OUString
& rPropValue
)
1711 bool bGotProperty
= false;
1716 uno::Reference
< XPropertySetInfo
> aPropInfo
= rContent
.getProperties();
1718 // check, whether or not the property exists
1719 if ( !aPropInfo
.is() || !aPropInfo
->hasPropertyByName( rPropName
) )
1724 // now get the property
1725 Any aAnyValue
= rContent
.getPropertyValue( rPropName
);
1726 aAnyValue
>>= rPropValue
;
1728 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName
) )
1730 SfxURLRelocator_Impl
aRelocImpl( ::comphelper::getProcessComponentContext() );
1731 aRelocImpl
.makeAbsoluteURL( rPropValue
);
1734 bGotProperty
= true;
1736 catch ( RuntimeException
& ) {}
1737 catch ( Exception
& ) {}
1739 return bGotProperty
;
1742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */