xref: /aoo41x/main/sfx2/source/doc/doctemplates.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #include "doctemplates.hxx"
32 #include <vos/mutex.hxx>
33 #include <tools/debug.hxx>
34 #include <tools/diagnose_ex.h>
35 #include <tools/urlobj.hxx>
36 #include <rtl/ustring.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #ifndef _SV_RESARY_HXX
39 #include <tools/resary.hxx>
40 #endif
41 #include <vcl/svapp.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <comphelper/sequenceashashmap.hxx>
44 #include <unotools/pathoptions.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/componentcontext.hxx>
47 #include <com/sun/star/beans/PropertyAttribute.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/beans/XPropertySetInfo.hpp>
50 #include <com/sun/star/beans/XPropertyContainer.hpp>
51 #include <com/sun/star/beans/StringPair.hpp>
52 #include <com/sun/star/container/XContainerQuery.hpp>
53 #include <com/sun/star/document/XTypeDetection.hpp>
54 #include <com/sun/star/document/XStandaloneDocumentInfo.hpp>
55 #include <com/sun/star/sdbc/XResultSet.hpp>
56 #include <com/sun/star/sdbc/XRow.hpp>
57 #include <com/sun/star/ucb/NameClash.hpp>
58 #include <com/sun/star/ucb/NameClashException.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
61 #include <com/sun/star/ucb/XContentAccess.hpp>
62 #include <com/sun/star/frame/XModuleManager.hpp>
63 #include <com/sun/star/uno/Exception.hpp>
64 
65 #include <svtools/templatefoldercache.hxx>
66 #include <unotools/configmgr.hxx>
67 #include <unotools/ucbhelper.hxx>
68 
69 #include "sfx2/sfxresid.hxx"
70 #include "sfxurlrelocator.hxx"
71 #include "doctemplateslocal.hxx"
72 #include <sfx2/docfac.hxx>
73 #include <sfx2/docfile.hxx>
74 #include "doc.hrc"
75 
76 //-----------------------------------------------------------------------------
77 
78 //=============================================================================
79 
80 #define TEMPLATE_SERVICE_NAME				"com.sun.star.frame.DocumentTemplates"
81 #define TEMPLATE_IMPLEMENTATION_NAME		"com.sun.star.comp.sfx2.DocumentTemplates"
82 
83 #define SERVICENAME_TYPEDETECTION			"com.sun.star.document.TypeDetection"
84 #define SERVICENAME_DOCINFO					"com.sun.star.document.StandaloneDocumentInfo"
85 
86 #define TEMPLATE_ROOT_URL		"vnd.sun.star.hier:/templates"
87 #define TITLE					"Title"
88 #define IS_FOLDER				"IsFolder"
89 #define IS_DOCUMENT				"IsDocument"
90 #define TARGET_URL				"TargetURL"
91 #define TEMPLATE_VERSION		"TemplateComponentVersion"
92 #define TEMPLATE_VERSION_VALUE	"2"
93 #define TYPE_FOLDER				"application/vnd.sun.star.hier-folder"
94 #define TYPE_LINK				"application/vnd.sun.star.hier-link"
95 #define TYPE_FSYS_FOLDER		"application/vnd.sun.staroffice.fsys-folder"
96 #define TYPE_FSYS_FILE			"application/vnd.sun.staroffice.fsys-file"
97 
98 #define PROPERTY_DIRLIST		"DirectoryList"
99 #define PROPERTY_NEEDSUPDATE	"NeedsUpdate"
100 #define PROPERTY_TYPE			"TypeDescription"
101 
102 #define TARGET_DIR_URL			"TargetDirURL"
103 #define COMMAND_DELETE			"delete"
104 #define COMMAND_TRANSFER		"transfer"
105 
106 #define STANDARD_FOLDER			"standard"
107 
108 #define	C_DELIM					';'
109 
110 //=============================================================================
111 
112 using namespace ::com::sun::star;
113 using namespace ::com::sun::star::beans;
114 using namespace ::com::sun::star::document;
115 using namespace ::com::sun::star::io;
116 using namespace ::com::sun::star::lang;
117 using namespace ::com::sun::star::sdbc;
118 using namespace ::com::sun::star::ucb;
119 using namespace ::com::sun::star::uno;
120 using namespace ::com::sun::star::container;
121 using namespace ::com::sun::star::util;
122 
123 using namespace ::rtl;
124 using namespace ::ucbhelper;
125 using namespace ::comphelper;
126 
127 //=============================================================================
128 
129 class WaitWindow_Impl : public WorkWindow
130 {
131     Rectangle   _aRect;
132     sal_uInt16      _nTextStyle;
133     String      _aText;
134 
135     public:
136                      WaitWindow_Impl();
137                     ~WaitWindow_Impl();
138     virtual void     Paint( const Rectangle& rRect );
139 };
140 
141 #define X_OFFSET 15
142 #define Y_OFFSET 15
143 
144 //=============================================================================
145 
146 struct NamePair_Impl
147 {
148     OUString maShortName;
149     OUString maLongName;
150 };
151 
152 DECLARE_LIST( NameList_Impl, NamePair_Impl* )
153 
154 class Updater_Impl;
155 class GroupList_Impl;
156 class DocTemplates_EntryData_Impl;
157 class GroupData_Impl;
158 
159 //=============================================================================
160 #include <com/sun/star/task/XInteractionHandler.hpp>
161 #include <com/sun/star/ucb/XProgressHandler.hpp>
162 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
163 
164 class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment >
165 {
166 	uno::Reference< task::XInteractionHandler >               m_xInteractionHandler;
167 	uno::Reference< ucb::XProgressHandler >                   m_xProgressHandler;
168 
169 public:
170 	TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler )
171                                 : m_xInteractionHandler( rxInteractionHandler )
172                             {}
173 
174 	virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException)
175 	{ return m_xInteractionHandler; }
176 
177 	virtual uno::Reference<ucb::XProgressHandler> SAL_CALL    getProgressHandler() throw (uno::RuntimeException)
178 	{ return m_xProgressHandler; }
179 };
180 
181 class SfxDocTplService_Impl
182 {
183     uno::Reference< XMultiServiceFactory >           mxFactory;
184     uno::Reference< XCommandEnvironment >            maCmdEnv;
185     uno::Reference< XStandaloneDocumentInfo >        mxInfo;
186     uno::Reference< XTypeDetection >                 mxType;
187 
188 	::osl::Mutex				maMutex;
189 	Sequence< OUString >		maTemplateDirs;
190 	OUString					maRootURL;
191 	NameList_Impl				maNames;
192 	Locale						maLocale;
193 	Content						maRootContent;
194 	Updater_Impl*				mpUpdater;
195 	sal_Bool					mbIsInitialized : 1;
196 	sal_Bool					mbLocaleSet		: 1;
197 
198 	SfxURLRelocator_Impl		maRelocator;
199 
200 	void						init_Impl();
201 	void						getDefaultLocale();
202 	void						getDirList();
203 	void						readFolderList();
204     sal_Bool                    needsUpdate();
205 	OUString					getLongName( const OUString& rShortName );
206 	sal_Bool					setTitleForURL( const OUString& rURL, const OUString& aTitle );
207 	sal_Bool					getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle );
208 
209 	sal_Bool					addEntry( Content& rParentFolder,
210                                           const OUString& rTitle,
211                                           const OUString& rTargetURL,
212                                           const OUString& rType );
213 
214     sal_Bool                    createFolder( const OUString& rNewFolderURL,
215                                               sal_Bool  bCreateParent,
216                                               sal_Bool  bFsysFolder,
217                                               Content   &rNewFolder );
218 
219 	sal_Bool					CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath,
220 																const ::rtl::OUString& aPrefix,
221 																::rtl::OUString& aNewFolderName,
222 																::rtl::OUString& aNewFolderURL,
223 																Content& aNewFolder );
224 	::rtl::OUString				CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath,
225 																const ::rtl::OUString& aPrefix,
226 																const ::rtl::OUString& aExt );
227 
228 	uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath );
229 	sal_Bool					UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
230 																  const ::rtl::OUString& aGroupName,
231 																  const ::rtl::OUString& aNewFolderName );
232 	sal_Bool					ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
233 																  const ::rtl::OUString& aFsysGroupName,
234 																  const ::rtl::OUString& aOldGroupName,
235 																  const ::rtl::OUString& aNewGroupName );
236 	sal_Bool					RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
237 																  const ::rtl::OUString& aGroupName );
238 	sal_Bool					WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
239 																const uno::Sequence< beans::StringPair >& aUINames );
240 
241 	::rtl::OUString				CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup );
242 
243     sal_Bool                    removeContent( Content& rContent );
244     sal_Bool                    removeContent( const OUString& rContentURL );
245 
246     sal_Bool                    setProperty( Content& rContent,
247                                              const OUString& rPropName,
248                                              const Any& rPropValue );
249     sal_Bool                    getProperty( Content& rContent,
250                                              const OUString& rPropName,
251                                              Any& rPropValue );
252 
253     void                        createFromContent( GroupList_Impl& rList,
254                                                    Content &rContent,
255                                                    sal_Bool bHierarchy,
256 												   sal_Bool bWriteableContent = sal_False );
257     void                        addHierGroup( GroupList_Impl& rList,
258                                               const OUString& rTitle,
259                                               const OUString& rOwnURL );
260     void                        addFsysGroup( GroupList_Impl& rList,
261                                               const OUString& rTitle,
262 											  const OUString& rUITitle,
263                                               const OUString& rOwnURL,
264 											  sal_Bool bWriteableGroup = sal_False );
265     void                        removeFromHierarchy( DocTemplates_EntryData_Impl *pData );
266     void                        addToHierarchy( GroupData_Impl *pGroup,
267                                                 DocTemplates_EntryData_Impl *pData );
268 
269     void                        removeFromHierarchy( GroupData_Impl *pGroup );
270     void                        addGroupToHierarchy( GroupData_Impl *pGroup );
271 
272     void                        updateData( DocTemplates_EntryData_Impl *pData );
273 
274 public:
275                                  SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory );
276                                 ~SfxDocTplService_Impl();
277 
278     sal_Bool                    init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; }
279     Content                     getContent() { return maRootContent; }
280 
281     void                        setLocale( const Locale & rLocale );
282     Locale                      getLocale();
283 
284 	sal_Bool 					storeTemplate( const OUString& rGroupName,
285                                                const OUString& rTemplateName,
286                                                const uno::Reference< XSTORABLE >& rStorable );
287 
288     sal_Bool                    addTemplate( const OUString& rGroupName,
289                                              const OUString& rTemplateName,
290                                              const OUString& rSourceURL );
291     sal_Bool                    removeTemplate( const OUString& rGroupName,
292                                                 const OUString& rTemplateName );
293     sal_Bool                    renameTemplate( const OUString& rGroupName,
294                                                 const OUString& rOldName,
295                                                 const OUString& rNewName );
296 
297     sal_Bool                    addGroup( const OUString& rGroupName );
298     sal_Bool                    removeGroup( const OUString& rGroupName );
299     sal_Bool                    renameGroup( const OUString& rOldName,
300                                              const OUString& rNewName );
301 
302     void                        update( sal_Bool bUpdateNow );
303     void                        doUpdate();
304     void                        finished() { mpUpdater = NULL; }
305 };
306 
307 //=============================================================================
308 
309 class Updater_Impl : public ::vos::OThread
310 {
311 private:
312     SfxDocTplService_Impl   *mpDocTemplates;
313 
314 public:
315                              Updater_Impl( SfxDocTplService_Impl* pTemplates );
316                             ~Updater_Impl();
317 
318     virtual void SAL_CALL   run();
319     virtual void SAL_CALL   onTerminated();
320 };
321 
322 //=============================================================================
323 
324 class DocTemplates_EntryData_Impl
325 {
326     OUString            maTitle;
327     OUString            maType;
328     OUString            maTargetURL;
329     OUString            maHierarchyURL;
330 
331     sal_Bool            mbInHierarchy   : 1;
332     sal_Bool            mbInUse         : 1;
333     sal_Bool            mbUpdateType    : 1;
334     sal_Bool            mbUpdateLink    : 1;
335 
336 public:
337                         DocTemplates_EntryData_Impl( const OUString& rTitle );
338 
339     void                setInUse() { mbInUse = sal_True; }
340     void                setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
341     void                setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; }
342     void                setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; }
343 
344     sal_Bool            getInUse() const { return mbInUse; }
345     sal_Bool            getInHierarchy() const { return mbInHierarchy; }
346     sal_Bool            getUpdateLink() const { return mbUpdateLink; }
347     sal_Bool            getUpdateType() const { return mbUpdateType; }
348 
349     const OUString&     getHierarchyURL() const { return maHierarchyURL; }
350     const OUString&     getTargetURL() const { return maTargetURL; }
351     const OUString&     getTitle() const { return maTitle; }
352     const OUString&     getType() const { return maType; }
353 
354     void                setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
355     void                setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
356     void                setType( const OUString& rType ) { maType = rType; }
357 };
358 
359 //=============================================================================
360 
361 class GroupData_Impl
362 {
363     DECLARE_LIST( EntryList_Impl, DocTemplates_EntryData_Impl* )
364     EntryList_Impl      maEntries;
365     OUString            maTitle;
366     OUString            maHierarchyURL;
367     OUString            maTargetURL;
368     sal_Bool            mbInUse         : 1;
369     sal_Bool            mbInHierarchy   : 1;
370 
371 public:
372                         GroupData_Impl( const OUString& rTitle );
373                         ~GroupData_Impl();
374 
375     void                setInUse() { mbInUse = sal_True; }
376     void                setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
377     void                setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
378     void                setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
379 
380     sal_Bool            getInUse() { return mbInUse; }
381     sal_Bool            getInHierarchy() { return mbInHierarchy; }
382     const OUString&     getHierarchyURL() const { return maHierarchyURL; }
383     const OUString&     getTargetURL() const { return maTargetURL; }
384     const OUString&     getTitle() const { return maTitle; }
385 
386     DocTemplates_EntryData_Impl*     addEntry( const OUString& rTitle,
387                                   const OUString& rTargetURL,
388                                   const OUString& rType,
389                                   const OUString& rHierURL );
390     sal_uIntPtr               count() { return maEntries.Count(); }
391     DocTemplates_EntryData_Impl*     getEntry( sal_uIntPtr nPos ) { return maEntries.GetObject( nPos ); }
392 };
393 
394 DECLARE_LIST( GroupList_Impl, GroupData_Impl* )
395 
396 //=============================================================================
397 //=============================================================================
398 //=============================================================================
399 
400 //-----------------------------------------------------------------------------
401 // private SfxDocTplService_Impl
402 //-----------------------------------------------------------------------------
403 void SfxDocTplService_Impl::init_Impl()
404 {
405     uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
406     if ( xFactory.is() )
407     {
408 		uno::Reference < task::XInteractionHandler > xInteractionHandler( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY );
409 		maCmdEnv = new TplTaskEnvironment( xInteractionHandler );
410 	}
411 
412     ::osl::ClearableMutexGuard aGuard( maMutex );
413 	sal_Bool bIsInitialized = sal_False;
414 	sal_Bool bNeedsUpdate   = sal_False;
415 
416     if ( !mbLocaleSet )
417         getDefaultLocale();
418 
419     // convert locale to string
420     OUString aLang = maLocale.Language;
421     aLang += String( '-' );
422     aLang += maLocale.Country;
423 
424     // set maRootContent to the root of the templates hierarchy. Create the
425     // entry if necessary
426 
427     maRootURL = OUString( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_ROOT_URL ) );
428     maRootURL += String( '/' );
429     maRootURL += aLang;
430 
431 	::rtl::OUString aTemplVersPropName( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION ) );
432 	::rtl::OUString aTemplVers( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION_VALUE ) );
433     if ( Content::create( maRootURL, maCmdEnv, maRootContent ) )
434 	{
435 		uno::Any aValue;
436 		::rtl::OUString aPropValue;
437 		if ( getProperty( maRootContent, aTemplVersPropName, aValue )
438 		  && ( aValue >>= aPropValue )
439 		  && aPropValue.equals( aTemplVers ) )
440 		{
441 			bIsInitialized = sal_True;
442 		}
443 		else
444 			removeContent( maRootContent );
445 	}
446 
447 	if ( !bIsInitialized )
448     {
449 		if ( createFolder( maRootURL, sal_True, sal_False, maRootContent )
450 		  && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) )
451 			bIsInitialized = sal_True;
452 
453         bNeedsUpdate = sal_True;
454     }
455 
456 	if ( bIsInitialized )
457     {
458         OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCINFO ) );
459         try {
460             mxInfo = uno::Reference< XStandaloneDocumentInfo > (
461                 mxFactory->createInstance( aService ), UNO_QUERY );
462         } catch (uno::RuntimeException &) {
463             OSL_ENSURE(false, "SfxDocTplService_Impl::init_Impl: "
464                 "cannot create DocumentProperties service");
465         }
466 
467         aService = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_TYPEDETECTION ) );
468         mxType = uno::Reference< XTypeDetection > ( mxFactory->createInstance( aService ), UNO_QUERY );
469 
470         getDirList();
471         readFolderList();
472 
473 		if ( bNeedsUpdate )
474 		{
475             aGuard.clear();
476             ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
477 
478             WaitWindow_Impl* pWin = new WaitWindow_Impl();
479 
480             aSolarGuard.clear();
481             ::osl::ClearableMutexGuard anotherGuard( maMutex );
482 
483 			update( sal_True );
484 
485             anotherGuard.clear();
486             ::vos::OGuard aSecondSolarGuard( Application::GetSolarMutex() );
487 
488             delete pWin;
489         }
490 		else if ( needsUpdate() )
491 			// the UI should be shown only on the first update
492 			update( sal_True );
493     }
494     else
495     {
496         DBG_ERRORFILE( "init_Impl(): Could not create root" );
497     }
498 
499     mbIsInitialized = bIsInitialized;
500 }
501 
502 //-----------------------------------------------------------------------------
503 void SfxDocTplService_Impl::getDefaultLocale()
504 {
505     if ( !mbLocaleSet )
506     {
507         ::osl::MutexGuard aGuard( maMutex );
508         if ( !mbLocaleSet )
509         {
510             rtl::OUString aLocale;
511             utl::ConfigManager::GetDirectConfigProperty( utl::ConfigManager::LOCALE )
512                 >>= aLocale;
513 
514             if ( aLocale.getLength() > 0 )
515             {
516                 sal_Int32 nPos = aLocale.indexOf( sal_Unicode( '-' ) );
517                 if ( nPos != -1 )
518                 {
519                     maLocale.Language = aLocale.copy( 0, nPos );
520                     nPos = aLocale.indexOf( sal_Unicode( '_' ), nPos + 1 );
521                     if ( nPos != -1 )
522                     {
523                         maLocale.Country
524                             = aLocale.copy( maLocale.Language.getLength() + 1,
525                                             nPos - maLocale.Language.getLength() - 1 );
526                         maLocale.Variant
527                             = aLocale.copy( nPos + 1 );
528                     }
529                     else
530                     {
531                         maLocale.Country
532                             = aLocale.copy( maLocale.Language.getLength() + 1 );
533                     }
534                 }
535 
536             }
537 
538             mbLocaleSet = sal_True;
539         }
540     }
541 }
542 
543 // -----------------------------------------------------------------------
544 void SfxDocTplService_Impl::readFolderList()
545 {
546     ::vos::OGuard aGuard( Application::GetSolarMutex() );
547 
548     ResStringArray  aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) );
549     ResStringArray  aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) );
550 
551     NamePair_Impl*  pPair;
552 
553     sal_uInt16 nCount = (sal_uInt16)( Min( aShortNames.Count(), aLongNames.Count() ) );
554 
555     for ( sal_uInt16 i=0; i<nCount; i++ )
556     {
557         pPair = new NamePair_Impl;
558         pPair->maShortName  = aShortNames.GetString( i );
559         pPair->maLongName   = aLongNames.GetString( i );
560 
561         maNames.Insert( pPair, LIST_APPEND );
562     }
563 }
564 
565 // -----------------------------------------------------------------------
566 OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName )
567 {
568     OUString         aRet;
569     NamePair_Impl   *pPair = maNames.First();
570 
571     while ( pPair )
572     {
573         if ( pPair->maShortName == rShortName )
574         {
575             aRet = pPair->maLongName;
576             break;
577         }
578         else
579             pPair = maNames.Next();
580     }
581 
582     if ( !aRet.getLength() )
583         aRet = rShortName;
584 
585     return aRet;
586 }
587 
588 //-----------------------------------------------------------------------------
589 void SfxDocTplService_Impl::getDirList()
590 {
591     OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_DIRLIST ) );
592     Any      aValue;
593 
594     // Get the template dir list
595 	// TODO/LATER: let use service, register listener
596     INetURLObject   aURL;
597     String          aDirs = SvtPathOptions().GetTemplatePath();
598     sal_uInt16          nCount = aDirs.GetTokenCount( C_DELIM );
599 
600     maTemplateDirs = Sequence< OUString >( nCount );
601 
602     for ( sal_uInt16 i=0; i<nCount; i++ )
603     {
604         aURL.SetSmartProtocol( INET_PROT_FILE );
605         aURL.SetURL( aDirs.GetToken( i, C_DELIM ) );
606         maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE );
607     }
608 
609     aValue <<= maTemplateDirs;
610 
611     // Store the template dir list
612     setProperty( maRootContent, aPropName, aValue );
613 }
614 
615 //-----------------------------------------------------------------------------
616 sal_Bool SfxDocTplService_Impl::needsUpdate()
617 {
618 	OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) );
619 	sal_Bool bHasProperty = sal_False;
620     sal_Bool bNeedsUpdate = sal_True;
621 	Any		 aValue;
622 
623 	// Get the template dir list
624 	bHasProperty = getProperty( maRootContent, aPropName, aValue );
625 
626 	if ( bHasProperty )
627 		aValue >>= bNeedsUpdate;
628 
629 	// the old template component also checks this state, but it is initialized from this component
630 	// so if this componend was already updated the old component does not need such an update
631 	::svt::TemplateFolderCache aTempCache;
632 	if ( !bNeedsUpdate )
633 		bNeedsUpdate = aTempCache.needsUpdate();
634 
635 	if ( bNeedsUpdate )
636 		aTempCache.storeState();
637 
638     return bNeedsUpdate;
639 }
640 
641 // -----------------------------------------------------------------------
642 sal_Bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle )
643 {
644 	sal_Bool bResult = sal_False;
645     if ( mxInfo.is() )
646     {
647         try
648         {
649             mxInfo->loadFromURL( rURL );
650             uno::Reference< XPropertySet > xPropSet( mxInfo, UNO_QUERY_THROW );
651             OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
652 			xPropSet->setPropertyValue( aPropName, uno::makeAny( aTitle ) );
653 			mxInfo->storeIntoURL( rURL );
654 			bResult = sal_True;
655 		}
656         catch ( Exception& )
657 		{
658 		}
659     }
660 
661 	return bResult;
662 }
663 
664 // -----------------------------------------------------------------------
665 sal_Bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle )
666 {
667 	bDocHasTitle = sal_False;
668 
669     if ( mxInfo.is() )
670     {
671         try
672         {
673             mxInfo->loadFromURL( rURL );
674 		}
675         catch ( Exception& )
676 		{
677 			// the document is not a StarOffice document
678 			return sal_False;
679 		}
680 
681         try
682 		{
683             uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY );
684             if ( aPropSet.is() )
685             {
686                 OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
687                 Any aValue = aPropSet->getPropertyValue( aPropName );
688                 aValue >>= aTitle;
689 
690                 aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( "MIMEType" ) );
691                 aValue = aPropSet->getPropertyValue( aPropName );
692                 aValue >>= aType;
693             }
694         }
695         catch ( UnknownPropertyException& ) {}
696         catch ( Exception& ) {}
697     }
698 
699     if ( ! aType.getLength() && mxType.is() )
700     {
701 		::rtl::OUString aDocType = mxType->queryTypeByURL( rURL );
702 		if ( aDocType.getLength() )
703 			try
704 			{
705 				uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW );
706 				SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) );
707 				aType = aTypeProps.getUnpackedValueOrDefault(
708 							::rtl::OUString::createFromAscii( "MediaType" ),
709 							::rtl::OUString() );
710 			}
711 			catch( uno::Exception& )
712 			{}
713     }
714 
715     if ( ! aTitle.getLength() )
716     {
717         INetURLObject aURL( rURL );
718         aURL.CutExtension();
719         aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
720                                INetURLObject::DECODE_WITH_CHARSET );
721     }
722 	else
723 		bDocHasTitle = sal_True;
724 
725 	return sal_True;
726 }
727 
728 // -----------------------------------------------------------------------
729 sal_Bool SfxDocTplService_Impl::addEntry( Content& rParentFolder,
730                                           const OUString& rTitle,
731                                           const OUString& rTargetURL,
732                                           const OUString& rType )
733 {
734     sal_Bool bAddedEntry = sal_False;
735 
736     INetURLObject aLinkObj( rParentFolder.getURL() );
737     aLinkObj.insertName( rTitle, false,
738                       INetURLObject::LAST_SEGMENT, true,
739                       INetURLObject::ENCODE_ALL );
740     OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE );
741 
742     Content aLink;
743 
744     if ( ! Content::create( aLinkURL, maCmdEnv, aLink ) )
745     {
746         Sequence< OUString > aNames(3);
747         aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
748         aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) );
749         aNames[2] = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
750 
751         Sequence< Any > aValues(3);
752         aValues[0] = makeAny( rTitle );
753         aValues[1] = makeAny( sal_Bool( sal_False ) );
754         aValues[2] = makeAny( rTargetURL );
755 
756         OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_LINK ) );
757         OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) );
758 
759         try
760         {
761             rParentFolder.insertNewContent( aType, aNames, aValues, aLink );
762             setProperty( aLink, aAdditionalProp, makeAny( rType ) );
763             bAddedEntry = sal_True;
764         }
765         catch( Exception& )
766         {}
767     }
768     return bAddedEntry;
769 }
770 
771 // -----------------------------------------------------------------------
772 sal_Bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL,
773                                               sal_Bool  bCreateParent,
774                                               sal_Bool  bFsysFolder,
775                                               Content   &rNewFolder )
776 {
777     Content         aParent;
778     sal_Bool        bCreatedFolder = sal_False;
779     INetURLObject   aParentURL( rNewFolderURL );
780     OUString        aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true,
781                                                       INetURLObject::DECODE_WITH_CHARSET );
782 
783     // compute the parent folder url from the new folder url
784     // and remove the final slash, because Content::create doesn't
785     // like it
786     aParentURL.removeSegment();
787     if ( aParentURL.getSegmentCount() >= 1 )
788         aParentURL.removeFinalSlash();
789 
790     // if the parent exists, we can continue with the creation of the
791     // new folder, we have to create the parent otherwise ( as long as
792     // bCreateParent is set to true )
793     if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) )
794     {
795         try
796         {
797             Sequence< OUString > aNames(2);
798             aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
799             aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) );
800 
801             Sequence< Any > aValues(2);
802             aValues[0] = makeAny( aFolderName );
803             aValues[1] = makeAny( sal_Bool( sal_True ) );
804 
805             OUString aType;
806 
807             if ( bFsysFolder )
808                 aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) );
809             else
810                 aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FOLDER ) );
811 
812             aParent.insertNewContent( aType, aNames, aValues, rNewFolder );
813             bCreatedFolder = sal_True;
814         }
815         catch( RuntimeException& )
816         {
817             DBG_ERRORFILE( "createFolder(): got runtime exception" );
818         }
819         catch( Exception& )
820         {
821             DBG_ERRORFILE( "createFolder(): Could not create new folder" );
822         }
823     }
824     else if ( bCreateParent )
825     {
826         // if the parent doesn't exists and bCreateParent is set to true,
827         // we try to create the parent and if this was successful, we
828         // try to create the new folder again ( but this time, we set
829         // bCreateParent to false to avoid endless recusions )
830         if ( ( aParentURL.getSegmentCount() >= 1 ) &&
831                createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) )
832         {
833             bCreatedFolder = createFolder( rNewFolderURL, sal_False, bFsysFolder, rNewFolder );
834         }
835     }
836 
837     return bCreatedFolder;
838 }
839 
840 // -----------------------------------------------------------------------
841 sal_Bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath,
842 																const ::rtl::OUString& aPrefix,
843 																::rtl::OUString& aNewFolderName,
844 																::rtl::OUString& aNewFolderURL,
845 																Content& aNewFolder )
846 {
847 	sal_Bool bCreated = sal_False;
848 	INetURLObject aDirPath( aPath );
849 
850     Content aParent;
851    	if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) )
852    	{
853 		for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
854 		{
855 			::rtl::OUString aTryName = aPrefix;
856 			if ( nInd )
857 				aTryName += ::rtl::OUString::valueOf( nInd );
858 
859         	try
860         	{
861             	Sequence< OUString > aNames(2);
862             	aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
863             	aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) );
864 
865             	Sequence< Any > aValues(2);
866             	aValues[0] = makeAny( aTryName );
867             	aValues[1] = makeAny( sal_Bool( sal_True ) );
868 
869             	OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) );
870 
871             	bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder );
872         	}
873         	catch( ucb::NameClashException& )
874         	{
875 				// if there is already an element, retry
876         	}
877         	catch( Exception& )
878         	{
879 				INetURLObject aObjPath( aDirPath );
880 				aObjPath.insertName( aTryName, false,
881                       INetURLObject::LAST_SEGMENT, true,
882                       INetURLObject::ENCODE_ALL );
883 				// if there is already an element, retry
884 				// if there was another error, do not try any more
885 				if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
886 					break;
887         	}
888 
889 			if ( bCreated )
890 			{
891 				aNewFolderName = aTryName;
892 				aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier();
893 				break;
894 			}
895 		}
896 	}
897 
898 	return bCreated;
899 }
900 
901 // -----------------------------------------------------------------------
902 ::rtl::OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath,
903 																		const ::rtl::OUString& aPrefix,
904 																		const ::rtl::OUString& aExt )
905 {
906 	::rtl::OUString aNewFileURL;
907 	INetURLObject aDirPath( aPath );
908 
909    	Content aParent;
910 
911 	uno::Reference< XCommandEnvironment > aQuietEnv;
912 	if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, aParent ) )
913    	{
914 		for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
915 		{
916 			Content aNewFile;
917 			sal_Bool bCreated = sal_False;
918 			::rtl::OUString aTryName = aPrefix;
919 			if ( nInd )
920 				aTryName += ::rtl::OUString::valueOf( nInd );
921 			if ( aExt.toChar() != '.' )
922 				aTryName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) );
923 			aTryName += aExt;
924 
925         	try
926         	{
927             	Sequence< OUString > aNames(2);
928             	aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
929             	aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_DOCUMENT ) );
930 
931             	Sequence< Any > aValues(2);
932             	aValues[0] = makeAny( aTryName );
933             	aValues[1] = makeAny( sal_Bool( sal_True ) );
934 
935             	OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FILE ) );
936 
937             	bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile );
938         	}
939         	catch( ucb::NameClashException& )
940         	{
941 				// if there is already an element, retry
942         	}
943         	catch( Exception& )
944         	{
945 				INetURLObject aObjPath( aPath );
946 				aObjPath.insertName( aTryName, false,
947                       INetURLObject::LAST_SEGMENT, true,
948                       INetURLObject::ENCODE_ALL );
949 				// if there is already an element, retry
950 				// if there was another error, do not try any more
951 				if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
952 					break;
953         	}
954 
955 			if ( bCreated )
956 			{
957 				aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier();
958 				break;
959 			}
960 		}
961 	}
962 
963 	return aNewFileURL;
964 }
965 
966 // -----------------------------------------------------------------------
967 sal_Bool SfxDocTplService_Impl::removeContent( Content& rContent )
968 {
969     sal_Bool bRemoved = sal_False;
970     try
971     {
972         OUString aCmd( RTL_CONSTASCII_USTRINGPARAM( COMMAND_DELETE ) );
973         Any aArg = makeAny( sal_Bool( sal_True ) );
974 
975         rContent.executeCommand( aCmd, aArg );
976         bRemoved = sal_True;
977     }
978     catch ( RuntimeException& ) {}
979     catch ( Exception& ) {}
980 
981     return bRemoved;
982 }
983 
984 // -----------------------------------------------------------------------
985 sal_Bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL )
986 {
987     Content aContent;
988 
989     if ( Content::create( rContentURL, maCmdEnv, aContent ) )
990         return removeContent( aContent );
991     else
992         return sal_False;
993 }
994 
995 // -----------------------------------------------------------------------
996 sal_Bool SfxDocTplService_Impl::setProperty( Content& rContent,
997                                              const OUString& rPropName,
998                                              const Any& rPropValue )
999 {
1000     sal_Bool bPropertySet = sal_False;
1001 
1002     // Store the property
1003     try
1004     {
1005         Any aPropValue( rPropValue );
1006         uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1007 
1008         // check, wether or not the property exists, create it, when not
1009         if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1010         {
1011             uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY );
1012             if ( xProperties.is() )
1013             {
1014                 try
1015                 {
1016                     xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue );
1017                 }
1018                 catch( PropertyExistException& ) {}
1019                 catch( IllegalTypeException& ) { DBG_ERRORFILE( "IllegalTypeException" ); }
1020                 catch( IllegalArgumentException& ) { DBG_ERRORFILE( "IllegalArgumentException" ); }
1021             }
1022         }
1023 
1024         // To ensure a reloctable office installation, the path to the
1025         // office installtion directory must never be stored directly.
1026         if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1027         {
1028             OUString aValue;
1029             if ( rPropValue >>= aValue )
1030             {
1031                 maRelocator.makeRelocatableURL( aValue );
1032                 aPropValue = makeAny( aValue );
1033             }
1034             else
1035             {
1036                 Sequence< OUString > aValues;
1037                 if ( rPropValue >>= aValues )
1038                 {
1039                     for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1040                     {
1041                         maRelocator.makeRelocatableURL( aValues[ n ] );
1042                     }
1043                     aPropValue = makeAny( aValues );
1044                 }
1045                 else
1046                 {
1047                     OSL_ENSURE( false, "Unsupported property value type" );
1048                 }
1049             }
1050         }
1051 
1052         // now set the property
1053 
1054         rContent.setPropertyValue( rPropName, aPropValue );
1055         bPropertySet = sal_True;
1056     }
1057     catch ( RuntimeException& ) {}
1058     catch ( Exception& ) {}
1059 
1060     return bPropertySet;
1061 }
1062 
1063 // -----------------------------------------------------------------------
1064 sal_Bool SfxDocTplService_Impl::getProperty( Content& rContent,
1065                                              const OUString& rPropName,
1066                                              Any& rPropValue )
1067 {
1068     sal_Bool bGotProperty = sal_False;
1069 
1070     // Get the property
1071     try
1072     {
1073         uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1074 
1075         // check, wether or not the property exists
1076         if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1077         {
1078             return sal_False;
1079         }
1080 
1081         // now get the property
1082 
1083         rPropValue = rContent.getPropertyValue( rPropName );
1084 
1085         // To ensure a reloctable office installation, the path to the
1086         // office installtion directory must never be stored directly.
1087         if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1088         {
1089             OUString aValue;
1090             if ( rPropValue >>= aValue )
1091             {
1092                 maRelocator.makeAbsoluteURL( aValue );
1093                 rPropValue = makeAny( aValue );
1094             }
1095             else
1096             {
1097                 Sequence< OUString > aValues;
1098                 if ( rPropValue >>= aValues )
1099                 {
1100                     for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1101                     {
1102                         maRelocator.makeAbsoluteURL( aValues[ n ] );
1103                     }
1104                     rPropValue = makeAny( aValues );
1105                 }
1106                 else
1107                 {
1108                     OSL_ENSURE( false, "Unsupported property value type" );
1109                 }
1110             }
1111         }
1112 
1113         bGotProperty = sal_True;
1114     }
1115     catch ( RuntimeException& ) {}
1116     catch ( Exception& ) {}
1117 
1118     return bGotProperty;
1119 }
1120 
1121 // -----------------------------------------------------------------------
1122 // static
1123 bool SfxURLRelocator_Impl::propertyCanContainOfficeDir(
1124                                         const rtl::OUString & rPropName )
1125 {
1126     // Note: TargetURL is handled by UCB itself (because it is a property
1127     //       with a predefined semantic). Additional Core properties introduced
1128     //       be a client app must be handled by the client app itself, because
1129     //       the UCB does not know the semantics of those properties.
1130     return ( rPropName.equalsAsciiL(
1131                 RTL_CONSTASCII_STRINGPARAM( TARGET_DIR_URL ) ) ||
1132              rPropName.equalsAsciiL(
1133                 RTL_CONSTASCII_STRINGPARAM( PROPERTY_DIRLIST ) ) );
1134 }
1135 
1136 //-----------------------------------------------------------------------------
1137 // public SfxDocTplService_Impl
1138 //-----------------------------------------------------------------------------
1139 
1140 SfxDocTplService_Impl::SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory )
1141 : maRelocator( xFactory )
1142 {
1143     mxFactory       = xFactory;
1144     mpUpdater       = NULL;
1145     mbIsInitialized = sal_False;
1146     mbLocaleSet     = sal_False;
1147 }
1148 
1149 //-----------------------------------------------------------------------------
1150 SfxDocTplService_Impl::~SfxDocTplService_Impl()
1151 {
1152 	::osl::MutexGuard aGuard( maMutex );
1153 
1154     if ( mpUpdater )
1155     {
1156         mpUpdater->kill();
1157         delete mpUpdater;
1158     }
1159 }
1160 
1161 //-----------------------------------------------------------------------------
1162 Locale SfxDocTplService_Impl::getLocale()
1163 {
1164     ::osl::MutexGuard aGuard( maMutex );
1165 
1166     if ( !mbLocaleSet )
1167         getDefaultLocale();
1168 
1169     return maLocale;
1170 }
1171 
1172 //-----------------------------------------------------------------------------
1173 void SfxDocTplService_Impl::setLocale( const Locale &rLocale )
1174 {
1175     ::osl::MutexGuard aGuard( maMutex );
1176 
1177     if ( mbLocaleSet &&
1178          ( maLocale.Language != rLocale.Language ) &&
1179          ( maLocale.Country != rLocale.Country ) )
1180         mbIsInitialized = sal_False;
1181 
1182     maLocale    = rLocale;
1183     mbLocaleSet = sal_True;
1184 }
1185 
1186 //-----------------------------------------------------------------------------
1187 void SfxDocTplService_Impl::update( sal_Bool bUpdateNow )
1188 {
1189     ::osl::MutexGuard aGuard( maMutex );
1190 
1191     if ( bUpdateNow )
1192         doUpdate();
1193     else
1194     {
1195         mpUpdater = new Updater_Impl( this );
1196         mpUpdater->create();
1197     }
1198 }
1199 
1200 //-----------------------------------------------------------------------------
1201 void SfxDocTplService_Impl::doUpdate()
1202 {
1203     ::osl::MutexGuard aGuard( maMutex );
1204 
1205 	OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) );
1206 	Any		 aValue;
1207 
1208 	aValue <<= sal_True;
1209     setProperty( maRootContent, aPropName, aValue );
1210 
1211     GroupList_Impl	aGroupList;
1212 
1213     // get the entries from the hierarchy
1214     createFromContent( aGroupList, maRootContent, sal_True );
1215 
1216     // get the entries from the template directories
1217     sal_Int32   nCountDir = maTemplateDirs.getLength();
1218     OUString*   pDirs = maTemplateDirs.getArray();
1219     Content     aDirContent;
1220 
1221 	// the last directory in the list must be writable
1222 	sal_Bool bWriteableDirectory = sal_True;
1223 
1224     // the target folder might not exist, for this reason no interaction handler should be used
1225     uno::Reference< XCommandEnvironment > aQuietEnv;
1226 
1227     while ( nCountDir )
1228     {
1229         nCountDir--;
1230         if ( Content::create( pDirs[ nCountDir ], aQuietEnv, aDirContent ) )
1231         {
1232             createFromContent( aGroupList, aDirContent, sal_False, bWriteableDirectory );
1233         }
1234 
1235 		bWriteableDirectory = sal_False;
1236     }
1237 
1238     // now check the list
1239     GroupData_Impl *pGroup = aGroupList.First();
1240     while ( pGroup )
1241     {
1242         if ( pGroup->getInUse() )
1243         {
1244             if ( pGroup->getInHierarchy() )
1245             {
1246 				Content aGroup;
1247     			if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
1248         			setProperty( aGroup,
1249 								 OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ),
1250 								 makeAny( pGroup->getTargetURL() ) );
1251 
1252                 sal_uIntPtr nCount = pGroup->count();
1253                 for ( sal_uIntPtr i=0; i<nCount; i++ )
1254                 {
1255                     DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
1256                     if ( ! pData->getInUse() )
1257                     {
1258                         if ( pData->getInHierarchy() )
1259                             removeFromHierarchy( pData ); // delete entry in hierarchy
1260                         else
1261                             addToHierarchy( pGroup, pData ); // add entry to hierarchy
1262                     }
1263                     else if ( pData->getUpdateType() ||
1264                               pData->getUpdateLink() )
1265                     {
1266                         updateData( pData );
1267                     }
1268                 }
1269             }
1270             else
1271             {
1272                 addGroupToHierarchy( pGroup ); // add group to hierarchy
1273             }
1274         }
1275         else
1276             removeFromHierarchy( pGroup ); // delete group from hierarchy
1277 
1278         delete pGroup;
1279         pGroup = aGroupList.Next();
1280     }
1281 
1282    	aValue <<= sal_False;
1283     setProperty( maRootContent, aPropName, aValue );
1284 }
1285 
1286 //-----------------------------------------------------------------------------
1287 uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath )
1288 {
1289 	INetURLObject aLocObj( aUserPath );
1290     aLocObj.insertName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ), false,
1291                       INetURLObject::LAST_SEGMENT, true,
1292                       INetURLObject::ENCODE_ALL );
1293 	Content aLocContent;
1294 
1295 	// TODO/LATER: Use hashmap in future
1296 	uno::Sequence< beans::StringPair > aUINames;
1297 	if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), aLocContent ) )
1298 	{
1299 		try
1300 		{
1301 			uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream();
1302 			if ( xLocStream.is() )
1303 				aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxFactory );
1304 		}
1305 		catch( uno::Exception& )
1306 		{}
1307 	}
1308 
1309 	return aUINames;
1310 }
1311 
1312 //-----------------------------------------------------------------------------
1313 sal_Bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1314 																  const ::rtl::OUString& aGroupName,
1315 																  const ::rtl::OUString& aNewFolderName )
1316 {
1317 	uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1318 	sal_Int32 nLen = aUINames.getLength();
1319 
1320 	// it is possible that the name is used already, but it should be checked before
1321 	for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1322 		if ( aUINames[nInd].First.equals( aNewFolderName ) )
1323 			return sal_False;
1324 
1325 	aUINames.realloc( ++nLen );
1326 	aUINames[nLen-1].First = aNewFolderName;
1327 	aUINames[nLen-1].Second = aGroupName;
1328 
1329 	return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1330 }
1331 
1332 //-----------------------------------------------------------------------------
1333 sal_Bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1334 																  const ::rtl::OUString& aDefaultFsysGroupName,
1335 																  const ::rtl::OUString& aOldGroupName,
1336 																  const ::rtl::OUString& aNewGroupName )
1337 {
1338 	uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1339 	sal_Int32 nLen = aUINames.getLength();
1340 
1341 	sal_Bool bChanged = sal_False;
1342 	for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1343 		if ( aUINames[nInd].Second.equals( aOldGroupName ) )
1344 		{
1345 			aUINames[nInd].Second = aNewGroupName;
1346 			bChanged = sal_True;
1347 		}
1348 
1349 	if ( !bChanged )
1350 	{
1351 		aUINames.realloc( ++nLen );
1352 		aUINames[nLen-1].First = aDefaultFsysGroupName;
1353 		aUINames[nLen-1].Second = aNewGroupName;
1354 	}
1355 	return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1356 }
1357 
1358 //-----------------------------------------------------------------------------
1359 sal_Bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1360 																  const ::rtl::OUString& aGroupName )
1361 {
1362 	uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1363 	sal_Int32 nLen = aUINames.getLength();
1364 	uno::Sequence< beans::StringPair > aNewUINames( nLen );
1365 	sal_Int32 nNewLen = 0;
1366 
1367 	sal_Bool bChanged = sal_False;
1368 	for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1369 		if ( aUINames[nInd].Second.equals( aGroupName ) )
1370 			bChanged = sal_True;
1371 		else
1372 		{
1373 			nNewLen++;
1374 			aNewUINames[nNewLen-1].First = aUINames[nInd].First;
1375 			aNewUINames[nNewLen-1].Second = aUINames[nInd].Second;
1376 		}
1377 
1378 	aNewUINames.realloc( nNewLen );
1379 
1380 	return bChanged ? WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames ) : sal_True;
1381 }
1382 
1383 
1384 //-----------------------------------------------------------------------------
1385 sal_Bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1386 																const uno::Sequence< beans::StringPair >& aUINames )
1387 {
1388 	sal_Bool bResult = sal_False;
1389 	try {
1390 		uno::Reference< beans::XPropertySet > xTempFile(
1391 				mxFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
1392 				uno::UNO_QUERY_THROW );
1393 
1394 		::rtl::OUString aTempURL;
1395 		uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1396 		aUrl >>= aTempURL;
1397 
1398 		uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW );
1399 		uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream();
1400 		if ( !xOutStream.is() )
1401 			throw uno::RuntimeException();
1402 
1403 		DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxFactory );
1404 		try {
1405 			// the SAX writer might close the stream
1406 			xOutStream->closeOutput();
1407 		} catch( uno::Exception& )
1408 		{}
1409 
1410 		Content aTargetContent( aUserPath, maCmdEnv );
1411 		Content aSourceContent( aTempURL, maCmdEnv );
1412 		aTargetContent.transferContent( aSourceContent,
1413 										InsertOperation_COPY,
1414 										::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ),
1415 										ucb::NameClash::OVERWRITE );
1416 		bResult = sal_True;
1417 	}
1418 	catch ( uno::Exception& )
1419 	{
1420 	}
1421 
1422 	return bResult;
1423 }
1424 
1425 //-----------------------------------------------------------------------------
1426 ::rtl::OUString SfxDocTplService_Impl::CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup )
1427 {
1428 	::rtl::OUString aResultURL;
1429 
1430 	if ( maTemplateDirs.getLength() )
1431 	{
1432 		::rtl::OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1433 
1434 		// create a new folder with the given name
1435 		Content aNewFolder;
1436 		::rtl::OUString aNewFolderName;
1437 
1438 		// the Fsys name instead of GroupName should be used, the groupuinames must be added also
1439 		if ( !CreateNewUniqueFolderWithPrefix( aTargetPath,
1440 												rGroupName,
1441 												aNewFolderName,
1442 												aResultURL,
1443 												aNewFolder )
1444 		  && !CreateNewUniqueFolderWithPrefix( aTargetPath,
1445 												::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ),
1446 												aNewFolderName,
1447 												aResultURL,
1448 												aNewFolder ) )
1449 
1450 			return ::rtl::OUString();
1451 
1452 		if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) )
1453 		{
1454 			// we could not create the groupuinames for the folder, so we delete the group in the
1455 			// the folder and return
1456 			removeContent( aNewFolder );
1457 			return ::rtl::OUString();
1458 		}
1459 
1460 		// Now set the target url for this group and we are done
1461 		OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1462 		Any aValue = makeAny( aResultURL );
1463 
1464 		if ( ! setProperty( aGroup, aPropName, aValue ) )
1465 		{
1466 			removeContent( aNewFolder );
1467 			return ::rtl::OUString();
1468 		}
1469 	}
1470 
1471 	return aResultURL;
1472 }
1473 
1474 //-----------------------------------------------------------------------------
1475 sal_Bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName )
1476 {
1477 	::osl::MutexGuard aGuard( maMutex );
1478 
1479 	// Check, wether or not there is a group with this name
1480 	Content		 aNewGroup;
1481 	OUString		aNewGroupURL;
1482 	INetURLObject   aNewGroupObj( maRootURL );
1483 
1484 	aNewGroupObj.insertName( rGroupName, false,
1485 					  INetURLObject::LAST_SEGMENT, true,
1486 					  INetURLObject::ENCODE_ALL );
1487 
1488 	aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1489 
1490 	if ( Content::create( aNewGroupURL, maCmdEnv, aNewGroup ) ||
1491 		 ! createFolder( aNewGroupURL, sal_False, sal_False, aNewGroup ) )
1492 	{
1493 		// if there already was a group with this name or the new group
1494 		// could not be created, we return here
1495 		return sal_False;
1496 	}
1497 
1498 	// Get the user template path entry ( new group will always
1499 	// be added in the user template path )
1500 	sal_Int32   nIndex;
1501 	OUString	aUserPath;
1502 
1503 	nIndex = maTemplateDirs.getLength();
1504 	if ( nIndex )
1505 		nIndex--;
1506 	else
1507 		return sal_False;   // We don't know where to add the group
1508 
1509 	aUserPath = maTemplateDirs[ nIndex ];
1510 
1511 	// create a new folder with the given name
1512 	Content		 aNewFolder;
1513 	OUString		aNewFolderName;
1514 	OUString		aNewFolderURL;
1515 
1516 	// the Fsys name instead of GroupName should be used, the groupuinames must be added also
1517 	if ( !CreateNewUniqueFolderWithPrefix( aUserPath,
1518 											rGroupName,
1519 											aNewFolderName,
1520 											aNewFolderURL,
1521 											aNewFolder )
1522 	  && !CreateNewUniqueFolderWithPrefix( aUserPath,
1523 											::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ),
1524 											aNewFolderName,
1525 											aNewFolderURL,
1526 											aNewFolder ) )
1527 	{
1528 		// we could not create the folder, so we delete the group in the
1529 		// hierarchy and return
1530 		removeContent( aNewGroup );
1531 		return sal_False;
1532 	}
1533 
1534 	if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) )
1535 	{
1536 		// we could not create the groupuinames for the folder, so we delete the group in the
1537 		// hierarchy, the folder and return
1538 		removeContent( aNewGroup );
1539 		removeContent( aNewFolder );
1540 		return sal_False;
1541 	}
1542 
1543 	// Now set the target url for this group and we are done
1544 	OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1545 	Any aValue = makeAny( aNewFolderURL );
1546 
1547 	if ( ! setProperty( aNewGroup, aPropName, aValue ) )
1548 	{
1549 		removeContent( aNewGroup );
1550 		removeContent( aNewFolder );
1551 		return sal_False;
1552 	}
1553 
1554 	return sal_True;
1555 }
1556 
1557 //-----------------------------------------------------------------------------
1558 sal_Bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName )
1559 {
1560 	// remove all the elements that have the prefix aTargetURL
1561 	// if the group does not have other elements remove it
1562 
1563 	::osl::MutexGuard aGuard( maMutex );
1564 
1565 	sal_Bool bResult = sal_False;
1566 
1567 	// create the group url
1568 	INetURLObject aGroupObj( maRootURL );
1569 	aGroupObj.insertName( rGroupName, false,
1570 					  INetURLObject::LAST_SEGMENT, true,
1571 					  INetURLObject::ENCODE_ALL );
1572 
1573 	// Get the target url
1574 	Content	 aGroup;
1575 	OUString	aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1576 
1577 	if ( Content::create( aGroupURL, maCmdEnv, aGroup ) )
1578 	{
1579 		OUString	aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1580 		Any		 aValue;
1581 
1582 		OUString	aGroupTargetURL;
1583 		if ( getProperty( aGroup, aPropName, aValue ) )
1584 			aValue >>= aGroupTargetURL;
1585 
1586 		if ( !aGroupTargetURL.getLength() )
1587 			return sal_False; // nothing is allowed to be removed
1588 
1589 		if ( !maTemplateDirs.getLength() )
1590 			return sal_False;
1591 		::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1592 
1593 		// check that the fs location is in writeble folder and this is not a "My templates" folder
1594 		INetURLObject aGroupParentFolder( aGroupTargetURL );
1595 		if ( !aGroupParentFolder.removeSegment()
1596 		  || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1597 		  											aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1598 			return sal_False;
1599 
1600 		// now get the content of the Group
1601 		uno::Reference< XResultSet > xResultSet;
1602 		Sequence< OUString > aProps( 1 );
1603 
1604 		aProps[0] = OUString::createFromAscii( TARGET_URL );
1605 
1606 		try
1607 		{
1608 			sal_Bool bHasNonRemovable = sal_False;
1609 			sal_Bool bHasShared = sal_False;
1610 
1611 			ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1612 			xResultSet = aGroup.createCursor( aProps, eInclude );
1613 
1614 			if ( xResultSet.is() )
1615 			{
1616 				uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1617 				uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1618 
1619 				while ( xResultSet->next() )
1620 				{
1621 					OUString aTemplTargetURL( xRow->getString( 1 ) );
1622 					OUString aHierURL = xContentAccess->queryContentIdentifierString();
1623 
1624 					if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1625 					{
1626 						// this is a user template, and it can be removed
1627 						if ( removeContent( aTemplTargetURL ) )
1628 							removeContent( aHierURL );
1629 						else
1630 							bHasNonRemovable = sal_True;
1631 					}
1632 					else
1633 						bHasShared = sal_True;
1634 				}
1635 
1636 				if ( !bHasNonRemovable && !bHasShared )
1637 				{
1638 					if ( removeContent( aGroupTargetURL )
1639 					  || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1640 					{
1641 						removeContent( aGroupURL );
1642 						RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1643 						bResult = sal_True; // the operation is successful only if the whole group is removed
1644 					}
1645 				}
1646 				else if ( !bHasNonRemovable )
1647 				{
1648 					if ( removeContent( aGroupTargetURL )
1649 					  || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1650 					{
1651 						RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1652 						setProperty( aGroup, aPropName, uno::makeAny( ::rtl::OUString() ) );
1653 					}
1654 				}
1655 			}
1656 		}
1657 		catch ( Exception& ) {}
1658 	}
1659 
1660 	return bResult;
1661 }
1662 
1663 //-----------------------------------------------------------------------------
1664 sal_Bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName,
1665                                              const OUString& rNewName )
1666 {
1667     ::osl::MutexGuard aGuard( maMutex );
1668 
1669     // create the group url
1670     Content         aGroup;
1671     INetURLObject   aGroupObj( maRootURL );
1672                     aGroupObj.insertName( rNewName, false,
1673                                           INetURLObject::LAST_SEGMENT, true,
1674                                           INetURLObject::ENCODE_ALL );
1675     OUString        aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1676 
1677     // Check, if there is a group with the new name, return false
1678     // if there is one.
1679     if ( Content::create( aGroupURL, maCmdEnv, aGroup ) )
1680         return sal_False;
1681 
1682     aGroupObj.removeSegment();
1683     aGroupObj.insertName( rOldName, false,
1684                       INetURLObject::LAST_SEGMENT, true,
1685                       INetURLObject::ENCODE_ALL );
1686     aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1687 
1688     // When there is no group with the old name, we can't rename it
1689     if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
1690         return sal_False;
1691 
1692 	OUString aGroupTargetURL;
1693 	// there is no need to check whether target dir url is in target path, since if the target path is changed
1694 	// the target dir url should be already generated new
1695 	OUString	aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1696 	Any		 aValue;
1697 	if ( getProperty( aGroup, aPropName, aValue ) )
1698 		aValue >>= aGroupTargetURL;
1699 
1700 	if ( !aGroupTargetURL.getLength() )
1701 		return sal_False;
1702 
1703 	if ( !maTemplateDirs.getLength() )
1704 		return sal_False;
1705 	::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1706 
1707 	// check that the fs location is in writeble folder and this is not a "My templates" folder
1708 	INetURLObject aGroupParentFolder( aGroupTargetURL );
1709 	if ( !aGroupParentFolder.removeSegment()
1710 	  || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1711 		  										aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1712 		return sal_False;
1713 
1714 	// check that the group can be renamed ( all the contents must be in target location )
1715 	sal_Bool bCanBeRenamed = sal_False;
1716    	try
1717    	{
1718 		uno::Reference< XResultSet > xResultSet;
1719 		Sequence< OUString > aProps( 1 );
1720 
1721 		aProps[0] = OUString::createFromAscii( TARGET_URL );
1722 		ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1723 		xResultSet = aGroup.createCursor( aProps, eInclude );
1724 
1725 		if ( xResultSet.is() )
1726 		{
1727 	   		uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1728 	   		uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1729 
1730 	   		while ( xResultSet->next() )
1731 	   		{
1732 		   		OUString aTemplTargetURL( xRow->getString( 1 ) );
1733 
1734 				if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1735 					throw uno::Exception();
1736 			}
1737 
1738 			bCanBeRenamed = sal_True;
1739 		}
1740 	}
1741 	catch ( Exception& ) {}
1742 
1743 	if ( bCanBeRenamed )
1744 	{
1745     	INetURLObject aGroupTargetObj( aGroupTargetURL );
1746 		::rtl::OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1747 
1748 		if ( aGroupTargetObj.removeSegment()
1749 		  && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ),
1750 		  										aFsysName,
1751 												rOldName,
1752 												rNewName ) )
1753 		{
1754 			// rename the group in the hierarchy
1755 			OUString aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
1756 			Any aTitleValue;
1757 			aTitleValue <<= rNewName;
1758 
1759 			return setProperty( aGroup, aTitleProp, aTitleValue );
1760 		}
1761 	}
1762 
1763 	return sal_False;
1764 }
1765 
1766 //-----------------------------------------------------------------------------
1767 sal_Bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName,
1768                                                const OUString& rTemplateName,
1769                                                const uno::Reference< XSTORABLE >& rStorable )
1770 {
1771     ::osl::MutexGuard aGuard( maMutex );
1772 
1773     // Check, wether or not there is a group with this name
1774     // Return false, if there is no group with the given name
1775     Content         aGroup, aTemplate, aTargetGroup, aTemplateToRemove;
1776     OUString        aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL;
1777     INetURLObject   aGroupObj( maRootURL );
1778 	sal_Bool		bRemoveOldTemplateContent = sal_False;
1779     ::rtl::OUString sDocServiceName;
1780 
1781     aGroupObj.insertName( rGroupName, false,
1782                       INetURLObject::LAST_SEGMENT, true,
1783                       INetURLObject::ENCODE_ALL );
1784     aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1785 
1786     if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
1787         return sal_False;
1788 
1789 	::rtl::OUString	aGroupTargetURL;
1790 	::rtl::OUString	aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1791 	Any		 aValue;
1792 	if ( getProperty( aGroup, aPropName, aValue ) )
1793 		aValue >>= aGroupTargetURL;
1794 
1795 
1796     // Check, if there's a template with the given name in this group
1797     // the target template should be overwritten if it is imported by user
1798 	// in case the template is installed by office installation of by an add-in
1799 	// it can not be replaced
1800     aGroupObj.insertName( rTemplateName, false,
1801                       INetURLObject::LAST_SEGMENT, true,
1802                       INetURLObject::ENCODE_ALL );
1803     aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1804 
1805     if ( Content::create( aTemplateURL, maCmdEnv, aTemplateToRemove ) )
1806 	{
1807 		OUString    aTargetTemplPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
1808 
1809 		bRemoveOldTemplateContent = sal_True;
1810 		if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) )
1811 			aValue >>= aTemplateToRemoveTargetURL;
1812 
1813 		if ( !aGroupTargetURL.getLength() || !maTemplateDirs.getLength()
1814 		  || (aTemplateToRemoveTargetURL.getLength() && !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTemplateToRemoveTargetURL )) )
1815         	return sal_False; // it is not allowed to remove the template
1816 	}
1817 
1818 	try
1819 	{
1820 		uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
1821 		if ( !xFactory.is() )
1822 			throw uno::RuntimeException();
1823 
1824 		// get document service name
1825 		uno::Reference< frame::XModuleManager > xModuleManager(
1826 			xFactory->createInstance(
1827 					::rtl::OUString::createFromAscii( "com.sun.star.frame.ModuleManager" ) ),
1828 			uno::UNO_QUERY_THROW );
1829         sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) );
1830         if ( !sDocServiceName.getLength() )
1831 			throw uno::RuntimeException();
1832 
1833 		// get the actual filter name
1834 		::rtl::OUString aFilterName;
1835 
1836 		uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
1837 				xFactory->createInstance(
1838 					::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ),
1839 				uno::UNO_QUERY_THROW );
1840 
1841 		uno::Sequence< uno::Any > aArgs( 1 );
1842 		beans::PropertyValue aPathProp;
1843 		aPathProp.Name = ::rtl::OUString::createFromAscii( "nodepath" );
1844 		aPathProp.Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/" ) );
1845 		aArgs[0] <<= aPathProp;
1846 
1847 		uno::Reference< container::XNameAccess > xSOFConfig(
1848 			xConfigProvider->createInstanceWithArguments(
1849 									::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationAccess" ),
1850 									aArgs ),
1851 			uno::UNO_QUERY_THROW );
1852 
1853 		uno::Reference< container::XNameAccess > xApplConfig;
1854         xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig;
1855 		if ( !xApplConfig.is() )
1856 			throw uno::RuntimeException();
1857 
1858 		xApplConfig->getByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupFactoryActualTemplateFilter" ) ) ) >>= aFilterName;
1859 		if ( !aFilterName.getLength() )
1860 			throw uno::RuntimeException();
1861 
1862 		// find the related type name
1863 		::rtl::OUString aTypeName;
1864 		uno::Reference< container::XNameAccess > xFilterFactory(
1865 			xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
1866 			uno::UNO_QUERY_THROW );
1867 
1868 		uno::Sequence< beans::PropertyValue > aFilterData;
1869 		xFilterFactory->getByName( aFilterName ) >>= aFilterData;
1870 		for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
1871 			if ( aFilterData[nInd].Name.equalsAscii( "Type" ) )
1872 				aFilterData[nInd].Value >>= aTypeName;
1873 
1874 		if ( !aTypeName.getLength() )
1875 			throw uno::RuntimeException();
1876 
1877 		// find the mediatype and extension
1878 		uno::Reference< container::XNameAccess > xTypeDetection	=
1879 			mxType.is() ?
1880 				uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) :
1881 				uno::Reference< container::XNameAccess >(
1882 					xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ),
1883 					uno::UNO_QUERY_THROW );
1884 
1885 		SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) );
1886 		uno::Sequence< ::rtl::OUString > aAllExt =
1887 			aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Extensions" ), Sequence< ::rtl::OUString >() );
1888 		if ( !aAllExt.getLength() )
1889 			throw uno::RuntimeException();
1890 
1891 		::rtl::OUString aMediaType = aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "MediaType"  ), ::rtl::OUString() );
1892 		::rtl::OUString aExt = aAllExt[0];
1893 
1894 		if ( !aMediaType.getLength() || !aExt.getLength() )
1895 			throw uno::RuntimeException();
1896 
1897 		// construct destination url
1898 		if ( !aGroupTargetURL.getLength() )
1899 		{
1900 			aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1901 
1902 			if ( !aGroupTargetURL.getLength() )
1903 				throw uno::RuntimeException();
1904 		}
1905 
1906 		::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt );
1907 		if ( !aNewTemplateTargetURL.getLength() )
1908 		{
1909 			aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserTemplate" ) ), aExt );
1910 
1911 			if ( !aNewTemplateTargetURL.getLength() )
1912 				throw uno::RuntimeException();
1913 		}
1914 
1915 		// store template
1916 		uno::Sequence< PropertyValue > aStoreArgs( 2 );
1917 		aStoreArgs[0].Name = ::rtl::OUString::createFromAscii( "FilterName" );
1918 		aStoreArgs[0].Value <<= aFilterName;
1919 		aStoreArgs[1].Name = ::rtl::OUString::createFromAscii( "DocumentTitle" );
1920 		aStoreArgs[1].Value <<= rTemplateName;
1921 
1922 		::rtl::OUString aCurrentDocumentURL = rStorable->getLocation();
1923 		if( !::utl::UCBContentHelper::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() ))
1924 			rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs );
1925 		else
1926 			rStorable->store();
1927 
1928 		// the storing was successful, now the old template with the same name can be removed if it existed
1929 		if ( aTemplateToRemoveTargetURL.getLength() )
1930         {
1931 			removeContent( aTemplateToRemoveTargetURL );
1932 
1933             /*
1934              * pb: #i79496#
1935              * if the old template was the standard template
1936              * it is necessary to change the standard template with the new file name
1937              */
1938             String sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName );
1939             if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) )
1940             {
1941                 SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL );
1942             }
1943         }
1944 
1945 		if ( bRemoveOldTemplateContent )
1946 			removeContent( aTemplateToRemove );
1947 
1948 		// add the template to hierarchy
1949 		return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType );
1950 	}
1951 	catch( Exception& )
1952 	{
1953 		// the template was not stored
1954 		return sal_False;
1955 	}
1956 }
1957 
1958 //-----------------------------------------------------------------------------
1959 sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName,
1960                                              const OUString& rTemplateName,
1961                                              const OUString& rSourceURL )
1962 {
1963     ::osl::MutexGuard aGuard( maMutex );
1964 
1965     // Check, wether or not there is a group with this name
1966     // Return false, if there is no group with the given name
1967     Content         aGroup, aTemplate, aTargetGroup;
1968     OUString        aGroupURL, aTemplateURL;
1969     INetURLObject   aGroupObj( maRootURL );
1970 
1971     aGroupObj.insertName( rGroupName, false,
1972                       INetURLObject::LAST_SEGMENT, true,
1973                       INetURLObject::ENCODE_ALL );
1974     aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1975 
1976     if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
1977         return sal_False;
1978 
1979     // Check, if there's a template with the given name in this group
1980     // Return false, if there already is a template
1981     aGroupObj.insertName( rTemplateName, false,
1982                       INetURLObject::LAST_SEGMENT, true,
1983                       INetURLObject::ENCODE_ALL );
1984     aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1985 
1986     if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
1987         return sal_False;
1988 
1989     // get the target url of the group
1990     OUString    aTargetURL;
1991     OUString    aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
1992     Any         aValue;
1993 
1994     if ( getProperty( aGroup, aPropName, aValue ) )
1995         aValue >>= aTargetURL;
1996 
1997     if ( !aTargetURL.getLength() )
1998 	{
1999 		aTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
2000 
2001 		if ( !aTargetURL.getLength() )
2002 			return sal_False;
2003 	}
2004 
2005     // Get the content type
2006     OUString aTitle, aType, aTargetURL2, aFullName;
2007 
2008 	// only StarOffice documents are acceptable
2009 	sal_Bool bDocHasTitle = sal_False;
2010     if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) )
2011 		return sal_False;
2012 
2013     INetURLObject   aSourceObj( rSourceURL );
2014 	if ( rTemplateName.equals( aTitle ) )
2015 	{
2016 		/////////////////////////////////////////////////////
2017     	// addTemplate will sometimes be called just to add an entry in the
2018     	// hierarchy; the target URL and the source URL will be the same in
2019     	// this scenario
2020 		// TODO/LATER: get rid of this old hack
2021 
2022     	INetURLObject   aTargetObj( aTargetURL );
2023 
2024     	aTargetObj.insertName( rTemplateName, false,
2025                       INetURLObject::LAST_SEGMENT, true,
2026                       INetURLObject::ENCODE_ALL );
2027     	aTargetObj.setExtension( aSourceObj.getExtension() );
2028 
2029     	aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE );
2030 
2031     	if ( aTargetURL2 == rSourceURL )
2032         	return addEntry( aGroup, rTemplateName, aTargetURL2, aType );
2033 	}
2034 
2035 	/////////////////////////////////////////////////////
2036     // copy the template into the new group (targeturl)
2037 
2038 	INetURLObject aTmpURL( aSourceObj );
2039 	aTmpURL.CutExtension();
2040 	::rtl::OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2041 
2042 	::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() );
2043 	INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL );
2044 	::rtl::OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2045 	if ( !aNewTemplateTargetURL.getLength() || !aNewTemplateTargetName.getLength() )
2046 		return sal_False;
2047 
2048 	// get access to source file
2049 	Content aSourceContent;
2050 	uno::Reference < ucb::XCommandEnvironment > xEnv;
2051 	INetURLObject   aSourceURL( rSourceURL );
2052 	if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) )
2053 		return sal_False;
2054 
2055 	if( ! Content::create( aTargetURL, xEnv, aTargetGroup ) )
2056 		return sal_False;
2057 
2058 	// transfer source file
2059     try
2060     {
2061 		if( ! aTargetGroup.transferContent( aSourceContent,
2062 												InsertOperation_COPY,
2063 												aNewTemplateTargetName,
2064 												NameClash::OVERWRITE ) )
2065 			return sal_False;
2066 
2067 		// allow to edit the added template
2068 		Content aResultContent;
2069 		if ( Content::create( aNewTemplateTargetURL, xEnv, aResultContent ) )
2070 		{
2071 			::rtl::OUString aPropertyName( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) );
2072 			uno::Any aProperty;
2073 			sal_Bool bReadOnly = sal_False;
2074 			if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly )
2075 				setProperty( aResultContent, aPropertyName, uno::makeAny( (sal_Bool)sal_False ) );
2076 		}
2077     }
2078     catch ( ContentCreationException& )
2079     { return sal_False; }
2080     catch ( Exception& )
2081     { return sal_False; }
2082 
2083 
2084 	// either the document has title and it is the same as requested, or we have to set it
2085 	sal_Bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) );
2086 	if ( !bCorrectTitle )
2087 	{
2088 		if ( !bDocHasTitle )
2089 		{
2090 			INetURLObject aNewTmpObj( aNewTemplateTargetObj );
2091 			aNewTmpObj.CutExtension();
2092 			bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) );
2093 		}
2094 
2095 		if ( !bCorrectTitle )
2096 			bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName );
2097 	}
2098 
2099     if ( bCorrectTitle )
2100 	{
2101     	// create a new entry in the hierarchy
2102     	return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType );
2103 	}
2104 
2105 	// TODO/LATER: The user could be notified here that the renaming has failed
2106     // create a new entry in the hierarchy
2107     addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType );
2108 	return sal_False;
2109 }
2110 
2111 //-----------------------------------------------------------------------------
2112 sal_Bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName,
2113                                                 const OUString& rTemplateName )
2114 {
2115     ::osl::MutexGuard aGuard( maMutex );
2116 
2117     // Check, wether or not there is a group with this name
2118     // Return false, if there is no group with the given name
2119     Content         aGroup, aTemplate;
2120     OUString        aGroupURL, aTemplateURL;
2121     INetURLObject   aGroupObj( maRootURL );
2122 
2123     aGroupObj.insertName( rGroupName, false,
2124                       INetURLObject::LAST_SEGMENT, true,
2125                       INetURLObject::ENCODE_ALL );
2126     aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2127 
2128     if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
2129         return sal_False;
2130 
2131     // Check, if there's a template with the given name in this group
2132     // Return false, if there is no template
2133     aGroupObj.insertName( rTemplateName, false,
2134                       INetURLObject::LAST_SEGMENT, true,
2135                       INetURLObject::ENCODE_ALL );
2136     aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2137 
2138     if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2139         return sal_False;
2140 
2141     // get the target URL from the template
2142     OUString    aTargetURL;
2143     OUString    aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
2144     Any         aValue;
2145 
2146     if ( getProperty( aTemplate, aPropName, aValue ) )
2147         aValue >>= aTargetURL;
2148 
2149     // delete the target template
2150     if ( aTargetURL.getLength() )
2151     {
2152 		if ( !maTemplateDirs.getLength()
2153 		  || !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTargetURL ) )
2154 			return sal_False;
2155 
2156         removeContent( aTargetURL );
2157     }
2158 
2159     // delete the template entry
2160     return removeContent( aTemplate );
2161 }
2162 
2163 //-----------------------------------------------------------------------------
2164 sal_Bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName,
2165                                                 const OUString& rOldName,
2166                                                 const OUString& rNewName )
2167 {
2168     ::osl::MutexGuard aGuard( maMutex );
2169 
2170     // Check, wether or not there is a group with this name
2171     // Return false, if there is no group with the given name
2172     Content         aGroup, aTemplate;
2173     OUString        aGroupURL, aTemplateURL;
2174     INetURLObject   aGroupObj( maRootURL );
2175 
2176     aGroupObj.insertName( rGroupName, false,
2177                       INetURLObject::LAST_SEGMENT, true,
2178                       INetURLObject::ENCODE_ALL );
2179     aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2180 
2181     if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
2182         return sal_False;
2183 
2184     // Check, if there's a template with the new name in this group
2185     // Return false, if there is one
2186     aGroupObj.insertName( rNewName, false,
2187                       INetURLObject::LAST_SEGMENT, true,
2188                       INetURLObject::ENCODE_ALL );
2189     aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2190 
2191     if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2192         return sal_False;
2193 
2194     // Check, if there's a template with the old name in this group
2195     // Return false, if there is no template
2196     aGroupObj.removeSegment();
2197     aGroupObj.insertName( rOldName, false,
2198                       INetURLObject::LAST_SEGMENT, true,
2199                       INetURLObject::ENCODE_ALL );
2200     aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2201 
2202     if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2203         return sal_False;
2204 
2205 	OUString    aTemplateTargetURL;
2206 	OUString    aTargetProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
2207 	Any         aTargetValue;
2208 
2209 	if ( getProperty( aTemplate, aTargetProp, aTargetValue ) )
2210 		aTargetValue >>= aTemplateTargetURL;
2211 
2212     if ( !setTitleForURL( aTemplateTargetURL, rNewName ) )
2213 		return sal_False;
2214 
2215     // rename the template entry in the cache
2216     OUString    aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) );
2217     Any         aTitleValue;
2218     aTitleValue <<= rNewName;
2219 
2220     return setProperty( aTemplate, aTitleProp, aTitleValue );
2221 }
2222 
2223 //-----------------------------------------------------------------------------
2224 //-----------------------------------------------------------------------------
2225 //-----------------------------------------------------------------------------
2226 
2227 SFX_IMPL_XSERVICEINFO( SfxDocTplService, TEMPLATE_SERVICE_NAME, TEMPLATE_IMPLEMENTATION_NAME )
2228 SFX_IMPL_SINGLEFACTORY( SfxDocTplService )
2229 
2230 //-----------------------------------------------------------------------------
2231 SfxDocTplService::SfxDocTplService( const uno::Reference< XMultiServiceFactory >& xFactory )
2232 {
2233     pImp = new SfxDocTplService_Impl( xFactory );
2234 }
2235 
2236 //-----------------------------------------------------------------------------
2237 
2238 SfxDocTplService::~SfxDocTplService()
2239 {
2240     delete pImp;
2241 }
2242 
2243 //-----------------------------------------------------------------------------
2244 //--- XLocalizable ---
2245 //-----------------------------------------------------------------------------
2246 
2247 Locale SAL_CALL SfxDocTplService::getLocale()
2248     throw( RUNTIMEEXCEPTION )
2249 {
2250     return pImp->getLocale();
2251 }
2252 
2253 //-----------------------------------------------------------------------------
2254 
2255 void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale )
2256     throw( RUNTIMEEXCEPTION )
2257 {
2258     pImp->setLocale( rLocale );
2259 }
2260 
2261 //-----------------------------------------------------------------------------
2262 //--- XDocumentTemplates ---
2263 //-----------------------------------------------------------------------------
2264 uno::Reference< XCONTENT > SAL_CALL SfxDocTplService::getContent()
2265     throw( RUNTIMEEXCEPTION )
2266 {
2267     if ( pImp->init() )
2268         return pImp->getContent().get();
2269     else
2270         return NULL;
2271 }
2272 
2273 //-----------------------------------------------------------------------------
2274 sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName,
2275                                                    const OUString& TemplateName,
2276                                                    const uno::Reference< XSTORABLE >& Storable )
2277     throw( RUNTIMEEXCEPTION )
2278 {
2279 	if ( pImp->init() )
2280 		return pImp->storeTemplate( GroupName, TemplateName, Storable );
2281 	else
2282     	return sal_False;
2283 }
2284 
2285 //-----------------------------------------------------------------------------
2286 sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName,
2287                                                  const OUString& rTemplateName,
2288                                                  const OUString& rSourceURL )
2289     throw( RUNTIMEEXCEPTION )
2290 {
2291     if ( pImp->init() )
2292         return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL );
2293     else
2294         return sal_False;
2295 }
2296 
2297 //-----------------------------------------------------------------------------
2298 sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName,
2299                                                     const OUString& rTemplateName )
2300     throw( RUNTIMEEXCEPTION )
2301 {
2302     if ( pImp->init() )
2303         return pImp->removeTemplate( rGroupName, rTemplateName );
2304     else
2305         return sal_False;
2306 }
2307 
2308 //-----------------------------------------------------------------------------
2309 sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName,
2310                                                     const OUString& rOldName,
2311                                                     const OUString& rNewName )
2312     throw( RUNTIMEEXCEPTION )
2313 {
2314     if ( rOldName == rNewName )
2315         return sal_True;
2316 
2317     if ( pImp->init() )
2318         return pImp->renameTemplate( rGroupName, rOldName, rNewName );
2319     else
2320         return sal_False;
2321 }
2322 
2323 //-----------------------------------------------------------------------------
2324 sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName )
2325     throw( RUNTIMEEXCEPTION )
2326 {
2327     if ( pImp->init() )
2328         return pImp->addGroup( rGroupName );
2329     else
2330         return sal_False;
2331 }
2332 
2333 //-----------------------------------------------------------------------------
2334 sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName )
2335     throw( RUNTIMEEXCEPTION )
2336 {
2337     if ( pImp->init() )
2338         return pImp->removeGroup( rGroupName );
2339     else
2340         return sal_False;
2341 }
2342 
2343 //-----------------------------------------------------------------------------
2344 sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName,
2345                                                  const OUString& rNewName )
2346     throw( RUNTIMEEXCEPTION )
2347 {
2348     if ( rOldName == rNewName )
2349         return sal_True;
2350 
2351     if ( pImp->init() )
2352         return pImp->renameGroup( rOldName, rNewName );
2353     else
2354         return sal_False;
2355 }
2356 
2357 //-----------------------------------------------------------------------------
2358 void SAL_CALL SfxDocTplService::update()
2359     throw( RUNTIMEEXCEPTION )
2360 {
2361     if ( pImp->init() )
2362         pImp->update( sal_True );
2363 }
2364 
2365 //-----------------------------------------------------------------------------
2366 //-----------------------------------------------------------------------------
2367 //------------------------------------------------------------------------
2368 
2369 Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2370 {
2371     mpDocTemplates = pTemplates;
2372 }
2373 
2374 //------------------------------------------------------------------------
2375 Updater_Impl::~Updater_Impl()
2376 {
2377 }
2378 
2379 //------------------------------------------------------------------------
2380 void SAL_CALL Updater_Impl::run()
2381 {
2382     mpDocTemplates->doUpdate();
2383 }
2384 
2385 //------------------------------------------------------------------------
2386 void SAL_CALL Updater_Impl::onTerminated()
2387 {
2388     mpDocTemplates->finished();
2389     delete this;
2390 }
2391 
2392 //-----------------------------------------------------------------------------
2393 //-----------------------------------------------------------------------------
2394 //-----------------------------------------------------------------------------
2395 WaitWindow_Impl::WaitWindow_Impl()
2396     : WorkWindow( NULL, WB_BORDER | WB_3DLOOK )
2397 {
2398     Rectangle aRect = Rectangle( 0, 0, 300, 30000 );
2399     _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE;
2400     _aText = String( SfxResId( RID_CNT_STR_WAITING ) );
2401     _aRect = GetTextRect( aRect, _aText, _nTextStyle );
2402     aRect = _aRect;
2403     aRect.Right() += 2*X_OFFSET;
2404     aRect.Bottom() += 2*Y_OFFSET;
2405     _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) );
2406     SetOutputSizePixel( aRect.GetSize() );
2407     Show();
2408     Update();
2409     Flush();
2410 }
2411 
2412 //-----------------------------------------------------------------------------
2413 WaitWindow_Impl::~WaitWindow_Impl()
2414 {
2415     Hide();
2416 }
2417 
2418 //-----------------------------------------------------------------------------
2419 void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ )
2420 {
2421     DrawText( _aRect, _aText, _nTextStyle );
2422 }
2423 
2424 //-----------------------------------------------------------------------------
2425 //-----------------------------------------------------------------------------
2426 //-----------------------------------------------------------------------------
2427 void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList,
2428                                           const OUString& rTitle,
2429                                           const OUString& rOwnURL )
2430 {
2431     // now get the content of the Group
2432     Content                 aContent;
2433     uno::Reference< XResultSet > xResultSet;
2434     Sequence< OUString >    aProps(3);
2435 
2436     aProps[0] = OUString::createFromAscii( TITLE );
2437     aProps[1] = OUString::createFromAscii( TARGET_URL );
2438     aProps[2] = OUString::createFromAscii( PROPERTY_TYPE );
2439 
2440     try
2441     {
2442         aContent = Content( rOwnURL, maCmdEnv );
2443         ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2444         xResultSet = aContent.createCursor( aProps, eInclude );
2445     }
2446     catch ( ContentCreationException& )
2447     {
2448         DBG_ERRORFILE( "addHierGroup: ContentCreationException" );
2449     }
2450     catch ( Exception& ) {}
2451 
2452     if ( xResultSet.is() )
2453     {
2454         GroupData_Impl *pGroup = new GroupData_Impl( rTitle );
2455         pGroup->setHierarchy( sal_True );
2456         pGroup->setHierarchyURL( rOwnURL );
2457         rList.Insert( pGroup );
2458 
2459         uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2460         uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2461 
2462         try
2463         {
2464             while ( xResultSet->next() )
2465             {
2466                 sal_Bool             bUpdateType = sal_False;
2467                 DocTemplates_EntryData_Impl  *pData;
2468 
2469                 OUString aTitle( xRow->getString( 1 ) );
2470                 OUString aTargetDir( xRow->getString( 2 ) );
2471                 OUString aType( xRow->getString( 3 ) );
2472                 OUString aHierURL = xContentAccess->queryContentIdentifierString();
2473 
2474                 if ( !aType.getLength() )
2475                 {
2476                     OUString aTmpTitle;
2477 
2478 					sal_Bool bDocHasTitle = sal_False;
2479 					if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) )
2480 					{
2481             			DBG_ERRORFILE( "addHierGroup(): template of alien format" );
2482 						continue;
2483 					}
2484 
2485                     if ( aType.getLength() )
2486                         bUpdateType = sal_True;
2487                 }
2488 
2489                 pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL );
2490                 pData->setUpdateType( bUpdateType );
2491             }
2492         }
2493         catch ( Exception& ) {}
2494     }
2495 }
2496 
2497 //-----------------------------------------------------------------------------
2498 void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList,
2499                                           const OUString& rTitle,
2500 										  const OUString& rUITitle,
2501                                           const OUString& rOwnURL,
2502 										  sal_Bool bWriteableGroup )
2503 {
2504 	::rtl::OUString aTitle;
2505 
2506 	if ( !rUITitle.getLength() )
2507 	{
2508 		// reserved FS names that should not be used
2509     	if ( rTitle.compareToAscii( "wizard" ) == 0 )
2510         	return;
2511     	else if ( rTitle.compareToAscii( "internal" ) == 0 )
2512         	return;
2513 
2514 		aTitle = getLongName( rTitle );
2515 	}
2516 	else
2517 		aTitle = rUITitle;
2518 
2519 	if ( !aTitle.getLength() )
2520 		return;
2521 
2522     GroupData_Impl *pGroup = rList.First();
2523 
2524     while ( pGroup && pGroup->getTitle() != aTitle )
2525         pGroup = rList.Next();
2526 
2527     if ( !pGroup )
2528     {
2529         pGroup = new GroupData_Impl( aTitle );
2530         rList.Insert( pGroup );
2531     }
2532 
2533 	if ( bWriteableGroup )
2534 		pGroup->setTargetURL( rOwnURL );
2535 
2536     pGroup->setInUse();
2537 
2538     // now get the content of the Group
2539     Content                 aContent;
2540     uno::Reference< XResultSet > xResultSet;
2541     Sequence< OUString >    aProps(1);
2542     aProps[0] = OUString::createFromAscii( TITLE );
2543 
2544     try
2545     {
2546         // this method is only used during checking of the available template-folders
2547         // that should happen quietly
2548         uno::Reference< XCommandEnvironment > aQuietEnv;
2549         aContent = Content( rOwnURL, aQuietEnv );
2550         ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2551         xResultSet = aContent.createCursor( aProps, eInclude );
2552     }
2553     catch ( Exception& ) {}
2554 
2555     if ( xResultSet.is() )
2556     {
2557         uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2558         uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2559 
2560         try
2561         {
2562             while ( xResultSet->next() )
2563             {
2564                 OUString aChildTitle( xRow->getString( 1 ) );
2565                 OUString aTargetURL = xContentAccess->queryContentIdentifierString();
2566                 OUString aType;
2567                 OUString aHierURL;
2568 
2569                 if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0
2570 				  || aChildTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "groupuinames.xml" ) ) )
2571                     continue;
2572 
2573 				// only StarOffice templates are accepted
2574 				sal_Bool bDocHasTitle = sal_False;
2575                 if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) )
2576 					continue;
2577 
2578                 pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL );
2579             }
2580         }
2581         catch ( Exception& ) {}
2582     }
2583 }
2584 
2585 // -----------------------------------------------------------------------
2586 void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList,
2587                                                Content &rContent,
2588                                                sal_Bool bHierarchy,
2589 											   sal_Bool bWriteableContent )
2590 {
2591     OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier();
2592 
2593     // when scanning the file system, we have to add the 'standard' group, too
2594     if ( ! bHierarchy )
2595     {
2596 		OUString aUIStdTitle = getLongName( OUString( RTL_CONSTASCII_USTRINGPARAM( STANDARD_FOLDER ) ) );
2597         addFsysGroup( rList, ::rtl::OUString(), aUIStdTitle, aTargetURL, bWriteableContent );
2598     }
2599 
2600 	// search for predefined UI names
2601     INetURLObject aLayerObj( aTargetURL );
2602 
2603 	// TODO/LATER: Use hashmap in future
2604 	uno::Sequence< beans::StringPair > aUINames;
2605 	if ( !bHierarchy )
2606 		aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) );
2607 
2608     uno::Reference< XResultSet > xResultSet;
2609     Sequence< OUString > aProps(1);
2610     aProps[0] = OUString::createFromAscii( TITLE );
2611 
2612     try
2613     {
2614         ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
2615         xResultSet = rContent.createCursor( aProps, eInclude );
2616     }
2617     catch ( Exception& ) {}
2618 
2619     if ( xResultSet.is() )
2620     {
2621         uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2622         uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2623 
2624         try
2625         {
2626             while ( xResultSet->next() )
2627             {
2628 				// TODO/LATER: clarify the encoding of the Title
2629                 OUString aTitle( xRow->getString( 1 ) );
2630                 OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() );
2631 
2632                 if ( bHierarchy )
2633                     addHierGroup( rList, aTitle, aTargetSubfolderURL );
2634                 else
2635 				{
2636 					::rtl::OUString aUITitle;
2637 					for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ )
2638 						if ( aUINames[nInd].First.equals( aTitle ) )
2639 						{
2640 							aUITitle = aUINames[nInd].Second;
2641 							break;
2642 						}
2643 
2644                     addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent );
2645 				}
2646             }
2647         }
2648         catch ( Exception& ) {}
2649     }
2650 }
2651 
2652 //-----------------------------------------------------------------------------
2653 void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData )
2654 {
2655     Content aTemplate;
2656 
2657     if ( Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2658     {
2659         removeContent( aTemplate );
2660     }
2661 }
2662 
2663 //-----------------------------------------------------------------------------
2664 void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup,
2665                                             DocTemplates_EntryData_Impl *pData )
2666 {
2667     Content aGroup, aTemplate;
2668 
2669     if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2670         return;
2671 
2672     // Check, if there's a template with the given name in this group
2673     // Return if there is already a template
2674     INetURLObject aGroupObj( pGroup->getHierarchyURL() );
2675 
2676     aGroupObj.insertName( pData->getTitle(), false,
2677                       INetURLObject::LAST_SEGMENT, true,
2678                       INetURLObject::ENCODE_ALL );
2679 
2680     OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2681 
2682     if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2683         return;
2684 
2685     addEntry( aGroup, pData->getTitle(),
2686               pData->getTargetURL(),
2687               pData->getType() );
2688 }
2689 
2690 //-----------------------------------------------------------------------------
2691 void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData )
2692 {
2693     Content aTemplate;
2694 
2695     if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2696         return;
2697 
2698     OUString aPropName;
2699 
2700     if ( pData->getUpdateType() )
2701     {
2702         aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) );
2703         setProperty( aTemplate, aPropName, makeAny( pData->getType() ) );
2704     }
2705 
2706     if ( pData->getUpdateLink() )
2707     {
2708         aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
2709         setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) );
2710     }
2711 }
2712 
2713 //-----------------------------------------------------------------------------
2714 void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup )
2715 {
2716     OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
2717     Content aGroup;
2718 
2719     INetURLObject aNewGroupObj( maRootURL );
2720     aNewGroupObj.insertName( pGroup->getTitle(), false,
2721           INetURLObject::LAST_SEGMENT, true,
2722           INetURLObject::ENCODE_ALL );
2723 
2724     OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2725 
2726     if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) )
2727     {
2728         setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) );
2729         pGroup->setHierarchyURL( aNewGroupURL );
2730 
2731         sal_uIntPtr nCount = pGroup->count();
2732         for ( sal_uIntPtr i=0; i<nCount; i++ )
2733         {
2734             DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
2735             addToHierarchy( pGroup, pData ); // add entry to hierarchy
2736         }
2737     }
2738 }
2739 
2740 //-----------------------------------------------------------------------------
2741 void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup )
2742 {
2743     Content aGroup;
2744 
2745     if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2746     {
2747         removeContent( aGroup );
2748     }
2749 }
2750 
2751 // -----------------------------------------------------------------------
2752 // -----------------------------------------------------------------------
2753 // -----------------------------------------------------------------------
2754 GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2755 {
2756     maTitle = rTitle;
2757     mbInUse = sal_False;
2758     mbInHierarchy = sal_False;
2759 }
2760 
2761 // -----------------------------------------------------------------------
2762 GroupData_Impl::~GroupData_Impl()
2763 {
2764     DocTemplates_EntryData_Impl *pData = maEntries.First();
2765     while ( pData )
2766     {
2767         delete pData;
2768         pData = maEntries.Next();
2769     }
2770 }
2771 
2772 // -----------------------------------------------------------------------
2773 DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle,
2774                                           const OUString& rTargetURL,
2775                                           const OUString& rType,
2776                                           const OUString& rHierURL )
2777 {
2778     DocTemplates_EntryData_Impl *pData = maEntries.First();
2779 
2780     while ( pData && pData->getTitle() != rTitle )
2781         pData = maEntries.Next();
2782 
2783     if ( !pData )
2784     {
2785         pData = new DocTemplates_EntryData_Impl( rTitle );
2786         pData->setTargetURL( rTargetURL );
2787         pData->setType( rType );
2788         if ( rHierURL.getLength() )
2789         {
2790             pData->setHierarchyURL( rHierURL );
2791             pData->setHierarchy( sal_True );
2792         }
2793         maEntries.Insert( pData );
2794     }
2795     else
2796     {
2797         if ( rHierURL.getLength() )
2798         {
2799             pData->setHierarchyURL( rHierURL );
2800             pData->setHierarchy( sal_True );
2801         }
2802 
2803 		if ( pData->getInHierarchy() )
2804 			pData->setInUse();
2805 
2806         if ( rTargetURL != pData->getTargetURL() )
2807         {
2808             pData->setTargetURL( rTargetURL );
2809             pData->setUpdateLink( sal_True );
2810         }
2811     }
2812 
2813     return pData;
2814 }
2815 
2816 // -----------------------------------------------------------------------
2817 // -----------------------------------------------------------------------
2818 // -----------------------------------------------------------------------
2819 DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle )
2820 {
2821     maTitle         = rTitle;
2822     mbInUse         = sal_False;
2823     mbInHierarchy   = sal_False;
2824     mbUpdateType    = sal_False;
2825     mbUpdateLink    = sal_False;
2826 }
2827 
2828 // -----------------------------------------------------------------------
2829 SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory )
2830 : mxFactory( xFactory )
2831 {
2832 }
2833 
2834 // -----------------------------------------------------------------------
2835 SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2836 {
2837 }
2838 
2839 // -----------------------------------------------------------------------
2840 void SfxURLRelocator_Impl::initOfficeInstDirs()
2841 {
2842     if ( !mxOfficeInstDirs.is() )
2843     {
2844         osl::MutexGuard aGuard( maMutex );
2845         if ( !mxOfficeInstDirs.is() )
2846         {
2847             OSL_ENSURE( mxFactory.is(), "No service manager!" );
2848 
2849             uno::Reference< XComponentContext > xCtx;
2850             uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY );
2851             if ( xPropSet.is() )
2852             {
2853                 xPropSet->getPropertyValue(
2854                     rtl::OUString(
2855                         RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) )
2856                 >>= xCtx;
2857             }
2858 
2859             OSL_ENSURE( xCtx.is(),
2860                         "Unable to obtain component context from "
2861                         "service manager!" );
2862 
2863             if ( xCtx.is() )
2864             {
2865                 xCtx->getValueByName(
2866                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
2867                         "/singletons/"
2868                         "com.sun.star.util.theOfficeInstallationDirectories" ) ) )
2869                 >>= mxOfficeInstDirs;
2870             }
2871 
2872             OSL_ENSURE( mxOfficeInstDirs.is(),
2873                         "Unable to obtain office installation directory "
2874                         "singleton!" );
2875         }
2876     }
2877 }
2878 
2879 // -----------------------------------------------------------------------
2880 void SfxURLRelocator_Impl::implExpandURL( ::rtl::OUString& io_url )
2881 {
2882     const INetURLObject aParser( io_url );
2883     if ( aParser.GetProtocol() != INET_PROT_VND_SUN_STAR_EXPAND )
2884         return;
2885 
2886     io_url = aParser.GetURLPath( INetURLObject::DECODE_WITH_CHARSET );
2887     try
2888     {
2889         if ( !mxMacroExpander.is() )
2890         {
2891             ::comphelper::ComponentContext aContext( mxFactory );
2892             mxMacroExpander.set( aContext.getSingleton( "com.sun.star.util.theMacroExpander" ), UNO_QUERY_THROW );
2893         }
2894         io_url = mxMacroExpander->expandMacros( io_url );
2895     }
2896     catch( const Exception& )
2897     {
2898     	DBG_UNHANDLED_EXCEPTION();
2899     }
2900 }
2901 
2902 // -----------------------------------------------------------------------
2903 void SfxURLRelocator_Impl::makeRelocatableURL( rtl::OUString & rURL )
2904 {
2905     if ( rURL.getLength() > 0 )
2906     {
2907         initOfficeInstDirs();
2908         implExpandURL( rURL );
2909         rURL = mxOfficeInstDirs->makeRelocatableURL( rURL );
2910     }
2911 }
2912 
2913 // -----------------------------------------------------------------------
2914 void SfxURLRelocator_Impl::makeAbsoluteURL( rtl::OUString & rURL )
2915 {
2916     if ( rURL.getLength() > 0 )
2917     {
2918         initOfficeInstDirs();
2919         implExpandURL( rURL );
2920         rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL );
2921     }
2922 }
2923 
2924 
2925