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()
171 { return m_xInteractionHandler; }
172
getProgressHandler()173 virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler()
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, whether 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 relocatable office installation, the path to the
1021 // office installation 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, whether 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 relocatable office installation, the path to the
1082 // office installation 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, whether 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, whether 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, whether 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, whether 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, whether 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 {
2245 return pImp->getLocale();
2246 }
2247
2248 //-----------------------------------------------------------------------------
2249
setLocale(const Locale & rLocale)2250 void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale )
2251 {
2252 pImp->setLocale( rLocale );
2253 }
2254
2255 //-----------------------------------------------------------------------------
2256 //--- XDocumentTemplates ---
2257 //-----------------------------------------------------------------------------
getContent()2258 uno::Reference< XCONTENT > SAL_CALL SfxDocTplService::getContent()
2259 {
2260 if ( pImp->init() )
2261 return pImp->getContent().get();
2262 else
2263 return NULL;
2264 }
2265
2266 //-----------------------------------------------------------------------------
storeTemplate(const OUString & GroupName,const OUString & TemplateName,const uno::Reference<XSTORABLE> & Storable)2267 sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName,
2268 const OUString& TemplateName,
2269 const uno::Reference< XSTORABLE >& Storable )
2270 {
2271 if ( pImp->init() )
2272 return pImp->storeTemplate( GroupName, TemplateName, Storable );
2273 else
2274 return sal_False;
2275 }
2276
2277 //-----------------------------------------------------------------------------
addTemplate(const OUString & rGroupName,const OUString & rTemplateName,const OUString & rSourceURL)2278 sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName,
2279 const OUString& rTemplateName,
2280 const OUString& rSourceURL )
2281 {
2282 if ( pImp->init() )
2283 return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL );
2284 else
2285 return sal_False;
2286 }
2287
2288 //-----------------------------------------------------------------------------
removeTemplate(const OUString & rGroupName,const OUString & rTemplateName)2289 sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName,
2290 const OUString& rTemplateName )
2291 {
2292 if ( pImp->init() )
2293 return pImp->removeTemplate( rGroupName, rTemplateName );
2294 else
2295 return sal_False;
2296 }
2297
2298 //-----------------------------------------------------------------------------
renameTemplate(const OUString & rGroupName,const OUString & rOldName,const OUString & rNewName)2299 sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName,
2300 const OUString& rOldName,
2301 const OUString& rNewName )
2302 {
2303 if ( rOldName == rNewName )
2304 return sal_True;
2305
2306 if ( pImp->init() )
2307 return pImp->renameTemplate( rGroupName, rOldName, rNewName );
2308 else
2309 return sal_False;
2310 }
2311
2312 //-----------------------------------------------------------------------------
addGroup(const OUString & rGroupName)2313 sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName )
2314 {
2315 if ( pImp->init() )
2316 return pImp->addGroup( rGroupName );
2317 else
2318 return sal_False;
2319 }
2320
2321 //-----------------------------------------------------------------------------
removeGroup(const OUString & rGroupName)2322 sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName )
2323 {
2324 if ( pImp->init() )
2325 return pImp->removeGroup( rGroupName );
2326 else
2327 return sal_False;
2328 }
2329
2330 //-----------------------------------------------------------------------------
renameGroup(const OUString & rOldName,const OUString & rNewName)2331 sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName,
2332 const OUString& rNewName )
2333 {
2334 if ( rOldName == rNewName )
2335 return sal_True;
2336
2337 if ( pImp->init() )
2338 return pImp->renameGroup( rOldName, rNewName );
2339 else
2340 return sal_False;
2341 }
2342
2343 //-----------------------------------------------------------------------------
update()2344 void SAL_CALL SfxDocTplService::update()
2345 {
2346 if ( pImp->init() )
2347 pImp->update( sal_True );
2348 }
2349
2350 //-----------------------------------------------------------------------------
2351 //-----------------------------------------------------------------------------
2352 //------------------------------------------------------------------------
2353
Updater_Impl(SfxDocTplService_Impl * pTemplates)2354 Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2355 {
2356 mpDocTemplates = pTemplates;
2357 }
2358
2359 //------------------------------------------------------------------------
~Updater_Impl()2360 Updater_Impl::~Updater_Impl()
2361 {
2362 }
2363
2364 //------------------------------------------------------------------------
run()2365 void SAL_CALL Updater_Impl::run()
2366 {
2367 mpDocTemplates->doUpdate();
2368 }
2369
2370 //------------------------------------------------------------------------
onTerminated()2371 void SAL_CALL Updater_Impl::onTerminated()
2372 {
2373 mpDocTemplates->finished();
2374 delete this;
2375 }
2376
2377 //-----------------------------------------------------------------------------
2378 //-----------------------------------------------------------------------------
2379 //-----------------------------------------------------------------------------
WaitWindow_Impl()2380 WaitWindow_Impl::WaitWindow_Impl()
2381 : WorkWindow( NULL, WB_BORDER | WB_3DLOOK )
2382 {
2383 Rectangle aRect = Rectangle( 0, 0, 300, 30000 );
2384 _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE;
2385 _aText = String( SfxResId( RID_CNT_STR_WAITING ) );
2386 _aRect = GetTextRect( aRect, _aText, _nTextStyle );
2387 aRect = _aRect;
2388 aRect.Right() += 2*X_OFFSET;
2389 aRect.Bottom() += 2*Y_OFFSET;
2390 _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) );
2391 SetOutputSizePixel( aRect.GetSize() );
2392 Show();
2393 Update();
2394 Flush();
2395 }
2396
2397 //-----------------------------------------------------------------------------
~WaitWindow_Impl()2398 WaitWindow_Impl::~WaitWindow_Impl()
2399 {
2400 Hide();
2401 }
2402
2403 //-----------------------------------------------------------------------------
Paint(const Rectangle &)2404 void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ )
2405 {
2406 DrawText( _aRect, _aText, _nTextStyle );
2407 }
2408
2409 //-----------------------------------------------------------------------------
2410 //-----------------------------------------------------------------------------
2411 //-----------------------------------------------------------------------------
addHierGroup(GroupList_Impl & rList,const OUString & rTitle,const OUString & rOwnURL)2412 void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList,
2413 const OUString& rTitle,
2414 const OUString& rOwnURL )
2415 {
2416 // now get the content of the Group
2417 Content aContent;
2418 uno::Reference< XResultSet > xResultSet;
2419 Sequence< OUString > aProps(3);
2420
2421 aProps[0] = OUString::createFromAscii( TITLE );
2422 aProps[1] = OUString::createFromAscii( TARGET_URL );
2423 aProps[2] = OUString::createFromAscii( PROPERTY_TYPE );
2424
2425 try
2426 {
2427 aContent = Content( rOwnURL, maCmdEnv );
2428 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2429 xResultSet = aContent.createCursor( aProps, eInclude );
2430 }
2431 catch ( ContentCreationException& )
2432 {
2433 DBG_ERRORFILE( "addHierGroup: ContentCreationException" );
2434 }
2435 catch ( Exception& ) {}
2436
2437 if ( xResultSet.is() )
2438 {
2439 GroupData_Impl *pGroup = new GroupData_Impl( rTitle );
2440 pGroup->setHierarchy( sal_True );
2441 pGroup->setHierarchyURL( rOwnURL );
2442 rList.Insert( pGroup );
2443
2444 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2445 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2446
2447 try
2448 {
2449 while ( xResultSet->next() )
2450 {
2451 sal_Bool bUpdateType = sal_False;
2452 DocTemplates_EntryData_Impl *pData;
2453
2454 OUString aTitle( xRow->getString( 1 ) );
2455 OUString aTargetDir( xRow->getString( 2 ) );
2456 OUString aType( xRow->getString( 3 ) );
2457 OUString aHierURL = xContentAccess->queryContentIdentifierString();
2458
2459 if ( !aType.getLength() )
2460 {
2461 OUString aTmpTitle;
2462
2463 sal_Bool bDocHasTitle = sal_False;
2464 if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) )
2465 {
2466 DBG_ERRORFILE( "addHierGroup(): template of alien format" );
2467 continue;
2468 }
2469
2470 if ( aType.getLength() )
2471 bUpdateType = sal_True;
2472 }
2473
2474 pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL );
2475 pData->setUpdateType( bUpdateType );
2476 }
2477 }
2478 catch ( Exception& ) {}
2479 }
2480 }
2481
2482 //-----------------------------------------------------------------------------
addFsysGroup(GroupList_Impl & rList,const OUString & rTitle,const OUString & rUITitle,const OUString & rOwnURL,sal_Bool bWriteableGroup)2483 void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList,
2484 const OUString& rTitle,
2485 const OUString& rUITitle,
2486 const OUString& rOwnURL,
2487 sal_Bool bWriteableGroup )
2488 {
2489 ::rtl::OUString aTitle;
2490
2491 if ( !rUITitle.getLength() )
2492 {
2493 // reserved FS names that should not be used
2494 if ( rTitle.compareToAscii( "wizard" ) == 0 )
2495 return;
2496 else if ( rTitle.compareToAscii( "internal" ) == 0 )
2497 return;
2498
2499 aTitle = getLongName( rTitle );
2500 }
2501 else
2502 aTitle = rUITitle;
2503
2504 if ( !aTitle.getLength() )
2505 return;
2506
2507 GroupData_Impl *pGroup = rList.First();
2508
2509 while ( pGroup && pGroup->getTitle() != aTitle )
2510 pGroup = rList.Next();
2511
2512 if ( !pGroup )
2513 {
2514 pGroup = new GroupData_Impl( aTitle );
2515 rList.Insert( pGroup );
2516 }
2517
2518 if ( bWriteableGroup )
2519 pGroup->setTargetURL( rOwnURL );
2520
2521 pGroup->setInUse();
2522
2523 // now get the content of the Group
2524 Content aContent;
2525 uno::Reference< XResultSet > xResultSet;
2526 Sequence< OUString > aProps(1);
2527 aProps[0] = OUString::createFromAscii( TITLE );
2528
2529 try
2530 {
2531 // this method is only used during checking of the available template-folders
2532 // that should happen quietly
2533 uno::Reference< XCommandEnvironment > aQuietEnv;
2534 aContent = Content( rOwnURL, aQuietEnv );
2535 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2536 xResultSet = aContent.createCursor( aProps, eInclude );
2537 }
2538 catch ( Exception& ) {}
2539
2540 if ( xResultSet.is() )
2541 {
2542 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2543 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2544
2545 try
2546 {
2547 while ( xResultSet->next() )
2548 {
2549 OUString aChildTitle( xRow->getString( 1 ) );
2550 OUString aTargetURL = xContentAccess->queryContentIdentifierString();
2551 OUString aType;
2552 OUString aHierURL;
2553
2554 if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0
2555 || aChildTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "groupuinames.xml" ) ) )
2556 continue;
2557
2558 // only StarOffice templates are accepted
2559 sal_Bool bDocHasTitle = sal_False;
2560 if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) )
2561 continue;
2562
2563 pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL );
2564 }
2565 }
2566 catch ( Exception& ) {}
2567 }
2568 }
2569
2570 // -----------------------------------------------------------------------
createFromContent(GroupList_Impl & rList,Content & rContent,sal_Bool bHierarchy,sal_Bool bWriteableContent)2571 void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList,
2572 Content &rContent,
2573 sal_Bool bHierarchy,
2574 sal_Bool bWriteableContent )
2575 {
2576 OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier();
2577
2578 // when scanning the file system, we have to add the 'standard' group, too
2579 if ( ! bHierarchy )
2580 {
2581 OUString aUIStdTitle = getLongName( OUString( RTL_CONSTASCII_USTRINGPARAM( STANDARD_FOLDER ) ) );
2582 addFsysGroup( rList, ::rtl::OUString(), aUIStdTitle, aTargetURL, bWriteableContent );
2583 }
2584
2585 // search for predefined UI names
2586 INetURLObject aLayerObj( aTargetURL );
2587
2588 // TODO/LATER: Use hashmap in future
2589 uno::Sequence< beans::StringPair > aUINames;
2590 if ( !bHierarchy )
2591 aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) );
2592
2593 uno::Reference< XResultSet > xResultSet;
2594 Sequence< OUString > aProps(1);
2595 aProps[0] = OUString::createFromAscii( TITLE );
2596
2597 try
2598 {
2599 ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
2600 xResultSet = rContent.createCursor( aProps, eInclude );
2601 }
2602 catch ( Exception& ) {}
2603
2604 if ( xResultSet.is() )
2605 {
2606 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2607 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2608
2609 try
2610 {
2611 while ( xResultSet->next() )
2612 {
2613 // TODO/LATER: clarify the encoding of the Title
2614 OUString aTitle( xRow->getString( 1 ) );
2615 OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() );
2616
2617 if ( bHierarchy )
2618 addHierGroup( rList, aTitle, aTargetSubfolderURL );
2619 else
2620 {
2621 ::rtl::OUString aUITitle;
2622 for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ )
2623 if ( aUINames[nInd].First.equals( aTitle ) )
2624 {
2625 aUITitle = aUINames[nInd].Second;
2626 break;
2627 }
2628
2629 addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent );
2630 }
2631 }
2632 }
2633 catch ( Exception& ) {}
2634 }
2635 }
2636
2637 //-----------------------------------------------------------------------------
removeFromHierarchy(DocTemplates_EntryData_Impl * pData)2638 void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData )
2639 {
2640 Content aTemplate;
2641
2642 if ( Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2643 {
2644 removeContent( aTemplate );
2645 }
2646 }
2647
2648 //-----------------------------------------------------------------------------
addToHierarchy(GroupData_Impl * pGroup,DocTemplates_EntryData_Impl * pData)2649 void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup,
2650 DocTemplates_EntryData_Impl *pData )
2651 {
2652 Content aGroup, aTemplate;
2653
2654 if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2655 return;
2656
2657 // Check, if there's a template with the given name in this group
2658 // Return if there is already a template
2659 INetURLObject aGroupObj( pGroup->getHierarchyURL() );
2660
2661 aGroupObj.insertName( pData->getTitle(), false,
2662 INetURLObject::LAST_SEGMENT, true,
2663 INetURLObject::ENCODE_ALL );
2664
2665 OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2666
2667 if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2668 return;
2669
2670 addEntry( aGroup, pData->getTitle(),
2671 pData->getTargetURL(),
2672 pData->getType() );
2673 }
2674
2675 //-----------------------------------------------------------------------------
updateData(DocTemplates_EntryData_Impl * pData)2676 void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData )
2677 {
2678 Content aTemplate;
2679
2680 if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2681 return;
2682
2683 OUString aPropName;
2684
2685 if ( pData->getUpdateType() )
2686 {
2687 aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) );
2688 setProperty( aTemplate, aPropName, makeAny( pData->getType() ) );
2689 }
2690
2691 if ( pData->getUpdateLink() )
2692 {
2693 aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) );
2694 setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) );
2695 }
2696 }
2697
2698 //-----------------------------------------------------------------------------
addGroupToHierarchy(GroupData_Impl * pGroup)2699 void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup )
2700 {
2701 OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) );
2702 Content aGroup;
2703
2704 INetURLObject aNewGroupObj( maRootURL );
2705 aNewGroupObj.insertName( pGroup->getTitle(), false,
2706 INetURLObject::LAST_SEGMENT, true,
2707 INetURLObject::ENCODE_ALL );
2708
2709 OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2710
2711 if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) )
2712 {
2713 setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) );
2714 pGroup->setHierarchyURL( aNewGroupURL );
2715
2716 sal_uIntPtr nCount = pGroup->count();
2717 for ( sal_uIntPtr i=0; i<nCount; i++ )
2718 {
2719 DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
2720 addToHierarchy( pGroup, pData ); // add entry to hierarchy
2721 }
2722 }
2723 }
2724
2725 //-----------------------------------------------------------------------------
removeFromHierarchy(GroupData_Impl * pGroup)2726 void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup )
2727 {
2728 Content aGroup;
2729
2730 if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2731 {
2732 removeContent( aGroup );
2733 }
2734 }
2735
2736 // -----------------------------------------------------------------------
2737 // -----------------------------------------------------------------------
2738 // -----------------------------------------------------------------------
GroupData_Impl(const OUString & rTitle)2739 GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2740 {
2741 maTitle = rTitle;
2742 mbInUse = sal_False;
2743 mbInHierarchy = sal_False;
2744 }
2745
2746 // -----------------------------------------------------------------------
~GroupData_Impl()2747 GroupData_Impl::~GroupData_Impl()
2748 {
2749 DocTemplates_EntryData_Impl *pData = maEntries.First();
2750 while ( pData )
2751 {
2752 delete pData;
2753 pData = maEntries.Next();
2754 }
2755 }
2756
2757 // -----------------------------------------------------------------------
addEntry(const OUString & rTitle,const OUString & rTargetURL,const OUString & rType,const OUString & rHierURL)2758 DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle,
2759 const OUString& rTargetURL,
2760 const OUString& rType,
2761 const OUString& rHierURL )
2762 {
2763 DocTemplates_EntryData_Impl *pData = maEntries.First();
2764
2765 while ( pData && pData->getTitle() != rTitle )
2766 pData = maEntries.Next();
2767
2768 if ( !pData )
2769 {
2770 pData = new DocTemplates_EntryData_Impl( rTitle );
2771 pData->setTargetURL( rTargetURL );
2772 pData->setType( rType );
2773 if ( rHierURL.getLength() )
2774 {
2775 pData->setHierarchyURL( rHierURL );
2776 pData->setHierarchy( sal_True );
2777 }
2778 maEntries.Insert( pData );
2779 }
2780 else
2781 {
2782 if ( rHierURL.getLength() )
2783 {
2784 pData->setHierarchyURL( rHierURL );
2785 pData->setHierarchy( sal_True );
2786 }
2787
2788 if ( pData->getInHierarchy() )
2789 pData->setInUse();
2790
2791 if ( rTargetURL != pData->getTargetURL() )
2792 {
2793 pData->setTargetURL( rTargetURL );
2794 pData->setUpdateLink( sal_True );
2795 }
2796 }
2797
2798 return pData;
2799 }
2800
2801 // -----------------------------------------------------------------------
2802 // -----------------------------------------------------------------------
2803 // -----------------------------------------------------------------------
DocTemplates_EntryData_Impl(const OUString & rTitle)2804 DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle )
2805 {
2806 maTitle = rTitle;
2807 mbInUse = sal_False;
2808 mbInHierarchy = sal_False;
2809 mbUpdateType = sal_False;
2810 mbUpdateLink = sal_False;
2811 }
2812
2813 // -----------------------------------------------------------------------
SfxURLRelocator_Impl(uno::Reference<XMultiServiceFactory> xFactory)2814 SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory )
2815 : mxFactory( xFactory )
2816 {
2817 }
2818
2819 // -----------------------------------------------------------------------
~SfxURLRelocator_Impl()2820 SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2821 {
2822 }
2823
2824 // -----------------------------------------------------------------------
initOfficeInstDirs()2825 void SfxURLRelocator_Impl::initOfficeInstDirs()
2826 {
2827 if ( !mxOfficeInstDirs.is() )
2828 {
2829 osl::MutexGuard aGuard( maMutex );
2830 if ( !mxOfficeInstDirs.is() )
2831 {
2832 OSL_ENSURE( mxFactory.is(), "No service manager!" );
2833
2834 uno::Reference< XComponentContext > xCtx;
2835 uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY );
2836 if ( xPropSet.is() )
2837 {
2838 xPropSet->getPropertyValue(
2839 rtl::OUString(
2840 RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) )
2841 >>= xCtx;
2842 }
2843
2844 OSL_ENSURE( xCtx.is(),
2845 "Unable to obtain component context from "
2846 "service manager!" );
2847
2848 if ( xCtx.is() )
2849 {
2850 xCtx->getValueByName(
2851 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
2852 "/singletons/"
2853 "com.sun.star.util.theOfficeInstallationDirectories" ) ) )
2854 >>= mxOfficeInstDirs;
2855 }
2856
2857 OSL_ENSURE( mxOfficeInstDirs.is(),
2858 "Unable to obtain office installation directory "
2859 "singleton!" );
2860 }
2861 }
2862 }
2863
2864 // -----------------------------------------------------------------------
implExpandURL(::rtl::OUString & io_url)2865 void SfxURLRelocator_Impl::implExpandURL( ::rtl::OUString& io_url )
2866 {
2867 const INetURLObject aParser( io_url );
2868 if ( aParser.GetProtocol() != INET_PROT_VND_SUN_STAR_EXPAND )
2869 return;
2870
2871 io_url = aParser.GetURLPath( INetURLObject::DECODE_WITH_CHARSET );
2872 try
2873 {
2874 if ( !mxMacroExpander.is() )
2875 {
2876 ::comphelper::ComponentContext aContext( mxFactory );
2877 mxMacroExpander.set( aContext.getSingleton( "com.sun.star.util.theMacroExpander" ), UNO_QUERY_THROW );
2878 }
2879 io_url = mxMacroExpander->expandMacros( io_url );
2880 }
2881 catch( const Exception& )
2882 {
2883 DBG_UNHANDLED_EXCEPTION();
2884 }
2885 }
2886
2887 // -----------------------------------------------------------------------
makeRelocatableURL(rtl::OUString & rURL)2888 void SfxURLRelocator_Impl::makeRelocatableURL( rtl::OUString & rURL )
2889 {
2890 if ( rURL.getLength() > 0 )
2891 {
2892 initOfficeInstDirs();
2893 implExpandURL( rURL );
2894 rURL = mxOfficeInstDirs->makeRelocatableURL( rURL );
2895 }
2896 }
2897
2898 // -----------------------------------------------------------------------
makeAbsoluteURL(rtl::OUString & rURL)2899 void SfxURLRelocator_Impl::makeAbsoluteURL( rtl::OUString & rURL )
2900 {
2901 if ( rURL.getLength() > 0 )
2902 {
2903 initOfficeInstDirs();
2904 implExpandURL( rURL );
2905 rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL );
2906 }
2907 }
2908