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 <com/sun/star/uno/Any.h>
23 #include <osl/mutex.hxx>
24 #include <osl/thread.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
28 #include <unotools/localedatawrapper.hxx>
29 #include <unotools/pathoptions.hxx>
30 #include <tools/resary.hxx>
31 #include <tools/urlobj.hxx>
32 #include <svtools/ehdl.hxx>
33 #include <svtools/sfxecode.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <ucbhelper/content.hxx>
36 #include <com/sun/star/beans/PropertyAttribute.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/beans/XPropertyContainer.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/beans/XPropertySetInfo.hpp>
41 #include <com/sun/star/document/XTypeDetection.hpp>
42 #include <com/sun/star/document/DocumentProperties.hpp>
43 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
44 #include <com/sun/star/frame/Desktop.hpp>
45 #include <com/sun/star/frame/XComponentLoader.hpp>
46 #include <com/sun/star/frame/DocumentTemplates.hpp>
47 #include <com/sun/star/frame/XDocumentTemplates.hpp>
48 #include <com/sun/star/io/XInputStream.hpp>
49 #include <com/sun/star/io/XPersist.hpp>
50 #include <com/sun/star/lang/XLocalizable.hpp>
51 #include <com/sun/star/sdbc/XResultSet.hpp>
52 #include <com/sun/star/sdbc/XRow.hpp>
53 #include <com/sun/star/ucb/ContentInfo.hpp>
54 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
55 #include <com/sun/star/ucb/NameClash.hpp>
56 #include <com/sun/star/ucb/TransferInfo.hpp>
57 #include <com/sun/star/ucb/XCommandProcessor.hpp>
58 #include <com/sun/star/ucb/XContent.hpp>
59 #include <com/sun/star/ucb/XContentAccess.hpp>
60 #include <com/sun/star/ucb/AnyCompareFactory.hpp>
61 #include <com/sun/star/ucb/XAnyCompare.hpp>
62 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
63 #include <com/sun/star/embed/ElementModes.hpp>
64 #include <com/sun/star/embed/XTransactedObject.hpp>
66 #include "sfxurlrelocator.hxx"
68 using namespace ::com::sun::star
;
69 using namespace ::com::sun::star::beans
;
70 using namespace ::com::sun::star::frame
;
71 using namespace ::com::sun::star::io
;
72 using namespace ::com::sun::star::lang
;
73 using namespace ::com::sun::star::sdbc
;
74 using namespace ::com::sun::star::uno
;
75 using namespace ::com::sun::star::ucb
;
76 using namespace ::com::sun::star::document
;
77 using namespace ::rtl
;
78 using namespace ::ucbhelper
;
81 #include <sfx2/doctempl.hxx>
82 #include <sfx2/docfac.hxx>
83 #include <sfx2/docfile.hxx>
84 #include <sfx2/objsh.hxx>
85 #include "sfxtypes.hxx"
86 #include <sfx2/app.hxx>
87 #include <sfx2/sfxresid.hxx>
88 #include <sfx2/templatelocnames.hrc>
90 #include <sfx2/fcontnr.hxx>
91 #include <svtools/templatefoldercache.hxx>
93 #include <comphelper/storagehelper.hxx>
94 #include <unotools/ucbhelper.hxx>
102 #define TITLE "Title"
103 #define TARGET_URL "TargetURL"
105 #define COMMAND_TRANSFER "transfer"
109 class RegionData_Impl
;
113 class DocTempl_EntryData_Impl
115 RegionData_Impl
* mpParent
;
117 // the following member must be SfxObjectShellLock since it controls that SfxObjectShell lifetime by design
118 // and users of this class expect it to be so.
119 SfxObjectShellLock mxObjShell
;
123 OUString maTargetURL
;
125 bool mbDidConvert
: 1;
128 RegionData_Impl
* GetParent() const { return mpParent
; }
131 DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
132 const OUString
& rTitle
);
134 const OUString
& GetTitle() const { return maTitle
; }
135 const OUString
& GetTargetURL();
136 const OUString
& GetHierarchyURL();
138 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
139 void SetTargetURL( const OUString
& rURL
) { maTargetURL
= rURL
; }
140 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
142 int Compare( const OUString
& rTitle
) const;
147 using namespace ::DocTempl
;
151 class RegionData_Impl
153 const SfxDocTemplate_Impl
* mpParent
;
154 vector
< DocTempl_EntryData_Impl
* > maEntries
;
157 OUString maTargetURL
;
160 size_t GetEntryPos( const OUString
& rTitle
,
161 bool& rFound
) const;
162 const SfxDocTemplate_Impl
* GetParent() const { return mpParent
; }
165 RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
166 const OUString
& rTitle
);
169 void SetTargetURL( const OUString
& rURL
) { maTargetURL
= rURL
; }
170 void SetHierarchyURL( const OUString
& rURL
) { maOwnURL
= rURL
; }
172 DocTempl_EntryData_Impl
* GetEntry( size_t nIndex
) const;
173 DocTempl_EntryData_Impl
* GetEntry( const OUString
& rName
) const;
175 const OUString
& GetTitle() const { return maTitle
; }
176 const OUString
& GetHierarchyURL();
178 size_t GetCount() const;
180 void SetTitle( const OUString
& rTitle
) { maTitle
= rTitle
; }
182 void AddEntry( const OUString
& rTitle
,
183 const OUString
& rTargetURL
,
184 size_t *pPos
= NULL
);
185 void DeleteEntry( size_t nIndex
);
187 int Compare( RegionData_Impl
* pCompareWith
) const;
190 typedef vector
< RegionData_Impl
* > RegionList_Impl
;
194 class SfxDocTemplate_Impl
: public SvRefBase
196 uno::Reference
< XPersist
> mxInfo
;
197 uno::Reference
< XDocumentTemplates
> mxTemplates
;
199 ::osl::Mutex maMutex
;
201 OUString maStandardGroup
;
202 RegionList_Impl maRegions
;
205 uno::Reference
< XAnyCompareFactory
> m_rCompareFactory
;
207 // the following member is intended to prevent clearing of the global data when it is in use
208 // TODO/LATER: it still does not make the implementation complete thread-safe
209 sal_Int32 mnLockCounter
;
215 SfxDocTemplate_Impl();
216 virtual ~SfxDocTemplate_Impl();
218 void IncrementLock();
219 void DecrementLock();
222 void CreateFromHierarchy( Content
&rTemplRoot
);
223 void ReInitFromComponent();
224 void AddRegion( const OUString
& rTitle
,
229 void DeleteRegion( size_t nIndex
);
231 size_t GetRegionCount() const
232 { return maRegions
.size(); }
233 RegionData_Impl
* GetRegion( const OUString
& rName
) const;
234 RegionData_Impl
* GetRegion( size_t nIndex
) const;
236 bool GetTitleFromURL( const OUString
& rURL
, OUString
& aTitle
);
237 bool InsertRegion( RegionData_Impl
*pData
, size_t nPos
= size_t(-1) );
238 OUString
GetRootURL() const { return maRootURL
; }
240 uno::Reference
< XDocumentTemplates
> getDocTemplates() { return mxTemplates
; }
245 class DocTemplLocker_Impl
247 SfxDocTemplate_Impl
& m_aDocTempl
;
249 DocTemplLocker_Impl( SfxDocTemplate_Impl
& aDocTempl
)
250 : m_aDocTempl( aDocTempl
)
252 m_aDocTempl
.IncrementLock();
255 ~DocTemplLocker_Impl()
257 m_aDocTempl
.DecrementLock();
263 #ifndef SFX_DECL_DOCTEMPLATES_DEFINED
264 #define SFX_DECL_DOCTEMPLATES_DEFINED
265 typedef tools::SvRef
<SfxDocTemplate_Impl
> SfxDocTemplate_ImplRef
;
268 SfxDocTemplate_Impl
*gpTemplateData
= 0;
272 static bool getTextProperty_Impl( Content
& rContent
,
273 const OUString
& rPropName
,
274 OUString
& rPropValue
);
278 OUString
SfxDocumentTemplates::GetFullRegionName
280 sal_uInt16 nIdx
// vcl::Region Index
285 Returns the logical name of a region and its path
287 [Return value] Reference to the vcl::Region name
292 // First: find the RegionData for the index
295 DocTemplLocker_Impl
aLocker( *pImp
);
297 if ( pImp
->Construct() )
299 RegionData_Impl
*pData1
= pImp
->GetRegion( nIdx
);
302 aName
= pData1
->GetTitle();
304 // --**-- here was some code which appended the path to the
305 // group if there was more than one with the same name.
306 // this should not happen anymore
314 const OUString
& SfxDocumentTemplates::GetRegionName
316 sal_uInt16 nIdx
// vcl::Region Index
321 Returns the logical name of a region
325 const String& Reference to the vcl::Region name
329 static OUString maTmpString
;
331 DocTemplLocker_Impl
aLocker( *pImp
);
333 if ( pImp
->Construct() )
335 RegionData_Impl
*pData
= pImp
->GetRegion( nIdx
);
338 maTmpString
= pData
->GetTitle();
350 sal_uInt16
SfxDocumentTemplates::GetRegionCount() const
354 Returns the number of Regions
358 sal_uInt16 Number of Regions
361 DocTemplLocker_Impl
aLocker( *pImp
);
363 if ( !pImp
->Construct() )
366 sal_uIntPtr nCount
= pImp
->GetRegionCount();
368 return (sal_uInt16
) nCount
;
373 sal_uInt16
SfxDocumentTemplates::GetCount
375 sal_uInt16 nRegion
/* vcl::Region index whose number is
382 Number of entries in Region
384 [Return value] Number of entries
388 DocTemplLocker_Impl
aLocker( *pImp
);
390 if ( !pImp
->Construct() )
393 RegionData_Impl
*pData
= pImp
->GetRegion( nRegion
);
394 sal_uIntPtr nCount
= 0;
397 nCount
= pData
->GetCount();
399 return (sal_uInt16
) nCount
;
404 const OUString
& SfxDocumentTemplates::GetName
406 sal_uInt16 nRegion
, // vcl::Region Index, in which the entry lies
407 sal_uInt16 nIdx
// Index of the entry
412 Returns the logical name of an entry in Region
416 const String& Entry Name
420 DocTemplLocker_Impl
aLocker( *pImp
);
422 static OUString maTmpString
;
424 if ( pImp
->Construct() )
426 DocTempl_EntryData_Impl
*pEntry
= NULL
;
427 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
430 pEntry
= pRegion
->GetEntry( nIdx
);
433 maTmpString
= pEntry
->GetTitle();
445 OUString
SfxDocumentTemplates::GetPath
447 sal_uInt16 nRegion
, // vcl::Region Index, in which the entry lies
448 sal_uInt16 nIdx
// Index of the entry
453 Returns the file name with full path to the file assigned to an entry
457 String File name with full path
460 DocTemplLocker_Impl
aLocker( *pImp
);
462 if ( !pImp
->Construct() )
465 DocTempl_EntryData_Impl
*pEntry
= NULL
;
466 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
469 pEntry
= pRegion
->GetEntry( nIdx
);
472 return pEntry
->GetTargetURL();
479 OUString
SfxDocumentTemplates::GetTemplateTargetURLFromComponent( const OUString
& aGroupName
,
480 const OUString
& aTitle
)
482 DocTemplLocker_Impl
aLocker( *pImp
);
484 INetURLObject
aTemplateObj( pImp
->GetRootURL() );
486 aTemplateObj
.insertName( aGroupName
, false,
487 INetURLObject::LAST_SEGMENT
, true,
488 INetURLObject::ENCODE_ALL
);
490 aTemplateObj
.insertName( aTitle
, false,
491 INetURLObject::LAST_SEGMENT
, true,
492 INetURLObject::ENCODE_ALL
);
497 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
498 if ( Content::create( aTemplateObj
.GetMainURL( INetURLObject::NO_DECODE
), aCmdEnv
, comphelper::getProcessComponentContext(), aTemplate
) )
500 OUString
aPropName( TARGET_URL
);
501 getTextProperty_Impl( aTemplate
, aPropName
, aResult
);
502 aResult
= SvtPathOptions().SubstituteVariable( aResult
);
510 /** Convert a resource string - a template name - to its localised pair if it exists.
512 Resource ID where the list of original en-US template names begin.
514 Resource ID where the list of localised template names begin.
516 The number of names that have been localised.
518 Name to be translated.
520 The localised pair of rString or rString if the former does not exist.
522 OUString
SfxDocumentTemplates::ConvertResourceString (
523 int nSourceResIds
, int nDestResIds
, int nCount
, const OUString
& rString
)
525 for( int i
= 0; i
< nCount
; ++i
)
527 if( rString
== SFX2_RESSTR(nSourceResIds
+ i
))
528 return SFX2_RESSTR(nDestResIds
+ i
);
535 bool SfxDocumentTemplates::CopyOrMove
537 sal_uInt16 nTargetRegion
, // Target vcl::Region Index
538 sal_uInt16 nTargetIdx
, // Target position Index
539 sal_uInt16 nSourceRegion
, // Source vcl::Region Index
540 sal_uInt16 nSourceIdx
, /* Index to be copied / to moved template */
541 bool bMove
// Copy / Move
546 Copy or move a document template
550 sal_Bool sal_True, Action could be performed
551 sal_False, Action could not be performed
555 <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
556 <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
560 /* to perform a copy or move, we need to send a transfer command to
561 the destination folder with the URL of the source as parameter.
562 ( If the destination content doesn't support the transfer command,
563 we could try a copy ( and delete ) instead. )
564 We need two transfers ( one for the real template and one for its
565 representation in the hierarchy )
569 DocTemplLocker_Impl
aLocker( *pImp
);
571 if ( !pImp
->Construct() )
574 // Don't copy or move any folders
575 if( nSourceIdx
== USHRT_MAX
)
578 if ( nSourceRegion
== nTargetRegion
)
580 SAL_WARN( "sfx.doc", "Don't know, what to do!" );
584 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nSourceRegion
);
588 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nSourceIdx
);
592 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nTargetRegion
);
596 OUString aTitle
= pSource
->GetTitle();
598 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
600 if ( xTemplates
->addTemplate( pTargetRgn
->GetTitle(),
602 pSource
->GetTargetURL() ) )
604 OUString aNewTargetURL
= GetTemplateTargetURLFromComponent( pTargetRgn
->GetTitle(), aTitle
);
605 if ( aNewTargetURL
.isEmpty() )
610 // --**-- delete the original file
611 bool bDeleted
= xTemplates
->removeTemplate( pSourceRgn
->GetTitle(),
612 pSource
->GetTitle() );
614 pSourceRgn
->DeleteEntry( nSourceIdx
);
617 if ( xTemplates
->removeTemplate( pTargetRgn
->GetTitle(), aTitle
) )
618 return false; // will trigger tetry with copy instead of move
620 // if it is not possible to remove just created template ( must be possible! )
621 // it is better to report success here, since at least the copy has succeeded
622 // TODO/LATER: solve it more gracefully in future
626 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
627 size_t temp_nTargetIdx
= nTargetIdx
;
628 pTargetRgn
->AddEntry( aTitle
, aNewTargetURL
, &temp_nTargetIdx
);
633 // --**-- if the current file is opened,
634 // it must be re-opened afterwards.
641 bool SfxDocumentTemplates::Move
643 sal_uInt16 nTargetRegion
, // Target vcl::Region Index
644 sal_uInt16 nTargetIdx
, // Target position Index
645 sal_uInt16 nSourceRegion
, // Source vcl::Region Index
646 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
655 sal_Bool sal_True, Action could be performed
656 sal_False, Action could not be performed
660 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
663 DocTemplLocker_Impl
aLocker( *pImp
);
665 return CopyOrMove( nTargetRegion
, nTargetIdx
,
666 nSourceRegion
, nSourceIdx
, true );
671 bool SfxDocumentTemplates::Copy
673 sal_uInt16 nTargetRegion
, // Target vcl::Region Index
674 sal_uInt16 nTargetIdx
, // Target position Index
675 sal_uInt16 nSourceRegion
, // Source vcl::Region Index
676 sal_uInt16 nSourceIdx
/* Index to be copied / to moved template */
685 sal_Bool sal_True, Action could be performed
686 sal_False, Action could not be performed
690 <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
694 DocTemplLocker_Impl
aLocker( *pImp
);
696 return CopyOrMove( nTargetRegion
, nTargetIdx
,
697 nSourceRegion
, nSourceIdx
, false );
702 bool SfxDocumentTemplates::CopyTo
704 sal_uInt16 nRegion
, // vcl::Region of the template to be exported
705 sal_uInt16 nIdx
, // Index of the template to be exported
706 const OUString
& rName
/* File name under which the template is to
712 Exporting a template into the file system
716 sal_Bool sal_True, Action could be performed
717 sal_False, Action could not be performed
721 <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
725 DocTemplLocker_Impl
aLocker( *pImp
);
727 if ( ! pImp
->Construct() )
730 RegionData_Impl
*pSourceRgn
= pImp
->GetRegion( nRegion
);
734 DocTempl_EntryData_Impl
*pSource
= pSourceRgn
->GetEntry( nIdx
);
738 INetURLObject
aTargetURL( rName
);
740 OUString
aTitle( aTargetURL
.getName( INetURLObject::LAST_SEGMENT
, true,
741 INetURLObject::DECODE_WITH_CHARSET
) );
742 aTargetURL
.removeSegment();
744 OUString aParentURL
= aTargetURL
.GetMainURL( INetURLObject::NO_DECODE
);
746 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
751 aTarget
= Content( aParentURL
, aCmdEnv
, comphelper::getProcessComponentContext() );
753 TransferInfo aTransferInfo
;
754 aTransferInfo
.MoveData
= sal_False
;
755 aTransferInfo
.SourceURL
= pSource
->GetTargetURL();
756 aTransferInfo
.NewTitle
= aTitle
;
757 aTransferInfo
.NameClash
= NameClash::OVERWRITE
;
759 Any aArg
= makeAny( aTransferInfo
);
760 OUString
aCmd( COMMAND_TRANSFER
);
762 aTarget
.executeCommand( aCmd
, aArg
);
764 catch ( ContentCreationException
& )
774 bool SfxDocumentTemplates::CopyFrom
776 sal_uInt16 nRegion
, /* vcl::Region in which the template is to be
778 sal_uInt16 nIdx
, // Index of the new template in this Region
779 OUString
& rName
/* File name of the template to be imported
780 as an out parameter of the (automatically
781 generated from the file name) logical name
787 Import a template from the file system
789 [Return value] Success (sal_True) or serfpTargetDirectory->GetContent());
791 sal_Bool sal_True, Action could be performed
792 sal_False, Action could not be performed
796 <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
800 DocTemplLocker_Impl
aLocker( *pImp
);
802 if ( ! pImp
->Construct() )
805 RegionData_Impl
*pTargetRgn
= pImp
->GetRegion( nRegion
);
810 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
811 if ( !xTemplates
.is() )
815 bool bTemplateAdded
= false;
817 if( pImp
->GetTitleFromURL( rName
, aTitle
) )
819 bTemplateAdded
= xTemplates
->addTemplate( pTargetRgn
->GetTitle(), aTitle
, rName
);
823 uno::Reference
< XDesktop2
> xDesktop
= Desktop::create( ::comphelper::getProcessComponentContext() );;
825 Sequence
< PropertyValue
> aArgs( 1 );
826 aArgs
[0].Name
= "Hidden";
827 aArgs
[0].Value
<<= sal_True
;
829 INetURLObject
aTemplURL( rName
);
830 uno::Reference
< XDocumentPropertiesSupplier
> xDocPropsSupplier
;
831 uno::Reference
< XStorable
> xStorable
;
834 xStorable
= uno::Reference
< XStorable
>(
835 xDesktop
->loadComponentFromURL( aTemplURL
.GetMainURL(INetURLObject::NO_DECODE
),
841 xDocPropsSupplier
= uno::Reference
< XDocumentPropertiesSupplier
>(
842 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::DECODE_WITH_CHARSET
);
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
, true,
879 INetURLObject::ENCODE_ALL
);
880 OUString aTemplURL
= aTemplObj
.GetMainURL( INetURLObject::NO_DECODE
);
882 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
885 if( Content::create( aTemplURL
, aCmdEnv
, comphelper::getProcessComponentContext(), aTemplCont
) )
888 OUString
aPropName( TARGET_URL
);
890 if( getTextProperty_Impl( aTemplCont
, aPropName
, aTemplName
) )
892 if ( nIdx
== USHRT_MAX
)
897 // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
898 size_t temp_nIdx
= nIdx
;
899 pTargetRgn
->AddEntry( aTitle
, aTemplName
, &temp_nIdx
);
905 DBG_ASSERT( false, "CopyFrom(): The content should contain target URL!" );
910 DBG_ASSERT( false, "CopyFrom(): The content just was created!" );
919 bool SfxDocumentTemplates::Delete
921 sal_uInt16 nRegion
, // vcl::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
);
983 bool SfxDocumentTemplates::InsertDir
985 const OUString
& rText
, // the logical name of the new Region
986 sal_uInt16 nRegion
// vcl::Region Index
995 sal_Bool sal_True, Action could be performed
996 sal_False, Action could not be performed
1000 <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
1003 DocTemplLocker_Impl
aLocker( *pImp
);
1005 if ( ! pImp
->Construct() )
1008 RegionData_Impl
*pRegion
= pImp
->GetRegion( rText
);
1013 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1015 if ( xTemplates
->addGroup( rText
) )
1017 RegionData_Impl
* pNewRegion
= new RegionData_Impl( pImp
, rText
);
1019 if ( ! pImp
->InsertRegion( pNewRegion
, nRegion
) )
1030 bool SfxDocumentTemplates::InsertTemplate(sal_uInt16 nSourceRegion
, sal_uInt16 nIdx
, const OUString
&rName
, const OUString
&rPath
)
1032 DocTemplLocker_Impl
aLocker( *pImp
);
1034 if ( ! pImp
->Construct() )
1037 RegionData_Impl
*pRegion
= pImp
->GetRegion( nSourceRegion
);
1043 pRegion
->AddEntry( rName
, rPath
, &pos
);
1048 bool SfxDocumentTemplates::SetName( const OUString
& rName
, sal_uInt16 nRegion
, sal_uInt16 nIdx
)
1051 DocTemplLocker_Impl
aLocker( *pImp
);
1053 if ( ! pImp
->Construct() )
1056 RegionData_Impl
*pRegion
= pImp
->GetRegion( nRegion
);
1061 uno::Reference
< XDocumentTemplates
> xTemplates
= pImp
->getDocTemplates();
1064 if ( nIdx
== USHRT_MAX
)
1066 if ( pRegion
->GetTitle() == rName
)
1069 // we have to rename a region
1070 if ( xTemplates
->renameGroup( pRegion
->GetTitle(), rName
) )
1072 pRegion
->SetTitle( rName
);
1073 pRegion
->SetTargetURL( aEmpty
);
1074 pRegion
->SetHierarchyURL( aEmpty
);
1080 DocTempl_EntryData_Impl
*pEntry
= pRegion
->GetEntry( nIdx
);
1085 if ( pEntry
->GetTitle() == rName
)
1088 if ( xTemplates
->renameTemplate( pRegion
->GetTitle(),
1092 pEntry
->SetTitle( rName
);
1093 pEntry
->SetTargetURL( aEmpty
);
1094 pEntry
->SetHierarchyURL( aEmpty
);
1104 bool SfxDocumentTemplates::GetFull
1106 const OUString
&rRegion
, // vcl::Region Name
1107 const OUString
&rName
, // Template Name
1108 OUString
&rPath
// Out: Path + File name
1113 Returns Path + File name of the template specified by rRegion and rName.
1117 sal_Bool sal_True, Action could be performed
1118 sal_False, Action could not be performed
1122 <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1126 DocTemplLocker_Impl
aLocker( *pImp
);
1128 // We don't search for empty names!
1129 if ( rName
.isEmpty() )
1132 if ( ! pImp
->Construct() )
1135 DocTempl_EntryData_Impl
* pEntry
= NULL
;
1136 const sal_uInt16 nCount
= GetRegionCount();
1138 for ( sal_uInt16 i
= 0; i
< nCount
; ++i
)
1140 RegionData_Impl
*pRegion
= pImp
->GetRegion( i
);
1143 ( rRegion
.isEmpty() || ( rRegion
== pRegion
->GetTitle() ) ) )
1145 pEntry
= pRegion
->GetEntry( rName
);
1149 rPath
= pEntry
->GetTargetURL();
1155 return ( pEntry
!= NULL
);
1160 bool SfxDocumentTemplates::GetLogicNames
1162 const OUString
&rPath
, // Full Path to the template
1163 OUString
&rRegion
, // Out: vcl::Region name
1164 OUString
&rName
// Out: Template name
1169 Returns and logical path name to the template specified by rPath
1173 sal_Bool sal_True, Action could be performed
1174 sal_False, Action could not be performed
1178 <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1182 DocTemplLocker_Impl
aLocker( *pImp
);
1184 if ( ! pImp
->Construct() )
1187 INetURLObject aFullPath
;
1189 aFullPath
.SetSmartProtocol( INetProtocol::File
);
1190 aFullPath
.SetURL( rPath
);
1191 OUString
aPath( aFullPath
.GetMainURL( INetURLObject::NO_DECODE
) );
1193 RegionData_Impl
*pData
= NULL
;
1194 DocTempl_EntryData_Impl
*pEntry
= NULL
;
1195 bool bFound
= false;
1197 sal_uIntPtr nCount
= GetRegionCount();
1199 for ( sal_uIntPtr i
=0; !bFound
&& (i
<nCount
); i
++ )
1201 pData
= pImp
->GetRegion( i
);
1204 sal_uIntPtr nChildCount
= pData
->GetCount();
1206 for ( sal_uIntPtr j
=0; !bFound
&& (j
<nChildCount
); j
++ )
1208 pEntry
= pData
->GetEntry( j
);
1209 if ( pEntry
&& pEntry
->GetTargetURL() == aPath
)
1219 rRegion
= pData
->GetTitle();
1220 rName
= pEntry
->GetTitle();
1228 SfxDocumentTemplates::SfxDocumentTemplates()
1235 if ( !gpTemplateData
)
1236 gpTemplateData
= new SfxDocTemplate_Impl
;
1238 pImp
= gpTemplateData
;
1243 SfxDocumentTemplates::~SfxDocumentTemplates()
1248 Release of administrative data
1255 void SfxDocumentTemplates::Update( bool _bSmart
)
1257 if ( !_bSmart
// don't be smart
1258 || ::svt::TemplateFolderCache( true ).needsUpdate() // update is really necessary
1261 if ( pImp
->Construct() )
1266 void SfxDocumentTemplates::ReInitFromComponent()
1268 pImp
->ReInitFromComponent();
1272 DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl
* pParent
,
1273 const OUString
& rTitle
)
1276 maTitle
= SfxDocumentTemplates::ConvertResourceString(
1277 STR_TEMPLATE_NAME1_DEF
, STR_TEMPLATE_NAME1
, NUM_TEMPLATE_NAMES
, rTitle
);
1279 mbDidConvert
= false;
1283 int DocTempl_EntryData_Impl::Compare( const OUString
& rTitle
) const
1285 return maTitle
.compareTo( rTitle
);
1289 const OUString
& DocTempl_EntryData_Impl::GetHierarchyURL()
1291 if ( maOwnURL
.isEmpty() )
1293 INetURLObject
aTemplateObj( GetParent()->GetHierarchyURL() );
1295 aTemplateObj
.insertName( GetTitle(), false,
1296 INetURLObject::LAST_SEGMENT
, true,
1297 INetURLObject::ENCODE_ALL
);
1299 maOwnURL
= aTemplateObj
.GetMainURL( INetURLObject::NO_DECODE
);
1300 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1307 const OUString
& DocTempl_EntryData_Impl::GetTargetURL()
1309 if ( maTargetURL
.isEmpty() )
1311 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1314 if ( Content::create( GetHierarchyURL(), aCmdEnv
, comphelper::getProcessComponentContext(), aRegion
) )
1316 OUString
aPropName( TARGET_URL
);
1318 getTextProperty_Impl( aRegion
, aPropName
, maTargetURL
);
1322 SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1330 RegionData_Impl::RegionData_Impl( const SfxDocTemplate_Impl
* pParent
,
1331 const OUString
& rTitle
)
1338 RegionData_Impl::~RegionData_Impl()
1340 for ( size_t i
= 0, n
= maEntries
.size(); i
< n
; ++i
)
1341 delete maEntries
[ i
];
1346 size_t RegionData_Impl::GetEntryPos( const OUString
& rTitle
, bool& rFound
) const
1348 #if 1 // Don't use binary search today
1350 size_t nCount
= maEntries
.size();
1352 for ( i
=0; i
<nCount
; i
++ )
1354 DocTempl_EntryData_Impl
*pData
= maEntries
[ i
];
1356 if ( pData
->Compare( rTitle
) == 0 )
1367 // use binary search to find the correct position
1368 // in the maEntries list
1372 size_t nEnd
= maEntries
.size() - 1;
1375 DocTempl_EntryData_Impl
* pMid
;
1379 while ( nCompVal
&& ( nStart
<= nEnd
) )
1381 nMid
= ( nEnd
- nStart
) / 2 + nStart
;
1382 pMid
= maEntries
[ nMid
];
1384 nCompVal
= pMid
->Compare( rTitle
);
1386 if ( nCompVal
< 0 ) // pMid < pData
1392 if ( nCompVal
== 0 )
1398 if ( nCompVal
< 0 ) // pMid < pData
1407 void RegionData_Impl::AddEntry( const OUString
& rTitle
,
1408 const OUString
& rTargetURL
,
1411 INetURLObject
aLinkObj( GetHierarchyURL() );
1412 aLinkObj
.insertName( rTitle
, false,
1413 INetURLObject::LAST_SEGMENT
, true,
1414 INetURLObject::ENCODE_ALL
);
1415 OUString aLinkURL
= aLinkObj
.GetMainURL( INetURLObject::NO_DECODE
);
1417 DocTempl_EntryData_Impl
* pEntry
;
1418 bool bFound
= false;
1419 size_t nPos
= GetEntryPos( rTitle
, bFound
);
1423 pEntry
= maEntries
[ nPos
];
1430 pEntry
= new DocTempl_EntryData_Impl( this, rTitle
);
1431 pEntry
->SetTargetURL( rTargetURL
);
1432 pEntry
->SetHierarchyURL( aLinkURL
);
1433 if ( nPos
< maEntries
.size() ) {
1434 vector
< DocTempl_EntryData_Impl
* >::iterator it
= maEntries
.begin();
1435 advance( it
, nPos
);
1436 maEntries
.insert( it
, pEntry
);
1439 maEntries
.push_back( pEntry
);
1444 size_t RegionData_Impl::GetCount() const
1446 return maEntries
.size();
1450 const OUString
& RegionData_Impl::GetHierarchyURL()
1452 if ( maOwnURL
.isEmpty() )
1454 INetURLObject
aRegionObj( GetParent()->GetRootURL() );
1456 aRegionObj
.insertName( GetTitle(), false,
1457 INetURLObject::LAST_SEGMENT
, true,
1458 INetURLObject::ENCODE_ALL
);
1460 maOwnURL
= aRegionObj
.GetMainURL( INetURLObject::NO_DECODE
);
1461 DBG_ASSERT( !maOwnURL
.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1468 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( const OUString
& rName
) const
1470 bool bFound
= false;
1471 long nPos
= GetEntryPos( rName
, bFound
);
1474 return maEntries
[ nPos
];
1480 DocTempl_EntryData_Impl
* RegionData_Impl::GetEntry( size_t nIndex
) const
1482 if ( nIndex
< maEntries
.size() )
1483 return maEntries
[ nIndex
];
1488 void RegionData_Impl::DeleteEntry( size_t nIndex
)
1490 if ( nIndex
< maEntries
.size() )
1492 delete maEntries
[ nIndex
];
1493 vector
< DocTempl_EntryData_Impl
*>::iterator it
= maEntries
.begin();
1494 advance( it
, nIndex
);
1495 maEntries
.erase( it
);
1500 int RegionData_Impl::Compare( RegionData_Impl
* pCompare
) const
1502 int nCompare
= maTitle
.compareTo( pCompare
->maTitle
);
1509 SfxDocTemplate_Impl::SfxDocTemplate_Impl()
1510 : mbConstructed( false )
1511 , mnLockCounter( 0 )
1516 SfxDocTemplate_Impl::~SfxDocTemplate_Impl()
1520 gpTemplateData
= NULL
;
1524 void SfxDocTemplate_Impl::IncrementLock()
1526 ::osl::MutexGuard
aGuard( maMutex
);
1531 void SfxDocTemplate_Impl::DecrementLock()
1533 ::osl::MutexGuard
aGuard( maMutex
);
1534 if ( mnLockCounter
)
1539 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( size_t nIndex
) const
1541 if ( nIndex
< maRegions
.size() )
1542 return maRegions
[ nIndex
];
1547 RegionData_Impl
* SfxDocTemplate_Impl::GetRegion( const OUString
& rName
)
1550 for ( size_t i
= 0, n
= maRegions
.size(); i
< n
; ++i
)
1552 RegionData_Impl
* pData
= maRegions
[ i
];
1553 if( pData
->GetTitle() == rName
)
1560 void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex
)
1562 if ( nIndex
< maRegions
.size() )
1564 delete maRegions
[ nIndex
];
1565 RegionList_Impl::iterator it
= maRegions
.begin();
1566 advance( it
, nIndex
);
1567 maRegions
.erase( it
);
1572 /* AddRegion adds a vcl::Region to the RegionList
1574 void SfxDocTemplate_Impl::AddRegion( const OUString
& rTitle
,
1577 RegionData_Impl
* pRegion
;
1578 pRegion
= new RegionData_Impl( this, rTitle
);
1580 if ( ! InsertRegion( pRegion
) )
1586 // now get the content of the region
1587 uno::Reference
< XResultSet
> xResultSet
;
1588 Sequence
< OUString
> aProps(2);
1590 aProps
[1] = TARGET_URL
;
1594 ResultSetInclude eInclude
= INCLUDE_DOCUMENTS_ONLY
;
1595 Sequence
< NumberedSortingInfo
> aSortingInfo(1);
1596 aSortingInfo
.getArray()->ColumnIndex
= 1;
1597 aSortingInfo
.getArray()->Ascending
= sal_True
;
1598 xResultSet
= rContent
.createSortedCursor( aProps
, aSortingInfo
, m_rCompareFactory
, eInclude
);
1600 catch ( Exception
& ) {}
1602 if ( xResultSet
.is() )
1604 uno::Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1605 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1609 while ( xResultSet
->next() )
1611 OUString
aTitle( xRow
->getString( 1 ) );
1612 OUString
aTargetDir( xRow
->getString( 2 ) );
1614 pRegion
->AddEntry( aTitle
, aTargetDir
);
1617 catch ( Exception
& ) {}
1622 void SfxDocTemplate_Impl::CreateFromHierarchy( Content
&rTemplRoot
)
1624 uno::Reference
< XResultSet
> xResultSet
;
1625 Sequence
< OUString
> aProps(1);
1630 ResultSetInclude eInclude
= INCLUDE_FOLDERS_ONLY
;
1631 Sequence
< NumberedSortingInfo
> aSortingInfo(1);
1632 aSortingInfo
.getArray()->ColumnIndex
= 1;
1633 aSortingInfo
.getArray()->Ascending
= sal_True
;
1634 xResultSet
= rTemplRoot
.createSortedCursor( aProps
, aSortingInfo
, m_rCompareFactory
, eInclude
);
1636 catch ( Exception
& ) {}
1638 if ( xResultSet
.is() )
1640 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1641 uno::Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1642 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1646 while ( xResultSet
->next() )
1648 OUString
aTitle( xRow
->getString( 1 ) );
1650 OUString aId
= xContentAccess
->queryContentIdentifierString();
1651 Content aContent
= Content( aId
, aCmdEnv
, comphelper::getProcessComponentContext() );
1653 AddRegion( aTitle
, aContent
);
1656 catch ( Exception
& ) {}
1661 bool SfxDocTemplate_Impl::Construct( )
1663 ::osl::MutexGuard
aGuard( maMutex
);
1665 if ( mbConstructed
)
1668 uno::Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1670 uno::Reference
< XPersist
> xInfo( document::DocumentProperties::create(xContext
), UNO_QUERY
);
1673 mxTemplates
= frame::DocumentTemplates::create(xContext
);
1675 uno::Reference
< XLocalizable
> xLocalizable( mxTemplates
, UNO_QUERY
);
1677 m_rCompareFactory
= AnyCompareFactory::createWithLocale(xContext
, xLocalizable
->getLocale());
1679 uno::Reference
< XContent
> aRootContent
= mxTemplates
->getContent();
1680 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1682 if ( ! aRootContent
.is() )
1685 mbConstructed
= true;
1686 maRootURL
= aRootContent
->getIdentifier()->getContentIdentifier();
1688 ResStringArray
aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY
) );
1690 if ( aLongNames
.Count() )
1691 maStandardGroup
= aLongNames
.GetString( 0 );
1693 Content
aTemplRoot( aRootContent
, aCmdEnv
, xContext
);
1694 CreateFromHierarchy( aTemplRoot
);
1700 void SfxDocTemplate_Impl::ReInitFromComponent()
1702 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1703 if ( xTemplates
.is() )
1705 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1706 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1707 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1709 CreateFromHierarchy( aTemplRoot
);
1714 bool SfxDocTemplate_Impl::InsertRegion( RegionData_Impl
*pNew
, size_t nPos
)
1716 ::osl::MutexGuard
aGuard( maMutex
);
1718 // return false (not inserted) if the entry already exists
1719 for ( size_t i
= 0, n
= maRegions
.size(); i
< n
; ++i
)
1720 if ( maRegions
[ i
]->Compare( pNew
) == 0 )
1723 size_t newPos
= nPos
;
1724 if ( pNew
->GetTitle() == maStandardGroup
)
1727 if ( newPos
< maRegions
.size() )
1729 RegionList_Impl::iterator it
= maRegions
.begin();
1730 advance( it
, newPos
);
1731 maRegions
.insert( it
, pNew
);
1734 maRegions
.push_back( pNew
);
1740 void SfxDocTemplate_Impl::Rescan()
1746 uno::Reference
< XDocumentTemplates
> xTemplates
= getDocTemplates();
1747 DBG_ASSERT( xTemplates
.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" );
1748 if ( xTemplates
.is() )
1750 xTemplates
->update();
1752 uno::Reference
< XContent
> aRootContent
= xTemplates
->getContent();
1753 uno::Reference
< XCommandEnvironment
> aCmdEnv
;
1755 Content
aTemplRoot( aRootContent
, aCmdEnv
, comphelper::getProcessComponentContext() );
1756 CreateFromHierarchy( aTemplRoot
);
1759 catch( const Exception
& )
1761 SAL_WARN( "sfx.doc", "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update!" );
1766 bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString
& rURL
,
1773 mxInfo
->read( rURL
);
1775 catch ( Exception
& )
1777 // the document is not a StarOffice document
1784 uno::Reference
< XPropertySet
> aPropSet( mxInfo
, UNO_QUERY
);
1785 if ( aPropSet
.is() )
1787 OUString
aPropName( TITLE
);
1788 Any aValue
= aPropSet
->getPropertyValue( aPropName
);
1792 catch ( IOException
& ) {}
1793 catch ( UnknownPropertyException
& ) {}
1794 catch ( Exception
& ) {}
1797 if ( aTitle
.isEmpty() )
1799 INetURLObject
aURL( rURL
);
1800 aURL
.CutExtension();
1801 aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true,
1802 INetURLObject::DECODE_WITH_CHARSET
);
1810 void SfxDocTemplate_Impl::Clear()
1812 ::osl::MutexGuard
aGuard( maMutex
);
1813 if ( mnLockCounter
)
1816 for ( size_t i
= 0, n
= maRegions
.size(); i
< n
; ++i
)
1817 delete maRegions
[ i
];
1822 bool getTextProperty_Impl( Content
& rContent
,
1823 const OUString
& rPropName
,
1824 OUString
& rPropValue
)
1826 bool bGotProperty
= false;
1831 uno::Reference
< XPropertySetInfo
> aPropInfo
= rContent
.getProperties();
1833 // check, whether or not the property exists
1834 if ( !aPropInfo
.is() || !aPropInfo
->hasPropertyByName( rPropName
) )
1839 // now get the property
1842 aAnyValue
= rContent
.getPropertyValue( rPropName
);
1843 aAnyValue
>>= rPropValue
;
1845 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName
) )
1847 SfxURLRelocator_Impl
aRelocImpl( ::comphelper::getProcessComponentContext() );
1848 aRelocImpl
.makeAbsoluteURL( rPropValue
);
1851 bGotProperty
= true;
1853 catch ( RuntimeException
& ) {}
1854 catch ( Exception
& ) {}
1856 return bGotProperty
;
1859 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */