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 <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>
57 #include "doctemplateslocal.hxx"
58 #include <sfxurlrelocator.hxx>
60 using namespace ::com::sun::star
;
61 using namespace ::com::sun::star::beans
;
62 using namespace ::com::sun::star::frame
;
63 using namespace ::com::sun::star::io
;
64 using namespace ::com::sun::star::lang
;
65 using namespace ::com::sun::star::sdbc
;
66 using namespace ::com::sun::star::uno
;
67 using namespace ::com::sun::star::ucb
;
68 using namespace ::com::sun::star::document
;
69 using namespace ::rtl
;
70 using namespace ::ucbhelper
;
73 #include <sfx2/doctempl.hxx>
74 #include <sfx2/objsh.hxx>
75 #include <sfx2/sfxresid.hxx>
76 #include <sfx2/strings.hrc>
77 #include <strings.hxx>
78 #include <svtools/templatefoldercache.hxx>
84 constexpr OUStringLiteral TITLE
= u
"Title";
85 constexpr OUStringLiteral TARGET_URL
= u
"TargetURL";
87 constexpr OUStringLiteral COMMAND_TRANSFER
= u
"transfer";
91 class RegionData_Impl
;
99 class DocTempl_EntryData_Impl
101 RegionData_Impl
* mpParent
;
103 // the following member must be SfxObjectShellLock since it controls that SfxObjectShell lifetime by design
104 // and users of this class expect it to be so.
105 SfxObjectShellLock mxObjShell
;
109 OUString maTargetURL
;
112 DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
113 const OUString
& rTitle
);
115 const OUString
& GetTitle() const { return maTitle
; }
116 const OUString
& GetTargetURL();
117 const OUString
& GetHierarchyURL();
119 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
120 void SetTargetURL( const OUString
& rURL
) { maTargetURL
= rURL
; }
121 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
123 int Compare( std::u16string_view rTitle
) const;
130 using namespace ::DocTempl
;
134 class RegionData_Impl
136 const SfxDocTemplate_Impl
* mpParent
;
137 std::vector
<std::unique_ptr
<DocTempl_EntryData_Impl
>> maEntries
;
142 size_t GetEntryPos( std::u16string_view rTitle
,
143 bool& rFound
) const;
146 RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
147 const OUString
& rTitle
);
149 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
151 DocTempl_EntryData_Impl
* GetEntry( size_t nIndex
) const;
152 DocTempl_EntryData_Impl
* GetEntry( std::u16string_view rName
) const;
154 const OUString
& GetTitle() const { return maTitle
; }
155 const OUString
& GetHierarchyURL();
157 size_t GetCount() const;
159 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
161 void AddEntry( const OUString
& rTitle
,
162 const OUString
& rTargetURL
,
163 const size_t *pPos
);
164 void DeleteEntry( size_t nIndex
);
166 int Compare( RegionData_Impl
const * pCompareWith
) const;
171 class SfxDocTemplate_Impl
: public SvRefBase
173 uno::Reference
< XPersist
> mxInfo
;
174 uno::Reference
< XDocumentTemplates
> mxTemplates
;
176 ::osl::Mutex maMutex
;
178 OUString maStandardGroup
;
179 std::vector
<std::unique_ptr
<RegionData_Impl
>> maRegions
;
182 uno::Reference
< XAnyCompareFactory
> m_rCompareFactory
;
184 // the following member is intended to prevent clearing of the global data when it is in use
185 // TODO/LATER: it still does not make the implementation complete thread-safe
186 sal_Int32 mnLockCounter
;
192 SfxDocTemplate_Impl();
193 virtual ~SfxDocTemplate_Impl() override
;
195 void IncrementLock();
196 void DecrementLock();
199 void CreateFromHierarchy( Content
&rTemplRoot
);
200 void ReInitFromComponent();
201 void AddRegion( const OUString
& rTitle
,
206 void DeleteRegion( size_t nIndex
);
208 size_t GetRegionCount() const
209 { return maRegions
.size(); }
210 RegionData_Impl
* GetRegion( std::u16string_view rName
) const;
211 RegionData_Impl
* GetRegion( size_t nIndex
) const;
213 bool GetTitleFromURL( const OUString
& rURL
, OUString
& aTitle
);
214 bool InsertRegion( std::unique_ptr
<RegionData_Impl
> pData
, size_t nPos
);
215 const OUString
& GetRootURL() const { return maRootURL
; }
217 const uno::Reference
< XDocumentTemplates
>& getDocTemplates() const { return mxTemplates
; }
222 class DocTemplLocker_Impl
224 SfxDocTemplate_Impl
& m_aDocTempl
;
226 explicit DocTemplLocker_Impl( SfxDocTemplate_Impl
& aDocTempl
)
227 : m_aDocTempl( aDocTempl
)
229 m_aDocTempl
.IncrementLock();
232 ~DocTemplLocker_Impl()
234 m_aDocTempl
.DecrementLock();
240 static SfxDocTemplate_Impl
*gpTemplateData
= nullptr;
243 static bool getTextProperty_Impl( Content
& rContent
,
244 const OUString
& rPropName
,
245 OUString
& rPropValue
);
248 OUString
SfxDocumentTemplates::GetFullRegionName
250 sal_uInt16 nIdx
// Region Index
255 Returns the logical name of a region and its path
257 [Return value] Reference to the Region name
262 // First: find the RegionData for the index
264 DocTemplLocker_Impl
aLocker( *pImp
);
266 if ( pImp
->Construct() )
268 RegionData_Impl
*pData1
= pImp
->GetRegion( nIdx
);
271 return pData1
->GetTitle();
273 // --**-- here was some code which appended the path to the
274 // group if there was more than one with the same name.
275 // this should not happen anymore
282 OUString
SfxDocumentTemplates::GetRegionName
284 sal_uInt16 nIdx
// Region Index
289 Returns the logical name of a region
293 const String& Reference to the Region name
297 DocTemplLocker_Impl
aLocker( *pImp
);
299 if ( pImp
->Construct() )
301 RegionData_Impl
*pData
= pImp
->GetRegion( nIdx
);
304 return pData
->GetTitle();
311 sal_uInt16
SfxDocumentTemplates::GetRegionCount() const
315 Returns the number of Regions
319 sal_uInt16 Number of Regions
322 DocTemplLocker_Impl
aLocker( *pImp
);
324 if ( !pImp
->Construct() )
327 return pImp
->GetRegionCount();
331 sal_uInt16
SfxDocumentTemplates::GetCount
333 sal_uInt16 nRegion
/* Region index whose number is
340 Number of entries in Region
342 [Return value] Number of entries
346 DocTemplLocker_Impl
aLocker( *pImp
);
348 if ( !pImp
->Construct() )
351 RegionData_Impl
*pData
= pImp
->GetRegion( nRegion
);
356 return pData
->GetCount();
360 OUString
SfxDocumentTemplates::GetName
362 sal_uInt16 nRegion
, // Region Index, in which the entry lies
363 sal_uInt16 nIdx
// Index of the entry
368 Returns the logical name of an entry in Region
372 const String& Entry Name
376 DocTemplLocker_Impl
aLocker( *pImp
);
378 if ( pImp
->Construct() )
380 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
384 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
386 return pEntry
->GetTitle();
394 OUString
SfxDocumentTemplates::GetPath
396 sal_uInt16 nRegion
, // Region Index, in which the entry lies
397 sal_uInt16 nIdx
// Index of the entry
402 Returns the file name with full path to the file assigned to an entry
406 String File name with full path
409 DocTemplLocker_Impl
aLocker( *pImp
);
411 if ( !pImp
->Construct() )
414 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
418 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
420 return pEntry
->GetTargetURL();
427 OUString
SfxDocumentTemplates::GetTemplateTargetURLFromComponent( std::u16string_view aGroupName
,
428 std::u16string_view aTitle
)
430 DocTemplLocker_Impl
aLocker( *pImp
);
432 INetURLObject
aTemplateObj( pImp
->GetRootURL() );
434 aTemplateObj
.insertName( aGroupName
, false,
435 INetURLObject::LAST_SEGMENT
,
436 INetURLObject::EncodeMechanism::All
);
438 aTemplateObj
.insertName( aTitle
, false,
439 INetURLObject::LAST_SEGMENT
,
440 INetURLObject::EncodeMechanism::All
);
444 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
445 if ( Content::create( aTemplateObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aCmdEnv
, comphelper::getProcessComponentContext(), aTemplate
) )
448 getTextProperty_Impl( aTemplate
, TARGET_URL
, aResult
);
449 return SvtPathOptions().SubstituteVariable( aResult
);
456 /** Convert a template name to its localised pair if it exists.
458 Name to be translated.
460 The localised pair of rString or rString if the former does not exist.
462 OUString
SfxDocumentTemplates::ConvertResourceString(const OUString
& rString
)
464 static const std::u16string_view aTemplateNames
[] =
466 u
"" STR_TEMPLATE_NAME1_DEF
,
467 u
"" STR_TEMPLATE_NAME2_DEF
,
468 u
"" STR_TEMPLATE_NAME3_DEF
,
469 u
"" STR_TEMPLATE_NAME4_DEF
,
470 u
"" STR_TEMPLATE_NAME5_DEF
,
471 u
"" STR_TEMPLATE_NAME6_DEF
,
472 u
"" STR_TEMPLATE_NAME7_DEF
,
473 u
"" STR_TEMPLATE_NAME8_DEF
,
474 u
"" STR_TEMPLATE_NAME9_DEF
,
475 u
"" STR_TEMPLATE_NAME10_DEF
,
476 u
"" STR_TEMPLATE_NAME11_DEF
,
477 u
"" STR_TEMPLATE_NAME12_DEF
,
478 u
"" STR_TEMPLATE_NAME13_DEF
,
479 u
"" STR_TEMPLATE_NAME14_DEF
,
480 u
"" STR_TEMPLATE_NAME15_DEF
,
481 u
"" STR_TEMPLATE_NAME16_DEF
,
482 u
"" STR_TEMPLATE_NAME17_DEF
,
483 u
"" STR_TEMPLATE_NAME18_DEF
,
484 u
"" STR_TEMPLATE_NAME19_DEF
,
485 u
"" STR_TEMPLATE_NAME20_DEF
,
486 u
"" STR_TEMPLATE_NAME21_DEF
,
487 u
"" STR_TEMPLATE_NAME22_DEF
,
488 u
"" STR_TEMPLATE_NAME23_DEF
,
489 u
"" STR_TEMPLATE_NAME24_DEF
,
490 u
"" STR_TEMPLATE_NAME25_DEF
,
491 u
"" STR_TEMPLATE_NAME26_DEF
,
492 u
"" STR_TEMPLATE_NAME27_DEF
,
493 u
"" STR_TEMPLATE_NAME28_DEF
,
494 u
"" STR_TEMPLATE_NAME29_DEF
,
495 u
"" STR_TEMPLATE_NAME30_DEF
,
496 u
"" STR_TEMPLATE_NAME31_DEF
,
497 u
"" STR_TEMPLATE_NAME32_DEF
,
500 TranslateId STR_TEMPLATE_NAME
[] =
536 static_assert(SAL_N_ELEMENTS(aTemplateNames
) == SAL_N_ELEMENTS(STR_TEMPLATE_NAME
));
538 for (size_t i
= 0; i
< SAL_N_ELEMENTS(STR_TEMPLATE_NAME
); ++i
)
540 if (rString
== aTemplateNames
[i
])
541 return SfxResId(STR_TEMPLATE_NAME
[i
]);
547 bool SfxDocumentTemplates::CopyOrMove
549 sal_uInt16 nTargetRegion
, // Target Region Index
550 sal_uInt16 nTargetIdx
, // Target position Index
551 sal_uInt16 nSourceRegion
, // Source Region Index
552 sal_uInt16 nSourceIdx
, /* Index to be copied / to moved template */
553 bool bMove
// Copy / Move
558 Copy or move a document template
562 sal_Bool sal_True, Action could be performed
563 sal_False, Action could not be performed
567 <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
568 <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
572 /* to perform a copy or move, we need to send a transfer command to
573 the destination folder with the URL of the source as parameter.
574 ( If the destination content doesn't support the transfer command,
575 we could try a copy ( and delete ) instead. )
576 We need two transfers ( one for the real template and one for its
577 representation in the hierarchy )
581 DocTemplLocker_Impl
aLocker( *pImp
);
583 if ( !pImp
->Construct() )
586 // Don't copy or move any folders
587 if( nSourceIdx
== USHRT_MAX
)
590 if ( nSourceRegion
== nTargetRegion
)
592 SAL_WARN( "sfx.doc", "Don't know, what to do!" );
596 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nSourceRegion
);
600 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nSourceIdx
);
604 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nTargetRegion
);
608 const OUString aTitle
= pSource
->GetTitle();
610 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
612 if ( xTemplates
->addTemplate( pTargetRgn
->GetTitle(),
614 pSource
->GetTargetURL() ) )
616 const OUString aNewTargetURL
= GetTemplateTargetURLFromComponent( pTargetRgn
->GetTitle(), aTitle
);
617 if ( aNewTargetURL
.isEmpty() )
622 // --**-- delete the original file
623 bool bDeleted
= xTemplates
->removeTemplate( pSourceRgn
->GetTitle(),
624 pSource
->GetTitle() );
626 pSourceRgn
->DeleteEntry( nSourceIdx
);
629 if ( xTemplates
->removeTemplate( pTargetRgn
->GetTitle(), aTitle
) )
630 return false; // will trigger retry with copy instead of move
632 // if it is not possible to remove just created template ( must be possible! )
633 // it is better to report success here, since at least the copy has succeeded
634 // TODO/LATER: solve it more gracefully in future
638 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
639 size_t temp_nTargetIdx
= nTargetIdx
;
640 pTargetRgn
->AddEntry( aTitle
, aNewTargetURL
, &temp_nTargetIdx
);
645 // --**-- if the current file is opened,
646 // it must be re-opened afterwards.
652 bool SfxDocumentTemplates::Move
654 sal_uInt16 nTargetRegion
, // Target Region Index
655 sal_uInt16 nTargetIdx
, // Target position Index
656 sal_uInt16 nSourceRegion
, // Source Region Index
657 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
666 sal_Bool sal_True, Action could be performed
667 sal_False, Action could not be performed
671 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
674 DocTemplLocker_Impl
aLocker( *pImp
);
676 return CopyOrMove( nTargetRegion
, nTargetIdx
,
677 nSourceRegion
, nSourceIdx
, true );
681 bool SfxDocumentTemplates::Copy
683 sal_uInt16 nTargetRegion
, // Target Region Index
684 sal_uInt16 nTargetIdx
, // Target position Index
685 sal_uInt16 nSourceRegion
, // Source Region Index
686 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
695 sal_Bool sal_True, Action could be performed
696 sal_False, Action could not be performed
700 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
704 DocTemplLocker_Impl
aLocker( *pImp
);
706 return CopyOrMove( nTargetRegion
, nTargetIdx
,
707 nSourceRegion
, nSourceIdx
, false );
711 bool SfxDocumentTemplates::CopyTo
713 sal_uInt16 nRegion
, // Region of the template to be exported
714 sal_uInt16 nIdx
, // Index of the template to be exported
715 const OUString
& rName
/* File name under which the template is to
721 Exporting a template into the file system
725 sal_Bool sal_True, Action could be performed
726 sal_False, Action could not be performed
730 <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
734 DocTemplLocker_Impl
aLocker( *pImp
);
736 if ( ! pImp
->Construct() )
739 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nRegion
);
743 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nIdx
);
747 INetURLObject
aTargetURL( rName
);
749 const OUString
aTitle( aTargetURL
.getName( INetURLObject::LAST_SEGMENT
, true,
750 INetURLObject::DecodeMechanism::WithCharset
) );
751 aTargetURL
.removeSegment();
753 const OUString aParentURL
= aTargetURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
755 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
760 aTarget
= Content( aParentURL
, aCmdEnv
, comphelper::getProcessComponentContext() );
762 TransferInfo aTransferInfo
;
763 aTransferInfo
.MoveData
= false;
764 aTransferInfo
.SourceURL
= pSource
->GetTargetURL();
765 aTransferInfo
.NewTitle
= aTitle
;
766 aTransferInfo
.NameClash
= NameClash::RENAME
;
768 Any aArg
= makeAny( aTransferInfo
);
769 aTarget
.executeCommand( COMMAND_TRANSFER
, aArg
);
771 catch ( ContentCreationException
& )
780 bool SfxDocumentTemplates::CopyFrom
782 sal_uInt16 nRegion
, /* Region in which the template is to be
784 sal_uInt16 nIdx
, // Index of the new template in this Region
785 OUString
& rName
/* File name of the template to be imported
786 as an out parameter of the (automatically
787 generated from the file name) logical name
793 Import a template from the file system
795 [Return value] Success (sal_True) or serfpTargetDirectory->GetContent());
797 sal_Bool sal_True, Action could be performed
798 sal_False, Action could not be performed
802 <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
806 DocTemplLocker_Impl
aLocker( *pImp
);
808 if ( ! pImp
->Construct() )
811 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nRegion
);
816 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
817 if ( !xTemplates
.is() )
821 bool bTemplateAdded
= false;
823 if( pImp
->GetTitleFromURL( rName
, aTitle
) )
825 bTemplateAdded
= xTemplates
->addTemplate( pTargetRgn
->GetTitle(), aTitle
, rName
);
829 uno::Reference
< XDesktop2
> xDesktop
= Desktop::create( ::comphelper::getProcessComponentContext() );
831 Sequence
< PropertyValue
> aArgs
{ comphelper::makePropertyValue("Hidden", true) };
833 INetURLObject
aTemplURL( rName
);
834 uno::Reference
< XDocumentPropertiesSupplier
> xDocPropsSupplier
;
835 uno::Reference
< XStorable
> xStorable
;
839 xDesktop
->loadComponentFromURL( aTemplURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),
845 xDocPropsSupplier
.set( xStorable
, UNO_QUERY
);
853 // get Title from XDocumentPropertiesSupplier
854 if( xDocPropsSupplier
.is() )
856 uno::Reference
< XDocumentProperties
> xDocProps
857 = xDocPropsSupplier
->getDocumentProperties();
858 if (xDocProps
.is() ) {
859 aTitle
= xDocProps
->getTitle();
863 if( aTitle
.isEmpty() )
865 INetURLObject
aURL( aTemplURL
);
867 aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true,
868 INetURLObject::DecodeMechanism::WithCharset
);
871 // write a template using XStorable interface
872 bTemplateAdded
= xTemplates
->storeTemplate( pTargetRgn
->GetTitle(), aTitle
, xStorable
);
879 INetURLObject
aTemplObj( pTargetRgn
->GetHierarchyURL() );
880 aTemplObj
.insertName( aTitle
, false,
881 INetURLObject::LAST_SEGMENT
,
882 INetURLObject::EncodeMechanism::All
);
883 const OUString aTemplURL
= aTemplObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
885 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
888 if( Content::create( aTemplURL
, aCmdEnv
, comphelper::getProcessComponentContext(), aTemplCont
) )
891 if( getTextProperty_Impl( aTemplCont
, TARGET_URL
, aTemplName
) )
893 if ( nIdx
== USHRT_MAX
)
898 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
899 size_t temp_nIdx
= nIdx
;
900 pTargetRgn
->AddEntry( aTitle
, aTemplName
, &temp_nIdx
);
906 SAL_WARN( "sfx.doc", "CopyFrom(): The content should contain target URL!" );
911 SAL_WARN( "sfx.doc", "CopyFrom(): The content just was created!" );
919 bool SfxDocumentTemplates::Delete
921 sal_uInt16 nRegion
, // Region Index
922 sal_uInt16 nIdx
/* Index of the entry or USHRT_MAX,
923 if a directory is meant. */
928 Deleting an entry or a directory
932 sal_Bool sal_True, Action could be performed
933 sal_False, Action could not be performed
937 <SfxDocumentTemplates::InsertDir(const String&,sal_uInt16)>
938 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
942 DocTemplLocker_Impl
aLocker( *pImp
);
944 /* delete the template or folder in the hierarchy and in the
945 template folder by sending a delete command to the content.
946 Then remove the data from the lists
948 if ( ! pImp
->Construct() )
951 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
957 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
959 if ( nIdx
== USHRT_MAX
)
961 bRet
= xTemplates
->removeGroup( pRegion
->GetTitle() );
963 pImp
->DeleteRegion( nRegion
);
967 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
972 bRet
= xTemplates
->removeTemplate( pRegion
->GetTitle(),
973 pEntry
->GetTitle() );
975 pRegion
->DeleteEntry( nIdx
);
982 bool SfxDocumentTemplates::InsertDir
984 const OUString
& rText
, // the logical name of the new Region
985 sal_uInt16 nRegion
// Region Index
994 sal_Bool sal_True, Action could be performed
995 sal_False, Action could not be performed
999 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
1002 DocTemplLocker_Impl
aLocker( *pImp
);
1004 if ( ! pImp
->Construct() )
1007 RegionData_Impl
*pRegion
= pImp
->GetRegion( rText
);
1012 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1014 if ( xTemplates
->addGroup( rText
) )
1016 return pImp
->InsertRegion( std::make_unique
<RegionData_Impl
>( pImp
.get(), rText
), nRegion
);
1022 bool SfxDocumentTemplates::InsertTemplate(sal_uInt16 nSourceRegion
, sal_uInt16 nIdx
, const OUString
&rName
, const OUString
&rPath
)
1024 DocTemplLocker_Impl
aLocker( *pImp
);
1026 if ( ! pImp
->Construct() )
1029 RegionData_Impl
*pRegion
= pImp
->GetRegion( nSourceRegion
);
1035 pRegion
->AddEntry( rName
, rPath
, &pos
);
1040 bool SfxDocumentTemplates::SetName( const OUString
& rName
, sal_uInt16 nRegion
, sal_uInt16 nIdx
)
1043 DocTemplLocker_Impl
aLocker( *pImp
);
1045 if ( ! pImp
->Construct() )
1048 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
1053 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1055 if ( nIdx
== USHRT_MAX
)
1057 if ( pRegion
->GetTitle() == rName
)
1060 // we have to rename a region
1061 if ( xTemplates
->renameGroup( pRegion
->GetTitle(), rName
) )
1063 pRegion
->SetTitle( rName
);
1064 pRegion
->SetHierarchyURL( "" );
1070 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
1075 if ( pEntry
->GetTitle() == rName
)
1078 if ( xTemplates
->renameTemplate( pRegion
->GetTitle(),
1082 pEntry
->SetTitle( rName
);
1083 pEntry
->SetTargetURL( "" );
1084 pEntry
->SetHierarchyURL( "" );
1093 bool SfxDocumentTemplates::GetFull
1095 std::u16string_view rRegion
, // Region Name
1096 std::u16string_view rName
, // Template Name
1097 OUString
&rPath
// Out: Path + File name
1102 Returns Path + File name of the template specified by rRegion and rName.
1106 sal_Bool sal_True, Action could be performed
1107 sal_False, Action could not be performed
1111 <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1115 DocTemplLocker_Impl
aLocker( *pImp
);
1117 // We don't search for empty names!
1118 if ( rName
.empty() )
1121 if ( ! pImp
->Construct() )
1124 DocTempl_EntryData_Impl
* pEntry
= nullptr;
1125 const sal_uInt16 nCount
= GetRegionCount();
1127 for ( sal_uInt16 i
= 0; i
< nCount
; ++i
)
1129 RegionData_Impl
*pRegion
= pImp
->GetRegion( i
);
1132 ( rRegion
.empty() || ( rRegion
== pRegion
->GetTitle() ) ) )
1134 pEntry
= pRegion
->GetEntry( rName
);
1138 rPath
= pEntry
->GetTargetURL();
1144 return ( pEntry
!= nullptr );
1148 bool SfxDocumentTemplates::GetLogicNames
1150 const OUString
&rPath
, // Full Path to the template
1151 OUString
&rRegion
, // Out: Region name
1152 OUString
&rName
// Out: Template name
1157 Returns and logical path name to the template specified by rPath
1161 sal_Bool sal_True, Action could be performed
1162 sal_False, Action could not be performed
1166 <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1170 DocTemplLocker_Impl
aLocker( *pImp
);
1172 if ( ! pImp
->Construct() )
1175 INetURLObject aFullPath
;
1177 aFullPath
.SetSmartProtocol( INetProtocol::File
);
1178 aFullPath
.SetURL( rPath
);
1179 const OUString
aPath( aFullPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1181 const sal_uInt16 nCount
= GetRegionCount();
1183 for ( sal_uInt16 i
=0; i
<nCount
; ++i
)
1185 RegionData_Impl
*pData
= pImp
->GetRegion( i
);
1188 const sal_uInt16 nChildCount
= pData
->GetCount();
1190 for ( sal_uInt16 j
=0; j
<nChildCount
; ++j
)
1192 DocTempl_EntryData_Impl
*pEntry
= pData
->GetEntry( j
);
1193 if ( pEntry
&& pEntry
->GetTargetURL() == aPath
)
1195 rRegion
= pData
->GetTitle();
1196 rName
= pEntry
->GetTitle();
1207 SfxDocumentTemplates::SfxDocumentTemplates()
1214 if ( !gpTemplateData
)
1215 gpTemplateData
= new SfxDocTemplate_Impl
;
1217 pImp
= gpTemplateData
;
1221 SfxDocumentTemplates::~SfxDocumentTemplates()
1226 Release of administrative data
1233 void SfxDocumentTemplates::Update( )
1235 if ( ::svt::TemplateFolderCache( true ).needsUpdate() ) // update is really necessary
1237 if ( pImp
->Construct() )
1242 void SfxDocumentTemplates::ReInitFromComponent()
1244 pImp
->ReInitFromComponent();
1247 DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
1248 const OUString
& rTitle
)
1251 maTitle
= SfxDocumentTemplates::ConvertResourceString(rTitle
);
1255 int DocTempl_EntryData_Impl::Compare( std::u16string_view rTitle
) const
1257 return maTitle
.compareTo( rTitle
);
1261 const OUString
& DocTempl_EntryData_Impl::GetHierarchyURL()
1263 if ( maOwnURL
.isEmpty() )
1265 INetURLObject
aTemplateObj( mpParent
->GetHierarchyURL() );
1267 aTemplateObj
.insertName( GetTitle(), false,
1268 INetURLObject::LAST_SEGMENT
,
1269 INetURLObject::EncodeMechanism::All
);
1271 maOwnURL
= aTemplateObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1272 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1279 const OUString
& DocTempl_EntryData_Impl::GetTargetURL()
1281 if ( maTargetURL
.isEmpty() )
1283 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1286 if ( Content::create( GetHierarchyURL(), aCmdEnv
, comphelper::getProcessComponentContext(), aRegion
) )
1288 getTextProperty_Impl( aRegion
, TARGET_URL
, maTargetURL
);
1292 SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1300 RegionData_Impl::RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
1301 const OUString
& rTitle
)
1302 : mpParent(pParent
), maTitle(rTitle
)
1307 size_t RegionData_Impl::GetEntryPos( std::u16string_view rTitle
, bool& rFound
) const
1309 const size_t nCount
= maEntries
.size();
1311 for ( size_t i
=0; i
<nCount
; ++i
)
1313 auto &pData
= maEntries
[ i
];
1315 if ( pData
->Compare( rTitle
) == 0 )
1327 void RegionData_Impl::AddEntry( const OUString
& rTitle
,
1328 const OUString
& rTargetURL
,
1329 const size_t *pPos
)
1331 INetURLObject
aLinkObj( GetHierarchyURL() );
1332 aLinkObj
.insertName( rTitle
, false,
1333 INetURLObject::LAST_SEGMENT
,
1334 INetURLObject::EncodeMechanism::All
);
1335 const OUString aLinkURL
= aLinkObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1337 bool bFound
= false;
1338 size_t nPos
= GetEntryPos( rTitle
, bFound
);
1346 auto pEntry
= std::make_unique
<DocTempl_EntryData_Impl
>(
1348 pEntry
->SetTargetURL( rTargetURL
);
1349 pEntry
->SetHierarchyURL( aLinkURL
);
1350 if ( nPos
< maEntries
.size() ) {
1351 auto it
= maEntries
.begin();
1352 std::advance( it
, nPos
);
1353 maEntries
.insert( it
, std::move(pEntry
) );
1356 maEntries
.push_back( std::move(pEntry
) );
1360 size_t RegionData_Impl::GetCount() const
1362 return maEntries
.size();
1366 const OUString
& RegionData_Impl::GetHierarchyURL()
1368 if ( maOwnURL
.isEmpty() )
1370 INetURLObject
aRegionObj( mpParent
->GetRootURL() );
1372 aRegionObj
.insertName( GetTitle(), false,
1373 INetURLObject::LAST_SEGMENT
,
1374 INetURLObject::EncodeMechanism::All
);
1376 maOwnURL
= aRegionObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1377 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1384 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( std::u16string_view rName
) const
1386 bool bFound
= false;
1387 tools::Long nPos
= GetEntryPos( rName
, bFound
);
1390 return maEntries
[ nPos
].get();
1395 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( size_t nIndex
) const
1397 if ( nIndex
< maEntries
.size() )
1398 return maEntries
[ nIndex
].get();
1403 void RegionData_Impl::DeleteEntry( size_t nIndex
)
1405 if ( nIndex
< maEntries
.size() )
1407 auto it
= maEntries
.begin();
1408 std::advance( it
, nIndex
);
1409 maEntries
.erase( it
);
1414 int RegionData_Impl::Compare( RegionData_Impl
const * pCompare
) const
1416 return maTitle
.compareTo( pCompare
->maTitle
);
1420 SfxDocTemplate_Impl::SfxDocTemplate_Impl()
1421 : mbConstructed( false )
1422 , mnLockCounter( 0 )
1427 SfxDocTemplate_Impl::~SfxDocTemplate_Impl()
1429 gpTemplateData
= nullptr;
1433 void SfxDocTemplate_Impl::IncrementLock()
1435 ::osl::MutexGuard
aGuard( maMutex
);
1440 void SfxDocTemplate_Impl::DecrementLock()
1442 ::osl::MutexGuard
aGuard( maMutex
);
1443 if ( mnLockCounter
)
1448 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( size_t nIndex
) const
1450 if ( nIndex
< maRegions
.size() )
1451 return maRegions
[ nIndex
].get();
1456 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( std::u16string_view rName
)
1459 for (auto& pData
: maRegions
)
1461 if( pData
->GetTitle() == rName
)
1468 void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex
)
1470 if ( nIndex
< maRegions
.size() )
1472 auto it
= maRegions
.begin();
1473 std::advance( it
, nIndex
);
1474 maRegions
.erase( it
);
1479 /* AddRegion adds a Region to the RegionList
1481 void SfxDocTemplate_Impl::AddRegion( const OUString
& rTitle
,
1484 auto pRegion
= std::make_unique
<RegionData_Impl
>( this, rTitle
);
1485 auto pRegionTmp
= pRegion
.get();
1487 if ( ! InsertRegion( std::move(pRegion
), size_t(-1) ) )
1492 // now get the content of the region
1493 uno::Reference
< XResultSet
> xResultSet
;
1497 xResultSet
= rContent
.createSortedCursor( { TITLE
, TARGET_URL
}, { { 1, true } }, m_rCompareFactory
, INCLUDE_DOCUMENTS_ONLY
);
1499 catch ( Exception
& ) {}
1501 if ( !xResultSet
.is() )
1504 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1508 while ( xResultSet
->next() )
1510 pRegionTmp
->AddEntry( xRow
->getString( 1 ), xRow
->getString( 2 ), nullptr );
1513 catch ( Exception
& ) {}
1517 void SfxDocTemplate_Impl::CreateFromHierarchy( Content
&rTemplRoot
)
1519 uno::Reference
< XResultSet
> xResultSet
;
1520 Sequence
< OUString
> aProps
{ TITLE
};
1524 Sequence
< NumberedSortingInfo
> aSortingInfo(1);
1525 aSortingInfo
.getArray()->ColumnIndex
= 1;
1526 aSortingInfo
.getArray()->Ascending
= true;
1527 xResultSet
= rTemplRoot
.createSortedCursor( aProps
, aSortingInfo
, m_rCompareFactory
, INCLUDE_FOLDERS_ONLY
);
1529 catch ( Exception
& ) {}
1531 if ( !xResultSet
.is() )
1534 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1535 uno::Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1536 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1540 while ( xResultSet
->next() )
1542 const OUString aId
= xContentAccess
->queryContentIdentifierString();
1543 Content
aContent( aId
, aCmdEnv
, comphelper::getProcessComponentContext() );
1545 AddRegion( xRow
->getString( 1 ), aContent
);
1548 catch ( Exception
& ) {}
1552 bool SfxDocTemplate_Impl::Construct( )
1554 ::osl::MutexGuard
aGuard( maMutex
);
1556 if ( mbConstructed
)
1559 uno::Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1561 uno::Reference
< XPersist
> xInfo( document::DocumentProperties::create(xContext
), UNO_QUERY
);
1564 mxTemplates
= frame::DocumentTemplates::create(xContext
);
1566 uno::Reference
< XLocalizable
> xLocalizable( mxTemplates
, UNO_QUERY
);
1568 m_rCompareFactory
= AnyCompareFactory::createWithLocale(xContext
, xLocalizable
->getLocale());
1570 uno::Reference
< XContent
> aRootContent
= mxTemplates
->getContent();
1571 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1573 if ( ! aRootContent
.is() )
1576 mbConstructed
= true;
1577 maRootURL
= aRootContent
->getIdentifier()->getContentIdentifier();
1579 maStandardGroup
= DocTemplLocaleHelper::GetStandardGroupString();
1580 Content
aTemplRoot( aRootContent
, aCmdEnv
, xContext
);
1581 CreateFromHierarchy( aTemplRoot
);
1587 void SfxDocTemplate_Impl::ReInitFromComponent()
1589 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1590 if ( xTemplates
.is() )
1592 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1593 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1594 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1596 CreateFromHierarchy( aTemplRoot
);
1601 bool SfxDocTemplate_Impl::InsertRegion( std::unique_ptr
<RegionData_Impl
> pNew
, size_t nPos
)
1603 ::osl::MutexGuard
aGuard( maMutex
);
1605 // return false (not inserted) if the entry already exists
1606 for (auto const& pRegion
: maRegions
)
1607 if ( pRegion
->Compare( pNew
.get() ) == 0 )
1610 size_t newPos
= nPos
;
1611 if ( pNew
->GetTitle() == maStandardGroup
)
1614 if ( newPos
< maRegions
.size() )
1616 auto it
= maRegions
.begin();
1617 std::advance( it
, newPos
);
1618 maRegions
.emplace( it
, std::move(pNew
) );
1621 maRegions
.emplace_back( std::move(pNew
) );
1627 void SfxDocTemplate_Impl::Rescan()
1633 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1634 DBG_ASSERT( xTemplates
.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" );
1635 if ( xTemplates
.is() )
1637 xTemplates
->update();
1639 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1640 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1642 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1643 CreateFromHierarchy( aTemplRoot
);
1646 catch( const Exception
& )
1648 TOOLS_WARN_EXCEPTION( "sfx.doc", "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update" );
1653 bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString
& rURL
,
1660 mxInfo
->read( rURL
);
1662 catch ( Exception
& )
1664 // the document is not a StarOffice document
1671 uno::Reference
< XPropertySet
> aPropSet( mxInfo
, UNO_QUERY
);
1672 if ( aPropSet
.is() )
1674 Any aValue
= aPropSet
->getPropertyValue( TITLE
);
1678 catch ( IOException
& ) {}
1679 catch ( UnknownPropertyException
& ) {}
1680 catch ( Exception
& ) {}
1683 if ( aTitle
.isEmpty() )
1685 INetURLObject
aURL( rURL
);
1686 aURL
.CutExtension();
1687 aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true,
1688 INetURLObject::DecodeMechanism::WithCharset
);
1695 void SfxDocTemplate_Impl::Clear()
1697 ::osl::MutexGuard
aGuard( maMutex
);
1698 if ( mnLockCounter
)
1704 bool getTextProperty_Impl( Content
& rContent
,
1705 const OUString
& rPropName
,
1706 OUString
& rPropValue
)
1708 bool bGotProperty
= false;
1713 uno::Reference
< XPropertySetInfo
> aPropInfo
= rContent
.getProperties();
1715 // check, whether or not the property exists
1716 if ( !aPropInfo
.is() || !aPropInfo
->hasPropertyByName( rPropName
) )
1721 // now get the property
1722 Any aAnyValue
= rContent
.getPropertyValue( rPropName
);
1723 aAnyValue
>>= rPropValue
;
1725 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName
) )
1727 SfxURLRelocator_Impl
aRelocImpl( ::comphelper::getProcessComponentContext() );
1728 aRelocImpl
.makeAbsoluteURL( rPropValue
);
1731 bGotProperty
= true;
1733 catch ( RuntimeException
& ) {}
1734 catch ( Exception
& ) {}
1736 return bGotProperty
;
1739 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */