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