Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / doc / doctempl.cxx
blob726122c9f1cbfdc25550257e87616ef2a4d223f5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <limits.h>
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>
79 #include <memory>
80 #include <vector>
83 #define TITLE "Title"
84 #define TARGET_URL "TargetURL"
86 #define COMMAND_TRANSFER "transfer"
88 namespace {
90 class RegionData_Impl;
94 namespace DocTempl {
96 namespace {
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;
106 OUString maTitle;
107 OUString maOwnURL;
108 OUString maTargetURL;
110 public:
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;
131 namespace {
133 class RegionData_Impl
135 const SfxDocTemplate_Impl* mpParent;
136 std::vector<std::unique_ptr<DocTempl_EntryData_Impl>> maEntries;
137 OUString maTitle;
138 OUString maOwnURL;
140 private:
141 size_t GetEntryPos( const OUString& rTitle,
142 bool& rFound ) const;
144 public:
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;
176 OUString maRootURL;
177 OUString maStandardGroup;
178 std::vector<std::unique_ptr<RegionData_Impl>> maRegions;
179 bool mbConstructed;
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;
187 private:
188 void Clear();
190 public:
191 SfxDocTemplate_Impl();
192 virtual ~SfxDocTemplate_Impl() override;
194 void IncrementLock();
195 void DecrementLock();
197 bool Construct( );
198 void CreateFromHierarchy( Content &rTemplRoot );
199 void ReInitFromComponent();
200 void AddRegion( const OUString& rTitle,
201 Content& rContent );
203 void Rescan();
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; }
219 namespace {
221 class DocTemplLocker_Impl
223 SfxDocTemplate_Impl& m_aDocTempl;
224 public:
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
250 ) const
252 /* [Description]
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 );
269 if ( pData1 )
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
277 return OUString();
281 OUString SfxDocumentTemplates::GetRegionName
283 sal_uInt16 nIdx // Region Index
284 ) const
286 /* [Description]
288 Returns the logical name of a region
290 [Return value]
292 const String& Reference to the Region name
296 DocTemplLocker_Impl aLocker( *pImp );
298 if ( pImp->Construct() )
300 RegionData_Impl *pData = pImp->GetRegion( nIdx );
302 if ( pData )
303 return pData->GetTitle();
306 return OUString();
310 sal_uInt16 SfxDocumentTemplates::GetRegionCount() const
312 /* [Description]
314 Returns the number of Regions
316 [Return value]
318 sal_uInt16 Number of Regions
321 DocTemplLocker_Impl aLocker( *pImp );
323 if ( !pImp->Construct() )
324 return 0;
326 return pImp->GetRegionCount();
330 sal_uInt16 SfxDocumentTemplates::GetCount
332 sal_uInt16 nRegion /* Region index whose number is
333 to be determined */
335 ) const
337 /* [Description]
339 Number of entries in Region
341 [Return value] Number of entries
345 DocTemplLocker_Impl aLocker( *pImp );
347 if ( !pImp->Construct() )
348 return 0;
350 RegionData_Impl *pData = pImp->GetRegion( nRegion );
352 if ( !pData )
353 return 0;
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
363 ) const
365 /* [Description]
367 Returns the logical name of an entry in Region
369 [Return value]
371 const String& Entry Name
375 DocTemplLocker_Impl aLocker( *pImp );
377 if ( pImp->Construct() )
379 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
381 if ( pRegion )
383 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
384 if ( pEntry )
385 return pEntry->GetTitle();
389 return OUString();
393 OUString SfxDocumentTemplates::GetPath
395 sal_uInt16 nRegion, // Region Index, in which the entry lies
396 sal_uInt16 nIdx // Index of the entry
397 ) const
399 /* [Description]
401 Returns the file name with full path to the file assigned to an entry
403 [Return value]
405 String File name with full path
408 DocTemplLocker_Impl aLocker( *pImp );
410 if ( !pImp->Construct() )
411 return OUString();
413 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
415 if ( pRegion )
417 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
418 if ( pEntry )
419 return pEntry->GetTargetURL();
422 return OUString();
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 );
442 Content aTemplate;
443 uno::Reference< XCommandEnvironment > aCmdEnv;
444 if ( Content::create( aTemplateObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
446 OUString aResult;
447 getTextProperty_Impl( aTemplate, TARGET_URL, aResult );
448 return SvtPathOptions().SubstituteVariable( aResult );
451 return OUString();
455 /** Convert a template name to its localised pair if it exists.
456 @param rString
457 Name to be translated.
458 @return
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[] =
499 STR_TEMPLATE_NAME1,
500 STR_TEMPLATE_NAME2,
501 STR_TEMPLATE_NAME3,
502 STR_TEMPLATE_NAME4,
503 STR_TEMPLATE_NAME5,
504 STR_TEMPLATE_NAME6,
505 STR_TEMPLATE_NAME7,
506 STR_TEMPLATE_NAME8,
507 STR_TEMPLATE_NAME9,
508 STR_TEMPLATE_NAME10,
509 STR_TEMPLATE_NAME11,
510 STR_TEMPLATE_NAME12,
511 STR_TEMPLATE_NAME13,
512 STR_TEMPLATE_NAME14,
513 STR_TEMPLATE_NAME15,
514 STR_TEMPLATE_NAME16,
515 STR_TEMPLATE_NAME17,
516 STR_TEMPLATE_NAME18,
517 STR_TEMPLATE_NAME19,
518 STR_TEMPLATE_NAME20,
519 STR_TEMPLATE_NAME21,
520 STR_TEMPLATE_NAME22,
521 STR_TEMPLATE_NAME23,
522 STR_TEMPLATE_NAME24,
523 STR_TEMPLATE_NAME25,
524 STR_TEMPLATE_NAME26,
525 STR_TEMPLATE_NAME27,
526 STR_TEMPLATE_NAME28,
527 STR_TEMPLATE_NAME29,
528 STR_TEMPLATE_NAME30
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]);
538 return rString;
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
551 /* [Description]
553 Copy or move a document template
555 [Return value]
557 sal_Bool sal_True, Action could be performed
558 sal_False, Action could not be performed
560 [Cross-references]
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() )
579 return false;
581 // Don't copy or move any folders
582 if( nSourceIdx == USHRT_MAX )
583 return false ;
585 if ( nSourceRegion == nTargetRegion )
587 SAL_WARN( "sfx.doc", "Don't know, what to do!" );
588 return false;
591 RegionData_Impl *pSourceRgn = pImp->GetRegion( nSourceRegion );
592 if ( !pSourceRgn )
593 return false;
595 DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nSourceIdx );
596 if ( !pSource )
597 return false;
599 RegionData_Impl *pTargetRgn = pImp->GetRegion( nTargetRegion );
600 if ( !pTargetRgn )
601 return false;
603 const OUString aTitle = pSource->GetTitle();
605 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
607 if ( xTemplates->addTemplate( pTargetRgn->GetTitle(),
608 aTitle,
609 pSource->GetTargetURL() ) )
611 const OUString aNewTargetURL = GetTemplateTargetURLFromComponent( pTargetRgn->GetTitle(), aTitle );
612 if ( aNewTargetURL.isEmpty() )
613 return false;
615 if ( bMove )
617 // --**-- delete the original file
618 bool bDeleted = xTemplates->removeTemplate( pSourceRgn->GetTitle(),
619 pSource->GetTitle() );
620 if ( bDeleted )
621 pSourceRgn->DeleteEntry( nSourceIdx );
622 else
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 );
637 return true;
640 // --**-- if the current file is opened,
641 // it must be re-opened afterwards.
643 return false;
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 */
655 /* [Description]
657 Moving a template
659 [Return value]
661 sal_Bool sal_True, Action could be performed
662 sal_False, Action could not be performed
664 [Cross-references]
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 */
684 /* [Description]
686 Copying a template
688 [Return value]
690 sal_Bool sal_True, Action could be performed
691 sal_False, Action could not be performed
693 [Cross-references]
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
711 be created */
712 ) const
714 /* [Description]
716 Exporting a template into the file system
718 [Return value]
720 sal_Bool sal_True, Action could be performed
721 sal_False, Action could not be performed
723 [Cross-references]
725 <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
729 DocTemplLocker_Impl aLocker( *pImp );
731 if ( ! pImp->Construct() )
732 return false;
734 RegionData_Impl *pSourceRgn = pImp->GetRegion( nRegion );
735 if ( !pSourceRgn )
736 return false;
738 DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nIdx );
739 if ( !pSource )
740 return false;
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;
751 Content aTarget;
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& )
767 { return false; }
768 catch ( Exception& )
769 { return false; }
771 return true;
775 bool SfxDocumentTemplates::CopyFrom
777 sal_uInt16 nRegion, /* Region in which the template is to be
778 imported */
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
783 of the template */
786 /* [Description]
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
795 [Cross-references]
797 <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
801 DocTemplLocker_Impl aLocker( *pImp );
803 if ( ! pImp->Construct() )
804 return false;
806 RegionData_Impl *pTargetRgn = pImp->GetRegion( nRegion );
808 if ( !pTargetRgn )
809 return false;
811 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
812 if ( !xTemplates.is() )
813 return false;
815 OUString aTitle;
816 bool bTemplateAdded = false;
818 if( pImp->GetTitleFromURL( rName, aTitle ) )
820 bTemplateAdded = xTemplates->addTemplate( pTargetRgn->GetTitle(), aTitle, rName );
822 else
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;
835 xStorable.set(
836 xDesktop->loadComponentFromURL( aTemplURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
837 "_blank",
839 aArgs ),
840 UNO_QUERY );
842 xDocPropsSupplier.set( xStorable, UNO_QUERY );
844 catch( Exception& )
848 if( xStorable.is() )
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 );
863 aURL.CutExtension();
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 );
874 if( bTemplateAdded )
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;
883 Content aTemplCont;
885 if( Content::create( aTemplURL, aCmdEnv, comphelper::getProcessComponentContext(), aTemplCont ) )
887 OUString aTemplName;
888 if( getTextProperty_Impl( aTemplCont, TARGET_URL, aTemplName ) )
890 if ( nIdx == USHRT_MAX )
891 nIdx = 0;
892 else
893 ++nIdx;
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 );
898 rName = aTitle;
899 return true;
901 else
903 SAL_WARN( "sfx.doc", "CopyFrom(): The content should contain target URL!" );
906 else
908 SAL_WARN( "sfx.doc", "CopyFrom(): The content just was created!" );
912 return false;
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. */
923 /* [Description]
925 Deleting an entry or a directory
927 [Return value]
929 sal_Bool sal_True, Action could be performed
930 sal_False, Action could not be performed
932 [Cross-references]
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() )
946 return false;
948 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
950 if ( !pRegion )
951 return false;
953 bool bRet;
954 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
956 if ( nIdx == USHRT_MAX )
958 bRet = xTemplates->removeGroup( pRegion->GetTitle() );
959 if ( bRet )
960 pImp->DeleteRegion( nRegion );
962 else
964 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
966 if ( !pEntry )
967 return false;
969 bRet = xTemplates->removeTemplate( pRegion->GetTitle(),
970 pEntry->GetTitle() );
971 if( bRet )
972 pRegion->DeleteEntry( nIdx );
975 return bRet;
979 bool SfxDocumentTemplates::InsertDir
981 const OUString& rText, // the logical name of the new Region
982 sal_uInt16 nRegion // Region Index
985 /* [Description]
987 Insert an index
989 [Return value]
991 sal_Bool sal_True, Action could be performed
992 sal_False, Action could not be performed
994 [Cross-references]
996 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
999 DocTemplLocker_Impl aLocker( *pImp );
1001 if ( ! pImp->Construct() )
1002 return false;
1004 RegionData_Impl *pRegion = pImp->GetRegion( rText );
1006 if ( pRegion )
1007 return false;
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 );
1016 return false;
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() )
1024 return false;
1026 RegionData_Impl *pRegion = pImp->GetRegion( nSourceRegion );
1028 if ( !pRegion )
1029 return false;
1031 size_t pos = nIdx;
1032 pRegion->AddEntry( rName, rPath, &pos );
1034 return true;
1037 bool SfxDocumentTemplates::SetName( const OUString& rName, sal_uInt16 nRegion, sal_uInt16 nIdx )
1040 DocTemplLocker_Impl aLocker( *pImp );
1042 if ( ! pImp->Construct() )
1043 return false;
1045 RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
1047 if ( !pRegion )
1048 return false;
1050 uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
1052 if ( nIdx == USHRT_MAX )
1054 if ( pRegion->GetTitle() == rName )
1055 return true;
1057 // we have to rename a region
1058 if ( xTemplates->renameGroup( pRegion->GetTitle(), rName ) )
1060 pRegion->SetTitle( rName );
1061 pRegion->SetHierarchyURL( "" );
1062 return true;
1065 else
1067 DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
1069 if ( !pEntry )
1070 return false;
1072 if ( pEntry->GetTitle() == rName )
1073 return true;
1075 if ( xTemplates->renameTemplate( pRegion->GetTitle(),
1076 pEntry->GetTitle(),
1077 rName ) )
1079 pEntry->SetTitle( rName );
1080 pEntry->SetTargetURL( "" );
1081 pEntry->SetHierarchyURL( "" );
1082 return true;
1086 return false;
1090 bool SfxDocumentTemplates::GetFull
1092 const OUString &rRegion, // Region Name
1093 const OUString &rName, // Template Name
1094 OUString &rPath // Out: Path + File name
1097 /* [Description]
1099 Returns Path + File name of the template specified by rRegion and rName.
1101 [Return value]
1103 sal_Bool sal_True, Action could be performed
1104 sal_False, Action could not be performed
1106 [Cross-references]
1108 <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1112 DocTemplLocker_Impl aLocker( *pImp );
1114 // We don't search for empty names!
1115 if ( rName.isEmpty() )
1116 return false;
1118 if ( ! pImp->Construct() )
1119 return false;
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 );
1128 if( pRegion &&
1129 ( rRegion.isEmpty() || ( rRegion == pRegion->GetTitle() ) ) )
1131 pEntry = pRegion->GetEntry( rName );
1133 if ( pEntry )
1135 rPath = pEntry->GetTargetURL();
1136 break;
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
1150 ) const
1152 /* [Description]
1154 Returns and logical path name to the template specified by rPath
1156 [Return value]
1158 sal_Bool sal_True, Action could be performed
1159 sal_False, Action could not be performed
1161 [Cross-references]
1163 <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1167 DocTemplLocker_Impl aLocker( *pImp );
1169 if ( ! pImp->Construct() )
1170 return false;
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 );
1183 if ( pData )
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();
1194 return true;
1200 return false;
1204 SfxDocumentTemplates::SfxDocumentTemplates()
1206 /* [Description]
1208 Constructor
1211 if ( !gpTemplateData )
1212 gpTemplateData = new SfxDocTemplate_Impl;
1214 pImp = gpTemplateData;
1218 SfxDocumentTemplates::~SfxDocumentTemplates()
1220 /* [Description]
1222 Destructor
1223 Release of administrative data
1227 pImp = nullptr;
1230 void SfxDocumentTemplates::Update( )
1232 if ( ::svt::TemplateFolderCache( true ).needsUpdate() ) // update is really necessary
1234 if ( pImp->Construct() )
1235 pImp->Rescan();
1239 void SfxDocumentTemplates::ReInitFromComponent()
1241 pImp->ReInitFromComponent();
1244 DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl* pParent,
1245 const OUString& rTitle )
1247 mpParent = pParent;
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!" );
1272 return maOwnURL;
1276 const OUString& DocTempl_EntryData_Impl::GetTargetURL()
1278 if ( maTargetURL.isEmpty() )
1280 uno::Reference< XCommandEnvironment > aCmdEnv;
1281 Content aRegion;
1283 if ( Content::create( GetHierarchyURL(), aCmdEnv, comphelper::getProcessComponentContext(), aRegion ) )
1285 getTextProperty_Impl( aRegion, TARGET_URL, maTargetURL );
1287 else
1289 SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1293 return maTargetURL;
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 )
1314 rFound = true;
1315 return i;
1319 rFound = false;
1320 return nCount;
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 );
1337 if ( bFound )
1338 return;
1340 if ( pPos )
1341 nPos = *pPos;
1343 auto pEntry = std::make_unique<DocTempl_EntryData_Impl>(
1344 this, rTitle );
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) );
1352 else
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!" );
1377 return maOwnURL;
1381 DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( const OUString& rName ) const
1383 bool bFound = false;
1384 tools::Long nPos = GetEntryPos( rName, bFound );
1386 if ( bFound )
1387 return maEntries[ nPos ].get();
1388 return nullptr;
1392 DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( size_t nIndex ) const
1394 if ( nIndex < maEntries.size() )
1395 return maEntries[ nIndex ].get();
1396 return nullptr;
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 );
1433 mnLockCounter++;
1437 void SfxDocTemplate_Impl::DecrementLock()
1439 ::osl::MutexGuard aGuard( maMutex );
1440 if ( mnLockCounter )
1441 mnLockCounter--;
1445 RegionData_Impl* SfxDocTemplate_Impl::GetRegion( size_t nIndex ) const
1447 if ( nIndex < maRegions.size() )
1448 return maRegions[ nIndex ].get();
1449 return nullptr;
1453 RegionData_Impl* SfxDocTemplate_Impl::GetRegion( const OUString& rName )
1454 const
1456 for (auto& pData : maRegions)
1458 if( pData->GetTitle() == rName )
1459 return pData.get();
1461 return nullptr;
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,
1479 Content& rContent )
1481 auto pRegion = std::make_unique<RegionData_Impl>( this, rTitle );
1482 auto pRegionTmp = pRegion.get();
1484 if ( ! InsertRegion( std::move(pRegion), size_t(-1) ) )
1486 return;
1489 // now get the content of the region
1490 uno::Reference< XResultSet > xResultSet;
1491 Sequence< OUString > aProps(2);
1492 aProps[0] = TITLE;
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() )
1505 return;
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() )
1535 return;
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 )
1560 return true;
1562 uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1564 uno::Reference< XPersist > xInfo( document::DocumentProperties::create(xContext), UNO_QUERY );
1565 mxInfo = xInfo;
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() )
1577 return false;
1579 mbConstructed = true;
1580 maRootURL = aRootContent->getIdentifier()->getContentIdentifier();
1582 maStandardGroup = DocTemplLocaleHelper::GetStandardGroupString();
1583 Content aTemplRoot( aRootContent, aCmdEnv, xContext );
1584 CreateFromHierarchy( aTemplRoot );
1586 return true;
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() );
1598 Clear();
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 )
1611 return false;
1613 size_t newPos = nPos;
1614 if ( pNew->GetTitle() == maStandardGroup )
1615 newPos = 0;
1617 if ( newPos < maRegions.size() )
1619 auto it = maRegions.begin();
1620 std::advance( it, newPos );
1621 maRegions.emplace( it, std::move(pNew) );
1623 else
1624 maRegions.emplace_back( std::move(pNew) );
1626 return true;
1630 void SfxDocTemplate_Impl::Rescan()
1632 Clear();
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,
1657 OUString& aTitle )
1659 if ( mxInfo.is() )
1663 mxInfo->read( rURL );
1665 catch ( Exception& )
1667 // the document is not a StarOffice document
1668 return false;
1674 uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY );
1675 if ( aPropSet.is() )
1677 Any aValue = aPropSet->getPropertyValue( TITLE );
1678 aValue >>= aTitle;
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 );
1694 return true;
1698 void SfxDocTemplate_Impl::Clear()
1700 ::osl::MutexGuard aGuard( maMutex );
1701 if ( mnLockCounter )
1702 return;
1703 maRegions.clear();
1707 bool getTextProperty_Impl( Content& rContent,
1708 const OUString& rPropName,
1709 OUString& rPropValue )
1711 bool bGotProperty = false;
1713 // Get the property
1716 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1718 // check, whether or not the property exists
1719 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1721 return false;
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: */