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