xref: /AOO41X/main/sfx2/source/doc/doctemplates.cxx (revision d119d52d53d0b2180f2ae51341d882123be2af2b)
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:
TplTaskEnvironment(const uno::Reference<task::XInteractionHandler> & rxInteractionHandler)166     TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler )
167                                 : m_xInteractionHandler( rxInteractionHandler )
168                             {}
169 
getInteractionHandler()170     virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException)
171     { return m_xInteractionHandler; }
172 
getProgressHandler()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 
init()274     sal_Bool                    init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; }
getContent()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();
finished()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 
setInUse()335     void                setInUse() { mbInUse = sal_True; }
setHierarchy(sal_Bool bInHierarchy)336     void                setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
setUpdateLink(sal_Bool bUpdateLink)337     void                setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; }
setUpdateType(sal_Bool bUpdateType)338     void                setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; }
339 
getInUse() const340     sal_Bool            getInUse() const { return mbInUse; }
getInHierarchy() const341     sal_Bool            getInHierarchy() const { return mbInHierarchy; }
getUpdateLink() const342     sal_Bool            getUpdateLink() const { return mbUpdateLink; }
getUpdateType() const343     sal_Bool            getUpdateType() const { return mbUpdateType; }
344 
getHierarchyURL() const345     const OUString&     getHierarchyURL() const { return maHierarchyURL; }
getTargetURL() const346     const OUString&     getTargetURL() const { return maTargetURL; }
getTitle() const347     const OUString&     getTitle() const { return maTitle; }
getType() const348     const OUString&     getType() const { return maType; }
349 
setHierarchyURL(const OUString & rURL)350     void                setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
setTargetURL(const OUString & rURL)351     void                setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
setType(const OUString & rType)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 
setInUse()371     void                setInUse() { mbInUse = sal_True; }
setHierarchy(sal_Bool bInHierarchy)372     void                setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
setHierarchyURL(const OUString & rURL)373     void                setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
setTargetURL(const OUString & rURL)374     void                setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
375 
getInUse()376     sal_Bool            getInUse() { return mbInUse; }
getInHierarchy()377     sal_Bool            getInHierarchy() { return mbInHierarchy; }
getHierarchyURL() const378     const OUString&     getHierarchyURL() const { return maHierarchyURL; }
getTargetURL() const379     const OUString&     getTargetURL() const { return maTargetURL; }
getTitle() const380     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 );
count()386     sal_uIntPtr               count() { return maEntries.Count(); }
getEntry(sal_uIntPtr nPos)387     DocTemplates_EntryData_Impl*     getEntry( sal_uIntPtr nPos ) { return maEntries.GetObject( nPos ); }
388 };
389 
DECLARE_LIST(GroupList_Impl,GroupData_Impl *)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 //-----------------------------------------------------------------------------
getDefaultLocale()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 // -----------------------------------------------------------------------
readFolderList()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 // -----------------------------------------------------------------------
getLongName(const OUString & rShortName)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 //-----------------------------------------------------------------------------
getDirList()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 //-----------------------------------------------------------------------------
needsUpdate()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 // -----------------------------------------------------------------------
setTitleForURL(const OUString & rURL,const OUString & aTitle)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 // -----------------------------------------------------------------------
getTitleFromURL(const OUString & rURL,OUString & aTitle,OUString & aType,sal_Bool & bDocHasTitle)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 // -----------------------------------------------------------------------
addEntry(Content & rParentFolder,const OUString & rTitle,const OUString & rTargetURL,const OUString & rType)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 // -----------------------------------------------------------------------
createFolder(const OUString & rNewFolderURL,sal_Bool bCreateParent,sal_Bool bFsysFolder,Content & rNewFolder)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 // -----------------------------------------------------------------------
CreateNewUniqueFolderWithPrefix(const::rtl::OUString & aPath,const::rtl::OUString & aPrefix,::rtl::OUString & aNewFolderName,::rtl::OUString & aNewFolderURL,Content & aNewFolder)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 // -----------------------------------------------------------------------
CreateNewUniqueFileWithPrefix(const::rtl::OUString & aPath,const::rtl::OUString & aPrefix,const::rtl::OUString & aExt)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 // -----------------------------------------------------------------------
removeContent(Content & rContent)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 // -----------------------------------------------------------------------
removeContent(const OUString & rContentURL)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 // -----------------------------------------------------------------------
setProperty(Content & rContent,const OUString & rPropName,const Any & rPropValue)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 // -----------------------------------------------------------------------
getProperty(Content & rContent,const OUString & rPropName,Any & rPropValue)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
propertyCanContainOfficeDir(const rtl::OUString & rPropName)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 
SfxDocTplService_Impl(uno::Reference<XMultiServiceFactory> xFactory)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 //-----------------------------------------------------------------------------
~SfxDocTplService_Impl()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 //-----------------------------------------------------------------------------
getLocale()1158 Locale SfxDocTplService_Impl::getLocale()
1159 {
1160     ::osl::MutexGuard aGuard( maMutex );
1161 
1162     if ( !mbLocaleSet )
1163         getDefaultLocale();
1164 
1165     return maLocale;
1166 }
1167 
1168 //-----------------------------------------------------------------------------
setLocale(const Locale & rLocale)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 //-----------------------------------------------------------------------------
update(sal_Bool bUpdateNow)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 //-----------------------------------------------------------------------------
doUpdate()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 //-----------------------------------------------------------------------------
ReadUINamesForTemplateDir_Impl(const::rtl::OUString & aUserPath)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 //-----------------------------------------------------------------------------
UpdateUINamesForTemplateDir_Impl(const::rtl::OUString & aUserPath,const::rtl::OUString & aGroupName,const::rtl::OUString & aNewFolderName)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 //-----------------------------------------------------------------------------
ReplaceUINamesForTemplateDir_Impl(const::rtl::OUString & aUserPath,const::rtl::OUString & aDefaultFsysGroupName,const::rtl::OUString & aOldGroupName,const::rtl::OUString & aNewGroupName)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 //-----------------------------------------------------------------------------
RemoveUINamesForTemplateDir_Impl(const::rtl::OUString & aUserPath,const::rtl::OUString & aGroupName)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 //-----------------------------------------------------------------------------
WriteUINamesForTemplateDir_Impl(const::rtl::OUString & aUserPath,const uno::Sequence<beans::StringPair> & aUINames)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 //-----------------------------------------------------------------------------
CreateNewGroupFsys(const::rtl::OUString & rGroupName,Content & aGroup)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 //-----------------------------------------------------------------------------
addGroup(const OUString & rGroupName)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 //-----------------------------------------------------------------------------
removeGroup(const OUString & rGroupName)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 //-----------------------------------------------------------------------------
renameGroup(const OUString & rOldName,const OUString & rNewName)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 //-----------------------------------------------------------------------------
storeTemplate(const OUString & rGroupName,const OUString & rTemplateName,const uno::Reference<XSTORABLE> & rStorable)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 //-----------------------------------------------------------------------------
addTemplate(const OUString & rGroupName,const OUString & rTemplateName,const OUString & rSourceURL)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 //-----------------------------------------------------------------------------
removeTemplate(const OUString & rGroupName,const OUString & rTemplateName)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 //-----------------------------------------------------------------------------
renameTemplate(const OUString & rGroupName,const OUString & rOldName,const OUString & rNewName)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 
SFX_IMPL_XSERVICEINFO(SfxDocTplService,TEMPLATE_SERVICE_NAME,TEMPLATE_IMPLEMENTATION_NAME)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 
~SfxDocTplService()2234 SfxDocTplService::~SfxDocTplService()
2235 {
2236     delete pImp;
2237 }
2238 
2239 //-----------------------------------------------------------------------------
2240 //--- XLocalizable ---
2241 //-----------------------------------------------------------------------------
2242 
getLocale()2243 Locale SAL_CALL SfxDocTplService::getLocale()
2244     throw( RUNTIMEEXCEPTION )
2245 {
2246     return pImp->getLocale();
2247 }
2248 
2249 //-----------------------------------------------------------------------------
2250 
setLocale(const Locale & rLocale)2251 void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale )
2252     throw( RUNTIMEEXCEPTION )
2253 {
2254     pImp->setLocale( rLocale );
2255 }
2256 
2257 //-----------------------------------------------------------------------------
2258 //--- XDocumentTemplates ---
2259 //-----------------------------------------------------------------------------
getContent()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 //-----------------------------------------------------------------------------
storeTemplate(const OUString & GroupName,const OUString & TemplateName,const uno::Reference<XSTORABLE> & Storable)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 //-----------------------------------------------------------------------------
addTemplate(const OUString & rGroupName,const OUString & rTemplateName,const OUString & rSourceURL)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 //-----------------------------------------------------------------------------
removeTemplate(const OUString & rGroupName,const OUString & rTemplateName)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 //-----------------------------------------------------------------------------
renameTemplate(const OUString & rGroupName,const OUString & rOldName,const OUString & rNewName)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 //-----------------------------------------------------------------------------
addGroup(const OUString & rGroupName)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 //-----------------------------------------------------------------------------
removeGroup(const OUString & rGroupName)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 //-----------------------------------------------------------------------------
renameGroup(const OUString & rOldName,const OUString & rNewName)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 //-----------------------------------------------------------------------------
update()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 
Updater_Impl(SfxDocTplService_Impl * pTemplates)2365 Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2366 {
2367     mpDocTemplates = pTemplates;
2368 }
2369 
2370 //------------------------------------------------------------------------
~Updater_Impl()2371 Updater_Impl::~Updater_Impl()
2372 {
2373 }
2374 
2375 //------------------------------------------------------------------------
run()2376 void SAL_CALL Updater_Impl::run()
2377 {
2378     mpDocTemplates->doUpdate();
2379 }
2380 
2381 //------------------------------------------------------------------------
onTerminated()2382 void SAL_CALL Updater_Impl::onTerminated()
2383 {
2384     mpDocTemplates->finished();
2385     delete this;
2386 }
2387 
2388 //-----------------------------------------------------------------------------
2389 //-----------------------------------------------------------------------------
2390 //-----------------------------------------------------------------------------
WaitWindow_Impl()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 //-----------------------------------------------------------------------------
~WaitWindow_Impl()2409 WaitWindow_Impl::~WaitWindow_Impl()
2410 {
2411     Hide();
2412 }
2413 
2414 //-----------------------------------------------------------------------------
Paint(const Rectangle &)2415 void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ )
2416 {
2417     DrawText( _aRect, _aText, _nTextStyle );
2418 }
2419 
2420 //-----------------------------------------------------------------------------
2421 //-----------------------------------------------------------------------------
2422 //-----------------------------------------------------------------------------
addHierGroup(GroupList_Impl & rList,const OUString & rTitle,const OUString & rOwnURL)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 //-----------------------------------------------------------------------------
addFsysGroup(GroupList_Impl & rList,const OUString & rTitle,const OUString & rUITitle,const OUString & rOwnURL,sal_Bool bWriteableGroup)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 // -----------------------------------------------------------------------
createFromContent(GroupList_Impl & rList,Content & rContent,sal_Bool bHierarchy,sal_Bool bWriteableContent)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 //-----------------------------------------------------------------------------
removeFromHierarchy(DocTemplates_EntryData_Impl * pData)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 //-----------------------------------------------------------------------------
addToHierarchy(GroupData_Impl * pGroup,DocTemplates_EntryData_Impl * pData)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 //-----------------------------------------------------------------------------
updateData(DocTemplates_EntryData_Impl * pData)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 //-----------------------------------------------------------------------------
addGroupToHierarchy(GroupData_Impl * pGroup)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 //-----------------------------------------------------------------------------
removeFromHierarchy(GroupData_Impl * pGroup)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 // -----------------------------------------------------------------------
GroupData_Impl(const OUString & rTitle)2750 GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2751 {
2752     maTitle = rTitle;
2753     mbInUse = sal_False;
2754     mbInHierarchy = sal_False;
2755 }
2756 
2757 // -----------------------------------------------------------------------
~GroupData_Impl()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 // -----------------------------------------------------------------------
addEntry(const OUString & rTitle,const OUString & rTargetURL,const OUString & rType,const OUString & rHierURL)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 // -----------------------------------------------------------------------
DocTemplates_EntryData_Impl(const OUString & rTitle)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 // -----------------------------------------------------------------------
SfxURLRelocator_Impl(uno::Reference<XMultiServiceFactory> xFactory)2825 SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory )
2826 : mxFactory( xFactory )
2827 {
2828 }
2829 
2830 // -----------------------------------------------------------------------
~SfxURLRelocator_Impl()2831 SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2832 {
2833 }
2834 
2835 // -----------------------------------------------------------------------
initOfficeInstDirs()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 // -----------------------------------------------------------------------
implExpandURL(::rtl::OUString & io_url)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 // -----------------------------------------------------------------------
makeRelocatableURL(rtl::OUString & rURL)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 // -----------------------------------------------------------------------
makeAbsoluteURL(rtl::OUString & rURL)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