Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / doc / doctemplates.cxx
blobecceed91d4c6033c38fd4280a22f4745be29b9cc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "doctemplates.hxx"
31 #include <osl/mutex.hxx>
32 #include <tools/debug.hxx>
33 #include <tools/diagnose_ex.h>
34 #include <tools/urlobj.hxx>
35 #include <rtl/ustring.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <tools/resary.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <unotools/pathoptions.hxx>
41 #include <comphelper/componentcontext.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/sequenceashashmap.hxx>
44 #include <comphelper/string.hxx>
45 #include <com/sun/star/beans/PropertyAttribute.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/XPropertySetInfo.hpp>
48 #include <com/sun/star/beans/XPropertyContainer.hpp>
49 #include <com/sun/star/beans/StringPair.hpp>
50 #include <com/sun/star/util/XMacroExpander.hpp>
51 #include <com/sun/star/container/XContainerQuery.hpp>
52 #include <com/sun/star/document/XTypeDetection.hpp>
53 #include <com/sun/star/document/XStandaloneDocumentInfo.hpp>
54 #include <com/sun/star/sdbc/XResultSet.hpp>
55 #include <com/sun/star/sdbc/XRow.hpp>
56 #include <com/sun/star/ucb/NameClash.hpp>
57 #include <com/sun/star/ucb/NameClashException.hpp>
58 #include <com/sun/star/ucb/TransferInfo.hpp>
59 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
60 #include <com/sun/star/ucb/XContentAccess.hpp>
61 #include <com/sun/star/frame/XModuleManager.hpp>
62 #include <com/sun/star/uno/Exception.hpp>
64 #include <svtools/templatefoldercache.hxx>
65 #include <unotools/configmgr.hxx>
66 #include <unotools/ucbhelper.hxx>
68 #include "sfx2/sfxresid.hxx"
69 #include "sfxurlrelocator.hxx"
70 #include "doctemplateslocal.hxx"
71 #include <sfx2/docfac.hxx>
72 #include <sfx2/docfile.hxx>
73 #include "doc.hrc"
75 #include <vector>
77 //-----------------------------------------------------------------------------
79 //=============================================================================
81 #define TEMPLATE_SERVICE_NAME "com.sun.star.frame.DocumentTemplates"
82 #define TEMPLATE_IMPLEMENTATION_NAME "com.sun.star.comp.sfx2.DocumentTemplates"
84 #define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection"
85 #define SERVICENAME_DOCINFO "com.sun.star.document.StandaloneDocumentInfo"
87 #define TEMPLATE_ROOT_URL "vnd.sun.star.hier:/templates"
88 #define TITLE "Title"
89 #define IS_FOLDER "IsFolder"
90 #define IS_DOCUMENT "IsDocument"
91 #define TARGET_URL "TargetURL"
92 #define TEMPLATE_VERSION "TemplateComponentVersion"
93 #define TEMPLATE_VERSION_VALUE "2"
94 #define TYPE_FOLDER "application/vnd.sun.star.hier-folder"
95 #define TYPE_LINK "application/vnd.sun.star.hier-link"
96 #define TYPE_FSYS_FOLDER "application/vnd.sun.staroffice.fsys-folder"
97 #define TYPE_FSYS_FILE "application/vnd.sun.staroffice.fsys-file"
99 #define PROPERTY_DIRLIST "DirectoryList"
100 #define PROPERTY_NEEDSUPDATE "NeedsUpdate"
101 #define PROPERTY_TYPE "TypeDescription"
103 #define TARGET_DIR_URL "TargetDirURL"
104 #define COMMAND_DELETE "delete"
105 #define COMMAND_TRANSFER "transfer"
107 #define STANDARD_FOLDER "standard"
109 #define C_DELIM ';'
111 //=============================================================================
113 using namespace ::com::sun::star;
114 using namespace ::com::sun::star::beans;
115 using namespace ::com::sun::star::document;
116 using namespace ::com::sun::star::io;
117 using namespace ::com::sun::star::lang;
118 using namespace ::com::sun::star::sdbc;
119 using namespace ::com::sun::star::ucb;
120 using namespace ::com::sun::star::uno;
121 using namespace ::com::sun::star::container;
122 using namespace ::com::sun::star::util;
124 using namespace ::rtl;
125 using namespace ::ucbhelper;
126 using namespace ::comphelper;
128 using ::std::vector;
130 //=============================================================================
132 class WaitWindow_Impl : public WorkWindow
134 Rectangle _aRect;
135 sal_uInt16 _nTextStyle;
136 String _aText;
138 public:
139 WaitWindow_Impl();
140 ~WaitWindow_Impl();
141 virtual void Paint( const Rectangle& rRect );
144 #define X_OFFSET 15
145 #define Y_OFFSET 15
147 //=============================================================================
149 struct NamePair_Impl
151 OUString maShortName;
152 OUString maLongName;
155 class Updater_Impl;
156 class DocTemplates_EntryData_Impl;
157 class GroupData_Impl;
159 typedef vector< NamePair_Impl* > NameList_Impl;
160 typedef vector< GroupData_Impl* > GroupList_Impl;
162 //=============================================================================
163 #include <com/sun/star/task/XInteractionHandler.hpp>
164 #include <com/sun/star/ucb/XProgressHandler.hpp>
166 class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment >
168 uno::Reference< task::XInteractionHandler > m_xInteractionHandler;
169 uno::Reference< ucb::XProgressHandler > m_xProgressHandler;
171 public:
172 TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler )
173 : m_xInteractionHandler( rxInteractionHandler )
176 virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException)
177 { return m_xInteractionHandler; }
179 virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler() throw (uno::RuntimeException)
180 { return m_xProgressHandler; }
183 class SfxDocTplService_Impl
185 uno::Reference< XMultiServiceFactory > mxFactory;
186 uno::Reference< XCommandEnvironment > maCmdEnv;
187 uno::Reference< XStandaloneDocumentInfo > mxInfo;
188 uno::Reference< XTypeDetection > mxType;
190 ::osl::Mutex maMutex;
191 Sequence< OUString > maTemplateDirs;
192 OUString maRootURL;
193 NameList_Impl maNames;
194 Locale maLocale;
195 Content maRootContent;
196 Updater_Impl* mpUpdater;
197 sal_Bool mbIsInitialized : 1;
198 sal_Bool mbLocaleSet : 1;
200 SfxURLRelocator_Impl maRelocator;
202 void init_Impl();
203 void getDefaultLocale();
204 void getDirList();
205 void readFolderList();
206 sal_Bool needsUpdate();
207 OUString getLongName( const OUString& rShortName );
208 sal_Bool setTitleForURL( const OUString& rURL, const OUString& aTitle );
209 sal_Bool getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle );
211 sal_Bool addEntry( Content& rParentFolder,
212 const OUString& rTitle,
213 const OUString& rTargetURL,
214 const OUString& rType );
216 sal_Bool createFolder( const OUString& rNewFolderURL,
217 sal_Bool bCreateParent,
218 sal_Bool bFsysFolder,
219 Content &rNewFolder );
221 sal_Bool CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath,
222 const ::rtl::OUString& aPrefix,
223 ::rtl::OUString& aNewFolderName,
224 ::rtl::OUString& aNewFolderURL,
225 Content& aNewFolder );
226 ::rtl::OUString CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath,
227 const ::rtl::OUString& aPrefix,
228 const ::rtl::OUString& aExt );
230 uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath );
231 sal_Bool UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
232 const ::rtl::OUString& aGroupName,
233 const ::rtl::OUString& aNewFolderName );
234 sal_Bool ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
235 const ::rtl::OUString& aFsysGroupName,
236 const ::rtl::OUString& aOldGroupName,
237 const ::rtl::OUString& aNewGroupName );
238 sal_Bool RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
239 const ::rtl::OUString& aGroupName );
240 sal_Bool WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
241 const uno::Sequence< beans::StringPair >& aUINames );
243 ::rtl::OUString CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup );
245 sal_Bool removeContent( Content& rContent );
246 sal_Bool removeContent( const OUString& rContentURL );
248 sal_Bool setProperty( Content& rContent,
249 const OUString& rPropName,
250 const Any& rPropValue );
251 sal_Bool getProperty( Content& rContent,
252 const OUString& rPropName,
253 Any& rPropValue );
255 void createFromContent( GroupList_Impl& rList,
256 Content &rContent,
257 sal_Bool bHierarchy,
258 sal_Bool bWriteableContent = sal_False );
259 void addHierGroup( GroupList_Impl& rList,
260 const OUString& rTitle,
261 const OUString& rOwnURL );
262 void addFsysGroup( GroupList_Impl& rList,
263 const OUString& rTitle,
264 const OUString& rUITitle,
265 const OUString& rOwnURL,
266 sal_Bool bWriteableGroup = sal_False );
267 void removeFromHierarchy( DocTemplates_EntryData_Impl *pData );
268 void addToHierarchy( GroupData_Impl *pGroup,
269 DocTemplates_EntryData_Impl *pData );
271 void removeFromHierarchy( GroupData_Impl *pGroup );
272 void addGroupToHierarchy( GroupData_Impl *pGroup );
274 void updateData( DocTemplates_EntryData_Impl *pData );
276 public:
277 SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory );
278 ~SfxDocTplService_Impl();
280 sal_Bool init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; }
281 Content getContent() const { return maRootContent; }
283 void setLocale( const Locale & rLocale );
284 Locale getLocale();
286 sal_Bool storeTemplate( const OUString& rGroupName,
287 const OUString& rTemplateName,
288 const uno::Reference< XSTORABLE >& rStorable );
290 sal_Bool addTemplate( const OUString& rGroupName,
291 const OUString& rTemplateName,
292 const OUString& rSourceURL );
293 sal_Bool removeTemplate( const OUString& rGroupName,
294 const OUString& rTemplateName );
295 sal_Bool renameTemplate( const OUString& rGroupName,
296 const OUString& rOldName,
297 const OUString& rNewName );
299 sal_Bool addGroup( const OUString& rGroupName );
300 sal_Bool removeGroup( const OUString& rGroupName );
301 sal_Bool renameGroup( const OUString& rOldName,
302 const OUString& rNewName );
304 void update( sal_Bool bUpdateNow );
305 void doUpdate();
306 void finished() { mpUpdater = NULL; }
309 //=============================================================================
311 class Updater_Impl : public ::osl::Thread
313 private:
314 SfxDocTplService_Impl *mpDocTemplates;
316 public:
317 Updater_Impl( SfxDocTplService_Impl* pTemplates );
318 ~Updater_Impl();
320 virtual void SAL_CALL run();
321 virtual void SAL_CALL onTerminated();
324 //=============================================================================
326 class DocTemplates_EntryData_Impl
328 OUString maTitle;
329 OUString maType;
330 OUString maTargetURL;
331 OUString maHierarchyURL;
333 sal_Bool mbInHierarchy : 1;
334 sal_Bool mbInUse : 1;
335 sal_Bool mbUpdateType : 1;
336 sal_Bool mbUpdateLink : 1;
338 public:
339 DocTemplates_EntryData_Impl( const OUString& rTitle );
341 void setInUse() { mbInUse = sal_True; }
342 void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
343 void setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; }
344 void setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; }
346 sal_Bool getInUse() const { return mbInUse; }
347 sal_Bool getInHierarchy() const { return mbInHierarchy; }
348 sal_Bool getUpdateLink() const { return mbUpdateLink; }
349 sal_Bool getUpdateType() const { return mbUpdateType; }
351 const OUString& getHierarchyURL() const { return maHierarchyURL; }
352 const OUString& getTargetURL() const { return maTargetURL; }
353 const OUString& getTitle() const { return maTitle; }
354 const OUString& getType() const { return maType; }
356 void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
357 void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
358 void setType( const OUString& rType ) { maType = rType; }
361 //=============================================================================
363 class GroupData_Impl
365 vector< DocTemplates_EntryData_Impl* > maEntries;
366 OUString maTitle;
367 OUString maHierarchyURL;
368 OUString maTargetURL;
369 sal_Bool mbInUse : 1;
370 sal_Bool mbInHierarchy : 1;
372 public:
373 GroupData_Impl( const OUString& rTitle );
374 ~GroupData_Impl();
376 void setInUse() { mbInUse = sal_True; }
377 void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
378 void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
379 void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
381 sal_Bool getInUse() const { return mbInUse; }
382 sal_Bool getInHierarchy() const { return mbInHierarchy; }
383 const OUString& getHierarchyURL() const { return maHierarchyURL; }
384 const OUString& getTargetURL() const { return maTargetURL; }
385 const OUString& getTitle() const { return maTitle; }
387 DocTemplates_EntryData_Impl* addEntry( const OUString& rTitle,
388 const OUString& rTargetURL,
389 const OUString& rType,
390 const OUString& rHierURL );
391 size_t count() { return maEntries.size(); }
392 DocTemplates_EntryData_Impl* getEntry( size_t nPos ) { return maEntries[ nPos ]; }
395 //-----------------------------------------------------------------------------
396 // private SfxDocTplService_Impl
397 //-----------------------------------------------------------------------------
398 void SfxDocTplService_Impl::init_Impl()
400 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
401 if ( xFactory.is() )
403 uno::Reference < task::XInteractionHandler > xInteractionHandler( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY );
404 maCmdEnv = new TplTaskEnvironment( xInteractionHandler );
407 ::osl::ClearableMutexGuard aGuard( maMutex );
408 sal_Bool bIsInitialized = sal_False;
409 sal_Bool bNeedsUpdate = sal_False;
411 if ( !mbLocaleSet )
412 getDefaultLocale();
414 // convert locale to string
415 OUString aLang = maLocale.Language;
416 aLang += String( '-' );
417 aLang += maLocale.Country;
419 // set maRootContent to the root of the templates hierarchy. Create the
420 // entry if necessary
422 maRootURL = OUString( TEMPLATE_ROOT_URL );
423 maRootURL += String( '/' );
424 maRootURL += aLang;
426 ::rtl::OUString aTemplVersPropName( TEMPLATE_VERSION );
427 ::rtl::OUString aTemplVers( TEMPLATE_VERSION_VALUE );
428 if ( Content::create( maRootURL, maCmdEnv, maRootContent ) )
430 uno::Any aValue;
431 ::rtl::OUString aPropValue;
432 if ( getProperty( maRootContent, aTemplVersPropName, aValue )
433 && ( aValue >>= aPropValue )
434 && aPropValue.equals( aTemplVers ) )
436 bIsInitialized = sal_True;
438 else
439 removeContent( maRootContent );
442 if ( !bIsInitialized )
444 if ( createFolder( maRootURL, sal_True, sal_False, maRootContent )
445 && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) )
446 bIsInitialized = sal_True;
448 bNeedsUpdate = sal_True;
451 if ( bIsInitialized )
453 OUString aService( SERVICENAME_DOCINFO );
454 try {
455 mxInfo = uno::Reference< XStandaloneDocumentInfo > (
456 mxFactory->createInstance( aService ), UNO_QUERY );
457 } catch (uno::RuntimeException &) {
458 OSL_FAIL("SfxDocTplService_Impl::init_Impl: "
459 "cannot create DocumentProperties service");
462 aService = OUString( SERVICENAME_TYPEDETECTION );
463 mxType = uno::Reference< XTypeDetection > ( mxFactory->createInstance( aService ), UNO_QUERY );
465 getDirList();
466 readFolderList();
468 if ( bNeedsUpdate )
470 aGuard.clear();
471 SolarMutexClearableGuard aSolarGuard;
473 WaitWindow_Impl* pWin = new WaitWindow_Impl();
475 aSolarGuard.clear();
476 ::osl::ClearableMutexGuard anotherGuard( maMutex );
478 update( sal_True );
480 anotherGuard.clear();
481 SolarMutexGuard aSecondSolarGuard;
483 delete pWin;
485 else if ( needsUpdate() )
486 // the UI should be shown only on the first update
487 update( sal_True );
489 else
491 SAL_WARN( "sfx2.doc", "init_Impl(): Could not create root" );
494 mbIsInitialized = bIsInitialized;
497 //-----------------------------------------------------------------------------
498 void SfxDocTplService_Impl::getDefaultLocale()
500 if ( !mbLocaleSet )
502 ::osl::MutexGuard aGuard( maMutex );
503 if ( !mbLocaleSet )
505 rtl::OUString aLocale( utl::ConfigManager::getLocale() );
506 if ( !aLocale.isEmpty() )
508 sal_Int32 nPos = aLocale.indexOf( sal_Unicode( '-' ) );
509 if ( nPos != -1 )
511 maLocale.Language = aLocale.copy( 0, nPos );
512 nPos = aLocale.indexOf( sal_Unicode( '_' ), nPos + 1 );
513 if ( nPos != -1 )
515 maLocale.Country
516 = aLocale.copy( maLocale.Language.getLength() + 1,
517 nPos - maLocale.Language.getLength() - 1 );
518 maLocale.Variant
519 = aLocale.copy( nPos + 1 );
521 else
523 maLocale.Country
524 = aLocale.copy( maLocale.Language.getLength() + 1 );
530 mbLocaleSet = sal_True;
535 // -----------------------------------------------------------------------
536 void SfxDocTplService_Impl::readFolderList()
538 SolarMutexGuard aGuard;
540 ResStringArray aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) );
541 ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) );
543 NamePair_Impl* pPair;
545 sal_uInt16 nCount = (sal_uInt16)( Min( aShortNames.Count(), aLongNames.Count() ) );
547 for ( sal_uInt16 i=0; i<nCount; i++ )
549 pPair = new NamePair_Impl;
550 pPair->maShortName = aShortNames.GetString( i );
551 pPair->maLongName = aLongNames.GetString( i );
553 maNames.push_back( pPair );
557 // -----------------------------------------------------------------------
558 OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName )
560 OUString aRet;
562 for ( size_t i = 0, n = maNames.size(); i < n; ++i )
564 NamePair_Impl* pPair = maNames[ i ];
565 if ( pPair->maShortName == rShortName )
567 aRet = pPair->maLongName;
568 break;
572 if ( aRet.isEmpty() )
573 aRet = rShortName;
575 return aRet;
578 //-----------------------------------------------------------------------------
579 void SfxDocTplService_Impl::getDirList()
581 OUString aPropName( PROPERTY_DIRLIST );
582 Any aValue;
584 // Get the template dir list
585 // TODO/LATER: let use service, register listener
586 INetURLObject aURL;
587 String aDirs = SvtPathOptions().GetTemplatePath();
588 sal_uInt16 nCount = comphelper::string::getTokenCount(aDirs, C_DELIM);
590 maTemplateDirs = Sequence< OUString >( nCount );
592 uno::Reference< XComponentContext > xCtx;
593 uno::Reference< util::XMacroExpander > xExpander;
594 uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY );
595 const rtl::OUString aPrefix(
596 "vnd.sun.star.expand:" );
598 if ( xPropSet.is() )
600 xPropSet->getPropertyValue(
601 rtl::OUString(
602 "DefaultContext" ) )
603 >>= xCtx;
606 if ( xCtx.is() )
608 xCtx->getValueByName(
609 rtl::OUString( "/singletons/com.sun.star.util.theMacroExpander" ) )
610 >>= xExpander;
612 OSL_ENSURE( xExpander.is(),
613 "Unable to obtain macro expander singleton!" );
616 for ( sal_uInt16 i=0; i<nCount; i++ )
618 aURL.SetSmartProtocol( INET_PROT_FILE );
619 aURL.SetURL( aDirs.GetToken( i, C_DELIM ) );
620 maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE );
622 sal_Int32 nIndex = maTemplateDirs[i].indexOf( aPrefix );
623 if ( nIndex != -1 && xExpander.is() )
625 maTemplateDirs[i] = maTemplateDirs[i].replaceAt(nIndex,
626 aPrefix.getLength(),
627 rtl::OUString());
628 maTemplateDirs[i] = xExpander->expandMacros( maTemplateDirs[i] );
632 aValue <<= maTemplateDirs;
634 // Store the template dir list
635 setProperty( maRootContent, aPropName, aValue );
638 //-----------------------------------------------------------------------------
639 sal_Bool SfxDocTplService_Impl::needsUpdate()
641 OUString aPropName( PROPERTY_NEEDSUPDATE );
642 sal_Bool bHasProperty = sal_False;
643 sal_Bool bNeedsUpdate = sal_True;
644 Any aValue;
646 // Get the template dir list
647 bHasProperty = getProperty( maRootContent, aPropName, aValue );
649 if ( bHasProperty )
650 aValue >>= bNeedsUpdate;
652 // the old template component also checks this state, but it is initialized from this component
653 // so if this componend was already updated the old component does not need such an update
654 ::svt::TemplateFolderCache aTempCache;
655 if ( !bNeedsUpdate )
656 bNeedsUpdate = aTempCache.needsUpdate();
658 if ( bNeedsUpdate )
659 aTempCache.storeState();
661 return bNeedsUpdate;
664 // -----------------------------------------------------------------------
665 sal_Bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle )
667 sal_Bool bResult = sal_False;
668 if ( mxInfo.is() )
672 mxInfo->loadFromURL( rURL );
673 uno::Reference< XPropertySet > xPropSet( mxInfo, UNO_QUERY_THROW );
674 OUString aPropName( TITLE );
675 xPropSet->setPropertyValue( aPropName, uno::makeAny( aTitle ) );
676 mxInfo->storeIntoURL( rURL );
677 bResult = sal_True;
679 catch ( Exception& )
684 return bResult;
687 // -----------------------------------------------------------------------
688 sal_Bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle )
690 bDocHasTitle = sal_False;
692 if ( mxInfo.is() )
696 mxInfo->loadFromURL( rURL );
698 catch ( Exception& )
700 // the document is not a StarOffice document
701 return sal_False;
706 uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY );
707 if ( aPropSet.is() )
709 OUString aPropName( TITLE );
710 Any aValue = aPropSet->getPropertyValue( aPropName );
711 aValue >>= aTitle;
713 aPropName = OUString( "MIMEType" );
714 aValue = aPropSet->getPropertyValue( aPropName );
715 aValue >>= aType;
718 catch ( UnknownPropertyException& ) {}
719 catch ( Exception& ) {}
722 if ( aType.isEmpty() && mxType.is() )
724 ::rtl::OUString aDocType = mxType->queryTypeByURL( rURL );
725 if ( !aDocType.isEmpty() )
728 uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW );
729 SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) );
730 aType = aTypeProps.getUnpackedValueOrDefault(
731 ::rtl::OUString("MediaType"),
732 ::rtl::OUString() );
734 catch( uno::Exception& )
738 if ( aTitle.isEmpty() )
740 INetURLObject aURL( rURL );
741 aURL.CutExtension();
742 aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
743 INetURLObject::DECODE_WITH_CHARSET );
745 else
746 bDocHasTitle = sal_True;
748 return sal_True;
751 // -----------------------------------------------------------------------
752 sal_Bool SfxDocTplService_Impl::addEntry( Content& rParentFolder,
753 const OUString& rTitle,
754 const OUString& rTargetURL,
755 const OUString& rType )
757 sal_Bool bAddedEntry = sal_False;
759 INetURLObject aLinkObj( rParentFolder.getURL() );
760 aLinkObj.insertName( rTitle, false,
761 INetURLObject::LAST_SEGMENT, true,
762 INetURLObject::ENCODE_ALL );
763 OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE );
765 Content aLink;
767 if ( ! Content::create( aLinkURL, maCmdEnv, aLink ) )
769 Sequence< OUString > aNames(3);
770 aNames[0] = OUString( TITLE );
771 aNames[1] = OUString( IS_FOLDER );
772 aNames[2] = OUString( TARGET_URL );
774 Sequence< Any > aValues(3);
775 aValues[0] = makeAny( rTitle );
776 aValues[1] = makeAny( sal_Bool( sal_False ) );
777 aValues[2] = makeAny( rTargetURL );
779 OUString aType( TYPE_LINK );
780 OUString aAdditionalProp( PROPERTY_TYPE );
784 rParentFolder.insertNewContent( aType, aNames, aValues, aLink );
785 setProperty( aLink, aAdditionalProp, makeAny( rType ) );
786 bAddedEntry = sal_True;
788 catch( Exception& )
791 return bAddedEntry;
794 // -----------------------------------------------------------------------
795 sal_Bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL,
796 sal_Bool bCreateParent,
797 sal_Bool bFsysFolder,
798 Content &rNewFolder )
800 Content aParent;
801 sal_Bool bCreatedFolder = sal_False;
802 INetURLObject aParentURL( rNewFolderURL );
803 OUString aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true,
804 INetURLObject::DECODE_WITH_CHARSET );
806 // compute the parent folder url from the new folder url
807 // and remove the final slash, because Content::create doesn't
808 // like it
809 aParentURL.removeSegment();
810 if ( aParentURL.getSegmentCount() >= 1 )
811 aParentURL.removeFinalSlash();
813 // if the parent exists, we can continue with the creation of the
814 // new folder, we have to create the parent otherwise ( as long as
815 // bCreateParent is set to true )
816 if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) )
820 Sequence< OUString > aNames(2);
821 aNames[0] = OUString( TITLE );
822 aNames[1] = OUString( IS_FOLDER );
824 Sequence< Any > aValues(2);
825 aValues[0] = makeAny( aFolderName );
826 aValues[1] = makeAny( sal_Bool( sal_True ) );
828 OUString aType;
830 if ( bFsysFolder )
831 aType = OUString( TYPE_FSYS_FOLDER );
832 else
833 aType = OUString( TYPE_FOLDER );
835 aParent.insertNewContent( aType, aNames, aValues, rNewFolder );
836 bCreatedFolder = sal_True;
838 catch( RuntimeException& )
840 SAL_WARN( "sfx2.doc", "createFolder(): got runtime exception" );
842 catch( Exception& )
844 SAL_WARN( "sfx2.doc", "createFolder(): Could not create new folder" );
847 else if ( bCreateParent )
849 // if the parent doesn't exists and bCreateParent is set to true,
850 // we try to create the parent and if this was successful, we
851 // try to create the new folder again ( but this time, we set
852 // bCreateParent to false to avoid endless recusions )
853 if ( ( aParentURL.getSegmentCount() >= 1 ) &&
854 createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) )
856 bCreatedFolder = createFolder( rNewFolderURL, sal_False, bFsysFolder, rNewFolder );
860 return bCreatedFolder;
863 // -----------------------------------------------------------------------
864 sal_Bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath,
865 const ::rtl::OUString& aPrefix,
866 ::rtl::OUString& aNewFolderName,
867 ::rtl::OUString& aNewFolderURL,
868 Content& aNewFolder )
870 sal_Bool bCreated = sal_False;
871 INetURLObject aDirPath( aPath );
873 Content aParent;
874 uno::Reference< XCommandEnvironment > aQuietEnv;
875 if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, aParent ) )
877 for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
879 ::rtl::OUString aTryName = aPrefix;
880 if ( nInd )
881 aTryName += ::rtl::OUString::valueOf( nInd );
885 Sequence< OUString > aNames(2);
886 aNames[0] = OUString( TITLE );
887 aNames[1] = OUString( IS_FOLDER );
889 Sequence< Any > aValues(2);
890 aValues[0] = makeAny( aTryName );
891 aValues[1] = makeAny( sal_Bool( sal_True ) );
893 OUString aType( TYPE_FSYS_FOLDER );
895 bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder );
897 catch( ucb::NameClashException& )
899 // if there is already an element, retry
901 catch( Exception& )
903 INetURLObject aObjPath( aDirPath );
904 aObjPath.insertName( aTryName, false,
905 INetURLObject::LAST_SEGMENT, true,
906 INetURLObject::ENCODE_ALL );
907 // if there is already an element, retry
908 // if there was another error, do not try any more
909 if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
910 break;
913 if ( bCreated )
915 aNewFolderName = aTryName;
916 aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier();
917 break;
922 return bCreated;
925 // -----------------------------------------------------------------------
926 ::rtl::OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath,
927 const ::rtl::OUString& aPrefix,
928 const ::rtl::OUString& aExt )
930 ::rtl::OUString aNewFileURL;
931 INetURLObject aDirPath( aPath );
933 Content aParent;
935 uno::Reference< XCommandEnvironment > aQuietEnv;
936 if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, aParent ) )
938 for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
940 Content aNewFile;
941 sal_Bool bCreated = sal_False;
942 ::rtl::OUString aTryName = aPrefix;
943 if ( nInd )
944 aTryName += ::rtl::OUString::valueOf( nInd );
945 if ( aExt.toChar() != '.' )
946 aTryName += ::rtl::OUString( "." );
947 aTryName += aExt;
951 Sequence< OUString > aNames(2);
952 aNames[0] = OUString( TITLE );
953 aNames[1] = OUString( IS_DOCUMENT );
955 Sequence< Any > aValues(2);
956 aValues[0] = makeAny( aTryName );
957 aValues[1] = makeAny( sal_Bool( sal_True ) );
959 OUString aType( TYPE_FSYS_FILE );
961 bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile );
963 catch( ucb::NameClashException& )
965 // if there is already an element, retry
967 catch( Exception& )
969 INetURLObject aObjPath( aPath );
970 aObjPath.insertName( aTryName, false,
971 INetURLObject::LAST_SEGMENT, true,
972 INetURLObject::ENCODE_ALL );
973 // if there is already an element, retry
974 // if there was another error, do not try any more
975 if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
976 break;
979 if ( bCreated )
981 aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier();
982 break;
987 return aNewFileURL;
990 // -----------------------------------------------------------------------
991 sal_Bool SfxDocTplService_Impl::removeContent( Content& rContent )
993 sal_Bool bRemoved = sal_False;
996 OUString aCmd( COMMAND_DELETE );
997 Any aArg = makeAny( sal_Bool( sal_True ) );
999 rContent.executeCommand( aCmd, aArg );
1000 bRemoved = sal_True;
1002 catch ( RuntimeException& ) {}
1003 catch ( Exception& ) {}
1005 return bRemoved;
1008 // -----------------------------------------------------------------------
1009 sal_Bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL )
1011 Content aContent;
1013 if ( Content::create( rContentURL, maCmdEnv, aContent ) )
1014 return removeContent( aContent );
1015 else
1016 return sal_False;
1019 // -----------------------------------------------------------------------
1020 sal_Bool SfxDocTplService_Impl::setProperty( Content& rContent,
1021 const OUString& rPropName,
1022 const Any& rPropValue )
1024 sal_Bool bPropertySet = sal_False;
1026 // Store the property
1029 Any aPropValue( rPropValue );
1030 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1032 // check, whether or not the property exists, create it, when not
1033 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1035 uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY );
1036 if ( xProperties.is() )
1040 xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue );
1042 catch( PropertyExistException& ) {}
1043 catch( IllegalTypeException& ) {
1044 SAL_WARN( "sfx2.doc", "IllegalTypeException" );
1046 catch( IllegalArgumentException& ) {
1047 SAL_WARN( "sfx2.doc", "IllegalArgumentException" );
1052 // To ensure a reloctable office installation, the path to the
1053 // office installtion directory must never be stored directly.
1054 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1056 OUString aValue;
1057 if ( rPropValue >>= aValue )
1059 maRelocator.makeRelocatableURL( aValue );
1060 aPropValue = makeAny( aValue );
1062 else
1064 Sequence< OUString > aValues;
1065 if ( rPropValue >>= aValues )
1067 for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1069 maRelocator.makeRelocatableURL( aValues[ n ] );
1071 aPropValue = makeAny( aValues );
1073 else
1075 OSL_FAIL( "Unsupported property value type" );
1080 // now set the property
1082 rContent.setPropertyValue( rPropName, aPropValue );
1083 bPropertySet = sal_True;
1085 catch ( RuntimeException& ) {}
1086 catch ( Exception& ) {}
1088 return bPropertySet;
1091 // -----------------------------------------------------------------------
1092 sal_Bool SfxDocTplService_Impl::getProperty( Content& rContent,
1093 const OUString& rPropName,
1094 Any& rPropValue )
1096 sal_Bool bGotProperty = sal_False;
1098 // Get the property
1101 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1103 // check, whether or not the property exists
1104 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1106 return sal_False;
1109 // now get the property
1111 rPropValue = rContent.getPropertyValue( rPropName );
1113 // To ensure a reloctable office installation, the path to the
1114 // office installtion directory must never be stored directly.
1115 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1117 OUString aValue;
1118 if ( rPropValue >>= aValue )
1120 maRelocator.makeAbsoluteURL( aValue );
1121 rPropValue = makeAny( aValue );
1123 else
1125 Sequence< OUString > aValues;
1126 if ( rPropValue >>= aValues )
1128 for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1130 maRelocator.makeAbsoluteURL( aValues[ n ] );
1132 rPropValue = makeAny( aValues );
1134 else
1136 OSL_FAIL( "Unsupported property value type" );
1141 bGotProperty = sal_True;
1143 catch ( RuntimeException& ) {}
1144 catch ( Exception& ) {}
1146 return bGotProperty;
1149 // -----------------------------------------------------------------------
1150 // static
1151 bool SfxURLRelocator_Impl::propertyCanContainOfficeDir(
1152 const rtl::OUString & rPropName )
1154 // Note: TargetURL is handled by UCB itself (because it is a property
1155 // with a predefined semantic). Additional Core properties introduced
1156 // be a client app must be handled by the client app itself, because
1157 // the UCB does not know the semantics of those properties.
1158 return ( rPropName == TARGET_DIR_URL || rPropName == PROPERTY_DIRLIST );
1161 //-----------------------------------------------------------------------------
1162 // public SfxDocTplService_Impl
1163 //-----------------------------------------------------------------------------
1165 SfxDocTplService_Impl::SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory )
1166 : maRelocator( xFactory )
1168 mxFactory = xFactory;
1169 mpUpdater = NULL;
1170 mbIsInitialized = sal_False;
1171 mbLocaleSet = sal_False;
1174 //-----------------------------------------------------------------------------
1175 SfxDocTplService_Impl::~SfxDocTplService_Impl()
1177 ::osl::MutexGuard aGuard( maMutex );
1179 if ( mpUpdater )
1181 mpUpdater->terminate();
1182 mpUpdater->join();
1183 delete mpUpdater;
1186 for ( size_t i = 0, n = maNames.size(); i < n; ++i )
1187 delete maNames[ i ];
1188 maNames.clear();
1191 //-----------------------------------------------------------------------------
1192 Locale SfxDocTplService_Impl::getLocale()
1194 ::osl::MutexGuard aGuard( maMutex );
1196 if ( !mbLocaleSet )
1197 getDefaultLocale();
1199 return maLocale;
1202 //-----------------------------------------------------------------------------
1203 void SfxDocTplService_Impl::setLocale( const Locale &rLocale )
1205 ::osl::MutexGuard aGuard( maMutex );
1207 if ( mbLocaleSet &&
1208 ( maLocale.Language != rLocale.Language ) &&
1209 ( maLocale.Country != rLocale.Country ) )
1210 mbIsInitialized = sal_False;
1212 maLocale = rLocale;
1213 mbLocaleSet = sal_True;
1216 //-----------------------------------------------------------------------------
1217 void SfxDocTplService_Impl::update( sal_Bool bUpdateNow )
1219 ::osl::MutexGuard aGuard( maMutex );
1221 if ( bUpdateNow )
1222 doUpdate();
1223 else
1225 mpUpdater = new Updater_Impl( this );
1226 mpUpdater->create();
1230 //-----------------------------------------------------------------------------
1231 void SfxDocTplService_Impl::doUpdate()
1233 ::osl::MutexGuard aGuard( maMutex );
1235 OUString aPropName( PROPERTY_NEEDSUPDATE );
1236 Any aValue;
1238 aValue <<= sal_True;
1239 setProperty( maRootContent, aPropName, aValue );
1241 GroupList_Impl aGroupList;
1243 // get the entries from the hierarchy
1244 createFromContent( aGroupList, maRootContent, sal_True );
1246 // get the entries from the template directories
1247 sal_Int32 nCountDir = maTemplateDirs.getLength();
1248 OUString* pDirs = maTemplateDirs.getArray();
1249 Content aDirContent;
1251 // the last directory in the list must be writable
1252 sal_Bool bWriteableDirectory = sal_True;
1254 // the target folder might not exist, for this reason no interaction handler should be used
1255 uno::Reference< XCommandEnvironment > aQuietEnv;
1257 while ( nCountDir )
1259 nCountDir--;
1260 if ( Content::create( pDirs[ nCountDir ], aQuietEnv, aDirContent ) )
1262 createFromContent( aGroupList, aDirContent, sal_False, bWriteableDirectory );
1265 bWriteableDirectory = sal_False;
1268 // now check the list
1269 for( size_t j = 0, n = aGroupList.size(); j < n; ++j )
1271 GroupData_Impl *pGroup = aGroupList[ j ];
1272 if ( pGroup->getInUse() )
1274 if ( pGroup->getInHierarchy() )
1276 Content aGroup;
1277 if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
1278 setProperty( aGroup,
1279 OUString( TARGET_DIR_URL ),
1280 makeAny( pGroup->getTargetURL() ) );
1282 size_t nCount = pGroup->count();
1283 for ( size_t i=0; i<nCount; i++ )
1285 DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
1286 if ( ! pData->getInUse() )
1288 if ( pData->getInHierarchy() )
1289 removeFromHierarchy( pData ); // delete entry in hierarchy
1290 else
1291 addToHierarchy( pGroup, pData ); // add entry to hierarchy
1293 else if ( pData->getUpdateType() ||
1294 pData->getUpdateLink() )
1296 updateData( pData );
1300 else
1302 addGroupToHierarchy( pGroup ); // add group to hierarchy
1305 else
1306 removeFromHierarchy( pGroup ); // delete group from hierarchy
1308 delete pGroup;
1310 aGroupList.clear();
1312 aValue <<= sal_False;
1313 setProperty( maRootContent, aPropName, aValue );
1316 //-----------------------------------------------------------------------------
1317 uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath )
1319 INetURLObject aLocObj( aUserPath );
1320 aLocObj.insertName( ::rtl::OUString( "groupuinames.xml" ), false,
1321 INetURLObject::LAST_SEGMENT, true,
1322 INetURLObject::ENCODE_ALL );
1323 Content aLocContent;
1325 // TODO/LATER: Use hashmap in future
1326 uno::Sequence< beans::StringPair > aUINames;
1327 if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), aLocContent ) )
1331 uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream();
1332 if ( xLocStream.is() )
1333 aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxFactory );
1335 catch( uno::Exception& )
1339 return aUINames;
1342 //-----------------------------------------------------------------------------
1343 sal_Bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1344 const ::rtl::OUString& aGroupName,
1345 const ::rtl::OUString& aNewFolderName )
1347 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1348 sal_Int32 nLen = aUINames.getLength();
1350 // it is possible that the name is used already, but it should be checked before
1351 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1352 if ( aUINames[nInd].First.equals( aNewFolderName ) )
1353 return sal_False;
1355 aUINames.realloc( ++nLen );
1356 aUINames[nLen-1].First = aNewFolderName;
1357 aUINames[nLen-1].Second = aGroupName;
1359 return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1362 //-----------------------------------------------------------------------------
1363 sal_Bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1364 const ::rtl::OUString& aDefaultFsysGroupName,
1365 const ::rtl::OUString& aOldGroupName,
1366 const ::rtl::OUString& aNewGroupName )
1368 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1369 sal_Int32 nLen = aUINames.getLength();
1371 sal_Bool bChanged = sal_False;
1372 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1373 if ( aUINames[nInd].Second.equals( aOldGroupName ) )
1375 aUINames[nInd].Second = aNewGroupName;
1376 bChanged = sal_True;
1379 if ( !bChanged )
1381 aUINames.realloc( ++nLen );
1382 aUINames[nLen-1].First = aDefaultFsysGroupName;
1383 aUINames[nLen-1].Second = aNewGroupName;
1385 return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1388 //-----------------------------------------------------------------------------
1389 sal_Bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1390 const ::rtl::OUString& aGroupName )
1392 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1393 sal_Int32 nLen = aUINames.getLength();
1394 uno::Sequence< beans::StringPair > aNewUINames( nLen );
1395 sal_Int32 nNewLen = 0;
1397 sal_Bool bChanged = sal_False;
1398 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1399 if ( aUINames[nInd].Second.equals( aGroupName ) )
1400 bChanged = sal_True;
1401 else
1403 nNewLen++;
1404 aNewUINames[nNewLen-1].First = aUINames[nInd].First;
1405 aNewUINames[nNewLen-1].Second = aUINames[nInd].Second;
1408 aNewUINames.realloc( nNewLen );
1410 return bChanged ? WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames ) : sal_True;
1414 //-----------------------------------------------------------------------------
1415 sal_Bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath,
1416 const uno::Sequence< beans::StringPair >& aUINames )
1418 sal_Bool bResult = sal_False;
1419 try {
1420 uno::Reference< beans::XPropertySet > xTempFile(
1421 mxFactory->createInstance( ::rtl::OUString("com.sun.star.io.TempFile") ),
1422 uno::UNO_QUERY_THROW );
1424 ::rtl::OUString aTempURL;
1425 uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString("Uri") );
1426 aUrl >>= aTempURL;
1428 uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW );
1429 uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream();
1430 if ( !xOutStream.is() )
1431 throw uno::RuntimeException();
1433 DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxFactory );
1434 try {
1435 // the SAX writer might close the stream
1436 xOutStream->closeOutput();
1437 } catch( uno::Exception& )
1440 Content aTargetContent( aUserPath, maCmdEnv );
1441 Content aSourceContent( aTempURL, maCmdEnv );
1442 aTargetContent.transferContent( aSourceContent,
1443 InsertOperation_COPY,
1444 ::rtl::OUString( "groupuinames.xml" ),
1445 ucb::NameClash::OVERWRITE );
1446 bResult = sal_True;
1448 catch ( uno::Exception& )
1452 return bResult;
1455 //-----------------------------------------------------------------------------
1456 ::rtl::OUString SfxDocTplService_Impl::CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup )
1458 ::rtl::OUString aResultURL;
1460 if ( maTemplateDirs.getLength() )
1462 ::rtl::OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1464 // create a new folder with the given name
1465 Content aNewFolder;
1466 ::rtl::OUString aNewFolderName;
1468 // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1469 if ( !CreateNewUniqueFolderWithPrefix( aTargetPath,
1470 rGroupName,
1471 aNewFolderName,
1472 aResultURL,
1473 aNewFolder )
1474 && !CreateNewUniqueFolderWithPrefix( aTargetPath,
1475 ::rtl::OUString( "UserGroup" ),
1476 aNewFolderName,
1477 aResultURL,
1478 aNewFolder ) )
1480 return ::rtl::OUString();
1482 if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) )
1484 // we could not create the groupuinames for the folder, so we delete the group in the
1485 // the folder and return
1486 removeContent( aNewFolder );
1487 return ::rtl::OUString();
1490 // Now set the target url for this group and we are done
1491 OUString aPropName( TARGET_DIR_URL );
1492 Any aValue = makeAny( aResultURL );
1494 if ( ! setProperty( aGroup, aPropName, aValue ) )
1496 removeContent( aNewFolder );
1497 return ::rtl::OUString();
1501 return aResultURL;
1504 //-----------------------------------------------------------------------------
1505 sal_Bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName )
1507 ::osl::MutexGuard aGuard( maMutex );
1509 // Check, whether or not there is a group with this name
1510 Content aNewGroup;
1511 OUString aNewGroupURL;
1512 INetURLObject aNewGroupObj( maRootURL );
1514 aNewGroupObj.insertName( rGroupName, false,
1515 INetURLObject::LAST_SEGMENT, true,
1516 INetURLObject::ENCODE_ALL );
1518 aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1520 if ( Content::create( aNewGroupURL, maCmdEnv, aNewGroup ) ||
1521 ! createFolder( aNewGroupURL, sal_False, sal_False, aNewGroup ) )
1523 // if there already was a group with this name or the new group
1524 // could not be created, we return here
1525 return sal_False;
1528 // Get the user template path entry ( new group will always
1529 // be added in the user template path )
1530 sal_Int32 nIndex;
1531 OUString aUserPath;
1533 nIndex = maTemplateDirs.getLength();
1534 if ( nIndex )
1535 nIndex--;
1536 else
1537 return sal_False; // We don't know where to add the group
1539 aUserPath = maTemplateDirs[ nIndex ];
1541 // create a new folder with the given name
1542 Content aNewFolder;
1543 OUString aNewFolderName;
1544 OUString aNewFolderURL;
1546 // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1547 if ( !CreateNewUniqueFolderWithPrefix( aUserPath,
1548 rGroupName,
1549 aNewFolderName,
1550 aNewFolderURL,
1551 aNewFolder )
1552 && !CreateNewUniqueFolderWithPrefix( aUserPath,
1553 ::rtl::OUString( "UserGroup" ),
1554 aNewFolderName,
1555 aNewFolderURL,
1556 aNewFolder ) )
1558 // we could not create the folder, so we delete the group in the
1559 // hierarchy and return
1560 removeContent( aNewGroup );
1561 return sal_False;
1564 if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) )
1566 // we could not create the groupuinames for the folder, so we delete the group in the
1567 // hierarchy, the folder and return
1568 removeContent( aNewGroup );
1569 removeContent( aNewFolder );
1570 return sal_False;
1573 // Now set the target url for this group and we are done
1574 OUString aPropName( TARGET_DIR_URL );
1575 Any aValue = makeAny( aNewFolderURL );
1577 if ( ! setProperty( aNewGroup, aPropName, aValue ) )
1579 removeContent( aNewGroup );
1580 removeContent( aNewFolder );
1581 return sal_False;
1584 return sal_True;
1587 //-----------------------------------------------------------------------------
1588 sal_Bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName )
1590 // remove all the elements that have the prefix aTargetURL
1591 // if the group does not have other elements remove it
1593 ::osl::MutexGuard aGuard( maMutex );
1595 sal_Bool bResult = sal_False;
1597 // create the group url
1598 INetURLObject aGroupObj( maRootURL );
1599 aGroupObj.insertName( rGroupName, false,
1600 INetURLObject::LAST_SEGMENT, true,
1601 INetURLObject::ENCODE_ALL );
1603 // Get the target url
1604 Content aGroup;
1605 OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1607 if ( Content::create( aGroupURL, maCmdEnv, aGroup ) )
1609 OUString aPropName( TARGET_DIR_URL );
1610 Any aValue;
1612 OUString aGroupTargetURL;
1613 if ( getProperty( aGroup, aPropName, aValue ) )
1614 aValue >>= aGroupTargetURL;
1616 if ( aGroupTargetURL.isEmpty() )
1617 return sal_False; // nothing is allowed to be removed
1619 if ( !maTemplateDirs.getLength() )
1620 return sal_False;
1621 ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1623 // check that the fs location is in writeble folder and this is not a "My templates" folder
1624 INetURLObject aGroupParentFolder( aGroupTargetURL );
1625 if ( !aGroupParentFolder.removeSegment()
1626 || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1627 aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1628 return sal_False;
1630 // now get the content of the Group
1631 uno::Reference< XResultSet > xResultSet;
1632 Sequence< OUString > aProps( 1 );
1634 aProps[0] = OUString(TARGET_URL );
1638 sal_Bool bHasNonRemovable = sal_False;
1639 sal_Bool bHasShared = sal_False;
1641 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1642 xResultSet = aGroup.createCursor( aProps, eInclude );
1644 if ( xResultSet.is() )
1646 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1647 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1649 while ( xResultSet->next() )
1651 OUString aTemplTargetURL( xRow->getString( 1 ) );
1652 OUString aHierURL = xContentAccess->queryContentIdentifierString();
1654 if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1656 // this is a user template, and it can be removed
1657 if ( removeContent( aTemplTargetURL ) )
1658 removeContent( aHierURL );
1659 else
1660 bHasNonRemovable = sal_True;
1662 else
1663 bHasShared = sal_True;
1666 if ( !bHasNonRemovable && !bHasShared )
1668 if ( removeContent( aGroupTargetURL )
1669 || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1671 removeContent( aGroupURL );
1672 RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1673 bResult = sal_True; // the operation is successful only if the whole group is removed
1676 else if ( !bHasNonRemovable )
1678 if ( removeContent( aGroupTargetURL )
1679 || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1681 RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1682 setProperty( aGroup, aPropName, uno::makeAny( ::rtl::OUString() ) );
1687 catch ( Exception& ) {}
1690 return bResult;
1693 //-----------------------------------------------------------------------------
1694 sal_Bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName,
1695 const OUString& rNewName )
1697 ::osl::MutexGuard aGuard( maMutex );
1699 // create the group url
1700 Content aGroup;
1701 INetURLObject aGroupObj( maRootURL );
1702 aGroupObj.insertName( rNewName, false,
1703 INetURLObject::LAST_SEGMENT, true,
1704 INetURLObject::ENCODE_ALL );
1705 OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1707 // Check, if there is a group with the new name, return false
1708 // if there is one.
1709 if ( Content::create( aGroupURL, maCmdEnv, aGroup ) )
1710 return sal_False;
1712 aGroupObj.removeSegment();
1713 aGroupObj.insertName( rOldName, false,
1714 INetURLObject::LAST_SEGMENT, true,
1715 INetURLObject::ENCODE_ALL );
1716 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1718 // When there is no group with the old name, we can't rename it
1719 if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
1720 return sal_False;
1722 OUString aGroupTargetURL;
1723 // there is no need to check whether target dir url is in target path, since if the target path is changed
1724 // the target dir url should be already generated new
1725 OUString aPropName( TARGET_DIR_URL );
1726 Any aValue;
1727 if ( getProperty( aGroup, aPropName, aValue ) )
1728 aValue >>= aGroupTargetURL;
1730 if ( aGroupTargetURL.isEmpty() )
1731 return sal_False;
1733 if ( !maTemplateDirs.getLength() )
1734 return sal_False;
1735 ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1737 // check that the fs location is in writeble folder and this is not a "My templates" folder
1738 INetURLObject aGroupParentFolder( aGroupTargetURL );
1739 if ( !aGroupParentFolder.removeSegment()
1740 || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1741 aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1742 return sal_False;
1744 // check that the group can be renamed ( all the contents must be in target location )
1745 sal_Bool bCanBeRenamed = sal_False;
1748 uno::Reference< XResultSet > xResultSet;
1749 Sequence< OUString > aProps( 1 );
1751 aProps[0] = OUString(TARGET_URL );
1752 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1753 xResultSet = aGroup.createCursor( aProps, eInclude );
1755 if ( xResultSet.is() )
1757 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1758 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1760 while ( xResultSet->next() )
1762 OUString aTemplTargetURL( xRow->getString( 1 ) );
1764 if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1765 throw uno::Exception();
1768 bCanBeRenamed = sal_True;
1771 catch ( Exception& ) {}
1773 if ( bCanBeRenamed )
1775 INetURLObject aGroupTargetObj( aGroupTargetURL );
1776 ::rtl::OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1778 if ( aGroupTargetObj.removeSegment()
1779 && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ),
1780 aFsysName,
1781 rOldName,
1782 rNewName ) )
1784 // rename the group in the hierarchy
1785 OUString aTitleProp( TITLE );
1786 Any aTitleValue;
1787 aTitleValue <<= rNewName;
1789 return setProperty( aGroup, aTitleProp, aTitleValue );
1793 return sal_False;
1796 //-----------------------------------------------------------------------------
1797 sal_Bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName,
1798 const OUString& rTemplateName,
1799 const uno::Reference< XSTORABLE >& rStorable )
1801 ::osl::MutexGuard aGuard( maMutex );
1803 // Check, whether or not there is a group with this name
1804 // Return false, if there is no group with the given name
1805 Content aGroup, aTemplate, aTargetGroup, aTemplateToRemove;
1806 OUString aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL;
1807 INetURLObject aGroupObj( maRootURL );
1808 sal_Bool bRemoveOldTemplateContent = sal_False;
1809 ::rtl::OUString sDocServiceName;
1811 aGroupObj.insertName( rGroupName, false,
1812 INetURLObject::LAST_SEGMENT, true,
1813 INetURLObject::ENCODE_ALL );
1814 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1816 if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
1817 return sal_False;
1819 ::rtl::OUString aGroupTargetURL;
1820 ::rtl::OUString aPropName( TARGET_DIR_URL );
1821 Any aValue;
1822 if ( getProperty( aGroup, aPropName, aValue ) )
1823 aValue >>= aGroupTargetURL;
1826 // Check, if there's a template with the given name in this group
1827 // the target template should be overwritten if it is imported by user
1828 // in case the template is installed by office installation of by an add-in
1829 // it can not be replaced
1830 aGroupObj.insertName( rTemplateName, false,
1831 INetURLObject::LAST_SEGMENT, true,
1832 INetURLObject::ENCODE_ALL );
1833 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1835 if ( Content::create( aTemplateURL, maCmdEnv, aTemplateToRemove ) )
1837 OUString aTargetTemplPropName( TARGET_URL );
1839 bRemoveOldTemplateContent = sal_True;
1840 if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) )
1841 aValue >>= aTemplateToRemoveTargetURL;
1843 if ( aGroupTargetURL.isEmpty() || !maTemplateDirs.getLength()
1844 || (!aTemplateToRemoveTargetURL.isEmpty() && !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTemplateToRemoveTargetURL )) )
1845 return sal_False; // it is not allowed to remove the template
1850 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
1851 if ( !xFactory.is() )
1852 throw uno::RuntimeException();
1854 // get document service name
1855 uno::Reference< frame::XModuleManager > xModuleManager(
1856 xFactory->createInstance(
1857 ::rtl::OUString("com.sun.star.frame.ModuleManager") ),
1858 uno::UNO_QUERY_THROW );
1859 sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) );
1860 if ( sDocServiceName.isEmpty() )
1861 throw uno::RuntimeException();
1863 // get the actual filter name
1864 ::rtl::OUString aFilterName;
1866 uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
1867 xFactory->createInstance(
1868 ::rtl::OUString("com.sun.star.configuration.ConfigurationProvider") ),
1869 uno::UNO_QUERY_THROW );
1871 uno::Sequence< uno::Any > aArgs( 1 );
1872 beans::PropertyValue aPathProp;
1873 aPathProp.Name = ::rtl::OUString("nodepath");
1874 aPathProp.Value <<= ::rtl::OUString( "/org.openoffice.Setup/Office/Factories/" );
1875 aArgs[0] <<= aPathProp;
1877 uno::Reference< container::XNameAccess > xSOFConfig(
1878 xConfigProvider->createInstanceWithArguments(
1879 ::rtl::OUString("com.sun.star.configuration.ConfigurationAccess"),
1880 aArgs ),
1881 uno::UNO_QUERY_THROW );
1883 uno::Reference< container::XNameAccess > xApplConfig;
1884 xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig;
1885 if ( !xApplConfig.is() )
1886 throw uno::RuntimeException();
1888 xApplConfig->getByName( ::rtl::OUString( "ooSetupFactoryActualTemplateFilter" ) ) >>= aFilterName;
1889 if ( aFilterName.isEmpty() )
1890 throw uno::RuntimeException();
1892 // find the related type name
1893 ::rtl::OUString aTypeName;
1894 uno::Reference< container::XNameAccess > xFilterFactory(
1895 xFactory->createInstance( ::rtl::OUString("com.sun.star.document.FilterFactory") ),
1896 uno::UNO_QUERY_THROW );
1898 uno::Sequence< beans::PropertyValue > aFilterData;
1899 xFilterFactory->getByName( aFilterName ) >>= aFilterData;
1900 for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
1901 if ( aFilterData[nInd].Name == "Type" )
1902 aFilterData[nInd].Value >>= aTypeName;
1904 if ( aTypeName.isEmpty() )
1905 throw uno::RuntimeException();
1907 // find the mediatype and extension
1908 uno::Reference< container::XNameAccess > xTypeDetection =
1909 mxType.is() ?
1910 uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) :
1911 uno::Reference< container::XNameAccess >(
1912 xFactory->createInstance( ::rtl::OUString("com.sun.star.document.TypeDetection") ),
1913 uno::UNO_QUERY_THROW );
1915 SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) );
1916 uno::Sequence< ::rtl::OUString > aAllExt =
1917 aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString("Extensions"), Sequence< ::rtl::OUString >() );
1918 if ( !aAllExt.getLength() )
1919 throw uno::RuntimeException();
1921 ::rtl::OUString aMediaType = aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString("MediaType"), ::rtl::OUString() );
1922 ::rtl::OUString aExt = aAllExt[0];
1924 if ( aMediaType.isEmpty() || aExt.isEmpty() )
1925 throw uno::RuntimeException();
1927 // construct destination url
1928 if ( aGroupTargetURL.isEmpty() )
1930 aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1932 if ( aGroupTargetURL.isEmpty() )
1933 throw uno::RuntimeException();
1936 ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt );
1937 if ( aNewTemplateTargetURL.isEmpty() )
1939 aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, ::rtl::OUString( "UserTemplate" ), aExt );
1941 if ( aNewTemplateTargetURL.isEmpty() )
1942 throw uno::RuntimeException();
1945 // store template
1946 uno::Sequence< PropertyValue > aStoreArgs( 2 );
1947 aStoreArgs[0].Name = ::rtl::OUString("FilterName");
1948 aStoreArgs[0].Value <<= aFilterName;
1949 aStoreArgs[1].Name = ::rtl::OUString("DocumentTitle");
1950 aStoreArgs[1].Value <<= rTemplateName;
1952 ::rtl::OUString aCurrentDocumentURL = rStorable->getLocation();
1953 if( !::utl::UCBContentHelper::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() ))
1954 rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs );
1955 else
1956 rStorable->store();
1958 // the storing was successful, now the old template with the same name can be removed if it existed
1959 if ( !aTemplateToRemoveTargetURL.isEmpty() )
1961 removeContent( aTemplateToRemoveTargetURL );
1964 * pb: #i79496#
1965 * if the old template was the standard template
1966 * it is necessary to change the standard template with the new file name
1968 String sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName );
1969 if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) )
1971 SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL );
1975 if ( bRemoveOldTemplateContent )
1976 removeContent( aTemplateToRemove );
1978 // add the template to hierarchy
1979 return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType );
1981 catch( Exception& )
1983 // the template was not stored
1984 return sal_False;
1988 //-----------------------------------------------------------------------------
1989 sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName,
1990 const OUString& rTemplateName,
1991 const OUString& rSourceURL )
1993 ::osl::MutexGuard aGuard( maMutex );
1995 // Check, whether or not there is a group with this name
1996 // Return false, if there is no group with the given name
1997 Content aGroup, aTemplate, aTargetGroup;
1998 OUString aGroupURL, aTemplateURL;
1999 INetURLObject aGroupObj( maRootURL );
2001 aGroupObj.insertName( rGroupName, false,
2002 INetURLObject::LAST_SEGMENT, true,
2003 INetURLObject::ENCODE_ALL );
2004 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2006 if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
2007 return sal_False;
2009 // Check, if there's a template with the given name in this group
2010 // Return false, if there already is a template
2011 aGroupObj.insertName( rTemplateName, false,
2012 INetURLObject::LAST_SEGMENT, true,
2013 INetURLObject::ENCODE_ALL );
2014 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2016 if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2017 return sal_False;
2019 // get the target url of the group
2020 OUString aTargetURL;
2021 OUString aPropName( TARGET_DIR_URL );
2022 Any aValue;
2024 if ( getProperty( aGroup, aPropName, aValue ) )
2025 aValue >>= aTargetURL;
2027 if ( aTargetURL.isEmpty() )
2029 aTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
2031 if ( aTargetURL.isEmpty() )
2032 return sal_False;
2035 // Get the content type
2036 OUString aTitle, aType, aTargetURL2, aFullName;
2038 // only StarOffice documents are acceptable
2039 sal_Bool bDocHasTitle = sal_False;
2040 if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) )
2041 return sal_False;
2043 INetURLObject aSourceObj( rSourceURL );
2044 if ( rTemplateName.equals( aTitle ) )
2046 // addTemplate will sometimes be called just to add an entry in the
2047 // hierarchy; the target URL and the source URL will be the same in
2048 // this scenario
2049 // TODO/LATER: get rid of this old hack
2051 INetURLObject aTargetObj( aTargetURL );
2053 aTargetObj.insertName( rTemplateName, false,
2054 INetURLObject::LAST_SEGMENT, true,
2055 INetURLObject::ENCODE_ALL );
2056 aTargetObj.setExtension( aSourceObj.getExtension() );
2058 aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE );
2060 if ( aTargetURL2 == rSourceURL )
2061 return addEntry( aGroup, rTemplateName, aTargetURL2, aType );
2064 // copy the template into the new group (targeturl)
2066 INetURLObject aTmpURL( aSourceObj );
2067 aTmpURL.CutExtension();
2068 ::rtl::OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2070 ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() );
2071 INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL );
2072 ::rtl::OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2073 if ( aNewTemplateTargetURL.isEmpty() || aNewTemplateTargetName.isEmpty() )
2074 return sal_False;
2076 // get access to source file
2077 Content aSourceContent;
2078 uno::Reference < ucb::XCommandEnvironment > xEnv;
2079 INetURLObject aSourceURL( rSourceURL );
2080 if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) )
2081 return sal_False;
2083 if( ! Content::create( aTargetURL, xEnv, aTargetGroup ) )
2084 return sal_False;
2086 // transfer source file
2089 if( ! aTargetGroup.transferContent( aSourceContent,
2090 InsertOperation_COPY,
2091 aNewTemplateTargetName,
2092 NameClash::OVERWRITE ) )
2093 return sal_False;
2095 // allow to edit the added template
2096 Content aResultContent;
2097 if ( Content::create( aNewTemplateTargetURL, xEnv, aResultContent ) )
2099 ::rtl::OUString aPropertyName( "IsReadOnly" );
2100 uno::Any aProperty;
2101 sal_Bool bReadOnly = sal_False;
2102 if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly )
2103 setProperty( aResultContent, aPropertyName, uno::makeAny( (sal_Bool)sal_False ) );
2106 catch ( ContentCreationException& )
2107 { return sal_False; }
2108 catch ( Exception& )
2109 { return sal_False; }
2112 // either the document has title and it is the same as requested, or we have to set it
2113 sal_Bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) );
2114 if ( !bCorrectTitle )
2116 if ( !bDocHasTitle )
2118 INetURLObject aNewTmpObj( aNewTemplateTargetObj );
2119 aNewTmpObj.CutExtension();
2120 bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) );
2123 if ( !bCorrectTitle )
2124 bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName );
2127 if ( bCorrectTitle )
2129 // create a new entry in the hierarchy
2130 return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType );
2133 // TODO/LATER: The user could be notified here that the renaming has failed
2134 // create a new entry in the hierarchy
2135 addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType );
2136 return sal_False;
2139 //-----------------------------------------------------------------------------
2140 sal_Bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName,
2141 const OUString& rTemplateName )
2143 ::osl::MutexGuard aGuard( maMutex );
2145 // Check, whether or not there is a group with this name
2146 // Return false, if there is no group with the given name
2147 Content aGroup, aTemplate;
2148 OUString aGroupURL, aTemplateURL;
2149 INetURLObject aGroupObj( maRootURL );
2151 aGroupObj.insertName( rGroupName, false,
2152 INetURLObject::LAST_SEGMENT, true,
2153 INetURLObject::ENCODE_ALL );
2154 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2156 if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
2157 return sal_False;
2159 // Check, if there's a template with the given name in this group
2160 // Return false, if there is no template
2161 aGroupObj.insertName( rTemplateName, false,
2162 INetURLObject::LAST_SEGMENT, true,
2163 INetURLObject::ENCODE_ALL );
2164 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2166 if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2167 return sal_False;
2169 // get the target URL from the template
2170 OUString aTargetURL;
2171 OUString aPropName( TARGET_URL );
2172 Any aValue;
2174 if ( getProperty( aTemplate, aPropName, aValue ) )
2175 aValue >>= aTargetURL;
2177 // delete the target template
2178 if ( !aTargetURL.isEmpty() )
2180 if ( !maTemplateDirs.getLength()
2181 || !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTargetURL ) )
2182 return sal_False;
2184 removeContent( aTargetURL );
2187 // delete the template entry
2188 return removeContent( aTemplate );
2191 //-----------------------------------------------------------------------------
2192 sal_Bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName,
2193 const OUString& rOldName,
2194 const OUString& rNewName )
2196 ::osl::MutexGuard aGuard( maMutex );
2198 // Check, whether or not there is a group with this name
2199 // Return false, if there is no group with the given name
2200 Content aGroup, aTemplate;
2201 OUString aGroupURL, aTemplateURL;
2202 INetURLObject aGroupObj( maRootURL );
2204 aGroupObj.insertName( rGroupName, false,
2205 INetURLObject::LAST_SEGMENT, true,
2206 INetURLObject::ENCODE_ALL );
2207 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2209 if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) )
2210 return sal_False;
2212 // Check, if there's a template with the new name in this group
2213 // Return false, if there is one
2214 aGroupObj.insertName( rNewName, false,
2215 INetURLObject::LAST_SEGMENT, true,
2216 INetURLObject::ENCODE_ALL );
2217 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2219 if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2220 return sal_False;
2222 // Check, if there's a template with the old name in this group
2223 // Return false, if there is no template
2224 aGroupObj.removeSegment();
2225 aGroupObj.insertName( rOldName, false,
2226 INetURLObject::LAST_SEGMENT, true,
2227 INetURLObject::ENCODE_ALL );
2228 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2230 if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2231 return sal_False;
2233 OUString aTemplateTargetURL;
2234 OUString aTargetProp( TARGET_URL );
2235 Any aTargetValue;
2237 if ( getProperty( aTemplate, aTargetProp, aTargetValue ) )
2238 aTargetValue >>= aTemplateTargetURL;
2240 if ( !setTitleForURL( aTemplateTargetURL, rNewName ) )
2241 return sal_False;
2243 // rename the template entry in the cache
2244 OUString aTitleProp( TITLE );
2245 Any aTitleValue;
2246 aTitleValue <<= rNewName;
2248 return setProperty( aTemplate, aTitleProp, aTitleValue );
2251 //-----------------------------------------------------------------------------
2253 SFX_IMPL_XSERVICEINFO( SfxDocTplService, TEMPLATE_SERVICE_NAME, TEMPLATE_IMPLEMENTATION_NAME )
2254 SFX_IMPL_SINGLEFACTORY( SfxDocTplService )
2256 //-----------------------------------------------------------------------------
2257 SfxDocTplService::SfxDocTplService( const uno::Reference< XMultiServiceFactory >& xFactory )
2259 pImp = new SfxDocTplService_Impl( xFactory );
2262 //-----------------------------------------------------------------------------
2264 SfxDocTplService::~SfxDocTplService()
2266 delete pImp;
2269 //-----------------------------------------------------------------------------
2270 //--- XLocalizable ---
2271 //-----------------------------------------------------------------------------
2273 Locale SAL_CALL SfxDocTplService::getLocale()
2274 throw( RUNTIMEEXCEPTION )
2276 return pImp->getLocale();
2279 //-----------------------------------------------------------------------------
2281 void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale )
2282 throw( RUNTIMEEXCEPTION )
2284 pImp->setLocale( rLocale );
2287 //-----------------------------------------------------------------------------
2288 //--- XDocumentTemplates ---
2289 //-----------------------------------------------------------------------------
2290 uno::Reference< XCONTENT > SAL_CALL SfxDocTplService::getContent()
2291 throw( RUNTIMEEXCEPTION )
2293 if ( pImp->init() )
2294 return pImp->getContent().get();
2295 else
2296 return NULL;
2299 //-----------------------------------------------------------------------------
2300 sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName,
2301 const OUString& TemplateName,
2302 const uno::Reference< XSTORABLE >& Storable )
2303 throw( RUNTIMEEXCEPTION )
2305 if ( pImp->init() )
2306 return pImp->storeTemplate( GroupName, TemplateName, Storable );
2307 else
2308 return sal_False;
2311 //-----------------------------------------------------------------------------
2312 sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName,
2313 const OUString& rTemplateName,
2314 const OUString& rSourceURL )
2315 throw( RUNTIMEEXCEPTION )
2317 if ( pImp->init() )
2318 return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL );
2319 else
2320 return sal_False;
2323 //-----------------------------------------------------------------------------
2324 sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName,
2325 const OUString& rTemplateName )
2326 throw( RUNTIMEEXCEPTION )
2328 if ( pImp->init() )
2329 return pImp->removeTemplate( rGroupName, rTemplateName );
2330 else
2331 return sal_False;
2334 //-----------------------------------------------------------------------------
2335 sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName,
2336 const OUString& rOldName,
2337 const OUString& rNewName )
2338 throw( RUNTIMEEXCEPTION )
2340 if ( rOldName == rNewName )
2341 return sal_True;
2343 if ( pImp->init() )
2344 return pImp->renameTemplate( rGroupName, rOldName, rNewName );
2345 else
2346 return sal_False;
2349 //-----------------------------------------------------------------------------
2350 sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName )
2351 throw( RUNTIMEEXCEPTION )
2353 if ( pImp->init() )
2354 return pImp->addGroup( rGroupName );
2355 else
2356 return sal_False;
2359 //-----------------------------------------------------------------------------
2360 sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName )
2361 throw( RUNTIMEEXCEPTION )
2363 if ( pImp->init() )
2364 return pImp->removeGroup( rGroupName );
2365 else
2366 return sal_False;
2369 //-----------------------------------------------------------------------------
2370 sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName,
2371 const OUString& rNewName )
2372 throw( RUNTIMEEXCEPTION )
2374 if ( rOldName == rNewName )
2375 return sal_True;
2377 if ( pImp->init() )
2378 return pImp->renameGroup( rOldName, rNewName );
2379 else
2380 return sal_False;
2383 //-----------------------------------------------------------------------------
2384 void SAL_CALL SfxDocTplService::update()
2385 throw( RUNTIMEEXCEPTION )
2387 if ( pImp->init() )
2388 pImp->update( sal_True );
2391 //------------------------------------------------------------------------
2393 Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2395 mpDocTemplates = pTemplates;
2398 //------------------------------------------------------------------------
2399 Updater_Impl::~Updater_Impl()
2403 //------------------------------------------------------------------------
2404 void SAL_CALL Updater_Impl::run()
2406 mpDocTemplates->doUpdate();
2409 //------------------------------------------------------------------------
2410 void SAL_CALL Updater_Impl::onTerminated()
2412 mpDocTemplates->finished();
2413 delete this;
2416 //-----------------------------------------------------------------------------
2417 WaitWindow_Impl::WaitWindow_Impl()
2418 : WorkWindow( NULL, WB_BORDER | WB_3DLOOK )
2420 Rectangle aRect = Rectangle( 0, 0, 300, 30000 );
2421 _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE;
2422 _aText = String( SfxResId( RID_CNT_STR_WAITING ) );
2423 _aRect = GetTextRect( aRect, _aText, _nTextStyle );
2424 aRect = _aRect;
2425 aRect.Right() += 2*X_OFFSET;
2426 aRect.Bottom() += 2*Y_OFFSET;
2427 _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) );
2428 SetOutputSizePixel( aRect.GetSize() );
2429 Show();
2430 Update();
2431 Flush();
2434 //-----------------------------------------------------------------------------
2435 WaitWindow_Impl::~WaitWindow_Impl()
2437 Hide();
2440 //-----------------------------------------------------------------------------
2441 void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ )
2443 DrawText( _aRect, _aText, _nTextStyle );
2446 //-----------------------------------------------------------------------------
2447 void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList,
2448 const OUString& rTitle,
2449 const OUString& rOwnURL )
2451 // now get the content of the Group
2452 Content aContent;
2453 uno::Reference< XResultSet > xResultSet;
2454 Sequence< OUString > aProps(3);
2456 aProps[0] = OUString(TITLE );
2457 aProps[1] = OUString(TARGET_URL );
2458 aProps[2] = OUString(PROPERTY_TYPE );
2462 aContent = Content( rOwnURL, maCmdEnv );
2463 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2464 xResultSet = aContent.createCursor( aProps, eInclude );
2466 catch ( ContentCreationException& )
2468 SAL_WARN( "sfx2.doc", "addHierGroup: ContentCreationException" );
2470 catch ( Exception& ) {}
2472 if ( xResultSet.is() )
2474 GroupData_Impl *pGroup = new GroupData_Impl( rTitle );
2475 pGroup->setHierarchy( sal_True );
2476 pGroup->setHierarchyURL( rOwnURL );
2477 rList.push_back( pGroup );
2479 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2480 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2484 while ( xResultSet->next() )
2486 sal_Bool bUpdateType = sal_False;
2487 DocTemplates_EntryData_Impl *pData;
2489 OUString aTitle( xRow->getString( 1 ) );
2490 OUString aTargetDir( xRow->getString( 2 ) );
2491 OUString aType( xRow->getString( 3 ) );
2492 OUString aHierURL = xContentAccess->queryContentIdentifierString();
2494 if ( aType.isEmpty() )
2496 OUString aTmpTitle;
2498 sal_Bool bDocHasTitle = sal_False;
2499 if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) )
2501 SAL_WARN( "sfx2.doc", "addHierGroup(): template of alien format" );
2502 continue;
2505 if ( !aType.isEmpty() )
2506 bUpdateType = sal_True;
2509 pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL );
2510 pData->setUpdateType( bUpdateType );
2513 catch ( Exception& ) {}
2517 //-----------------------------------------------------------------------------
2518 void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList,
2519 const OUString& rTitle,
2520 const OUString& rUITitle,
2521 const OUString& rOwnURL,
2522 sal_Bool bWriteableGroup )
2524 ::rtl::OUString aTitle;
2526 if ( rUITitle.isEmpty() )
2528 // reserved FS names that should not be used
2529 if ( rTitle.compareToAscii( "wizard" ) == 0 )
2530 return;
2531 else if ( rTitle.compareToAscii( "internal" ) == 0 )
2532 return;
2534 aTitle = getLongName( rTitle );
2536 else
2537 aTitle = rUITitle;
2539 if ( aTitle.isEmpty() )
2540 return;
2542 GroupData_Impl* pGroup = NULL;
2543 for ( size_t i = 0, n = rList.size(); i < n; ++i )
2545 if ( rList[ i ]->getTitle() == aTitle )
2547 pGroup = rList[ i ];
2548 break;
2552 if ( !pGroup )
2554 pGroup = new GroupData_Impl( aTitle );
2555 rList.push_back( pGroup );
2558 if ( bWriteableGroup )
2559 pGroup->setTargetURL( rOwnURL );
2561 pGroup->setInUse();
2563 // now get the content of the Group
2564 Content aContent;
2565 uno::Reference< XResultSet > xResultSet;
2566 Sequence< OUString > aProps(1);
2567 aProps[0] = OUString(TITLE );
2571 // this method is only used during checking of the available template-folders
2572 // that should happen quietly
2573 uno::Reference< XCommandEnvironment > aQuietEnv;
2574 aContent = Content( rOwnURL, aQuietEnv );
2575 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2576 xResultSet = aContent.createCursor( aProps, eInclude );
2578 catch ( Exception& ) {}
2580 if ( xResultSet.is() )
2582 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2583 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2587 while ( xResultSet->next() )
2589 OUString aChildTitle( xRow->getString( 1 ) );
2590 OUString aTargetURL = xContentAccess->queryContentIdentifierString();
2591 OUString aType;
2592 OUString aHierURL;
2594 if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0 || aChildTitle == "groupuinames.xml" )
2595 continue;
2597 // only StarOffice templates are accepted
2598 sal_Bool bDocHasTitle = sal_False;
2599 if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) )
2600 continue;
2602 pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL );
2605 catch ( Exception& ) {}
2609 // -----------------------------------------------------------------------
2610 void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList,
2611 Content &rContent,
2612 sal_Bool bHierarchy,
2613 sal_Bool bWriteableContent )
2615 OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier();
2617 // when scanning the file system, we have to add the 'standard' group, too
2618 if ( ! bHierarchy )
2620 OUString aUIStdTitle = getLongName( OUString( STANDARD_FOLDER ) );
2621 addFsysGroup( rList, ::rtl::OUString(), aUIStdTitle, aTargetURL, bWriteableContent );
2624 // search for predefined UI names
2625 INetURLObject aLayerObj( aTargetURL );
2627 // TODO/LATER: Use hashmap in future
2628 uno::Sequence< beans::StringPair > aUINames;
2629 if ( !bHierarchy )
2630 aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) );
2632 uno::Reference< XResultSet > xResultSet;
2633 Sequence< OUString > aProps(1);
2634 aProps[0] = OUString(TITLE );
2638 ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
2639 xResultSet = rContent.createCursor( aProps, eInclude );
2641 catch ( Exception& ) {}
2643 if ( xResultSet.is() )
2645 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2646 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2650 while ( xResultSet->next() )
2652 // TODO/LATER: clarify the encoding of the Title
2653 OUString aTitle( xRow->getString( 1 ) );
2654 OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() );
2656 if ( bHierarchy )
2657 addHierGroup( rList, aTitle, aTargetSubfolderURL );
2658 else
2660 ::rtl::OUString aUITitle;
2661 for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ )
2662 if ( aUINames[nInd].First.equals( aTitle ) )
2664 aUITitle = aUINames[nInd].Second;
2665 break;
2668 addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent );
2672 catch ( Exception& ) {}
2676 //-----------------------------------------------------------------------------
2677 void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData )
2679 Content aTemplate;
2681 if ( Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2683 removeContent( aTemplate );
2687 //-----------------------------------------------------------------------------
2688 void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup,
2689 DocTemplates_EntryData_Impl *pData )
2691 Content aGroup, aTemplate;
2693 if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2694 return;
2696 // Check, if there's a template with the given name in this group
2697 // Return if there is already a template
2698 INetURLObject aGroupObj( pGroup->getHierarchyURL() );
2700 aGroupObj.insertName( pData->getTitle(), false,
2701 INetURLObject::LAST_SEGMENT, true,
2702 INetURLObject::ENCODE_ALL );
2704 OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2706 if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) )
2707 return;
2709 addEntry( aGroup, pData->getTitle(),
2710 pData->getTargetURL(),
2711 pData->getType() );
2714 //-----------------------------------------------------------------------------
2715 void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData )
2717 Content aTemplate;
2719 if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) )
2720 return;
2722 OUString aPropName;
2724 if ( pData->getUpdateType() )
2726 aPropName = OUString( PROPERTY_TYPE );
2727 setProperty( aTemplate, aPropName, makeAny( pData->getType() ) );
2730 if ( pData->getUpdateLink() )
2732 aPropName = OUString( TARGET_URL );
2733 setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) );
2737 //-----------------------------------------------------------------------------
2738 void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup )
2740 OUString aAdditionalProp( TARGET_DIR_URL );
2741 Content aGroup;
2743 INetURLObject aNewGroupObj( maRootURL );
2744 aNewGroupObj.insertName( pGroup->getTitle(), false,
2745 INetURLObject::LAST_SEGMENT, true,
2746 INetURLObject::ENCODE_ALL );
2748 OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2750 if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) )
2752 setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) );
2753 pGroup->setHierarchyURL( aNewGroupURL );
2755 sal_uIntPtr nCount = pGroup->count();
2756 for ( sal_uIntPtr i=0; i<nCount; i++ )
2758 DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
2759 addToHierarchy( pGroup, pData ); // add entry to hierarchy
2764 //-----------------------------------------------------------------------------
2765 void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup )
2767 Content aGroup;
2769 if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) )
2771 removeContent( aGroup );
2775 // -----------------------------------------------------------------------
2776 GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2778 maTitle = rTitle;
2779 mbInUse = sal_False;
2780 mbInHierarchy = sal_False;
2783 // -----------------------------------------------------------------------
2784 GroupData_Impl::~GroupData_Impl()
2786 for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2787 delete maEntries[ i ];
2788 maEntries.clear();
2791 // -----------------------------------------------------------------------
2792 DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle,
2793 const OUString& rTargetURL,
2794 const OUString& rType,
2795 const OUString& rHierURL )
2797 DocTemplates_EntryData_Impl* pData = NULL;
2798 bool EntryFound = false;
2800 for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2802 pData = maEntries[ i ];
2803 if ( pData->getTitle() == rTitle )
2805 EntryFound = true;
2806 break;
2810 if ( !EntryFound )
2812 pData = new DocTemplates_EntryData_Impl( rTitle );
2813 pData->setTargetURL( rTargetURL );
2814 pData->setType( rType );
2815 if ( !rHierURL.isEmpty() )
2817 pData->setHierarchyURL( rHierURL );
2818 pData->setHierarchy( sal_True );
2820 maEntries.push_back( pData );
2822 else
2824 if ( !rHierURL.isEmpty() )
2826 pData->setHierarchyURL( rHierURL );
2827 pData->setHierarchy( sal_True );
2830 if ( pData->getInHierarchy() )
2831 pData->setInUse();
2833 if ( rTargetURL != pData->getTargetURL() )
2835 pData->setTargetURL( rTargetURL );
2836 pData->setUpdateLink( sal_True );
2840 return pData;
2843 // -----------------------------------------------------------------------
2844 DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle )
2846 maTitle = rTitle;
2847 mbInUse = sal_False;
2848 mbInHierarchy = sal_False;
2849 mbUpdateType = sal_False;
2850 mbUpdateLink = sal_False;
2853 // -----------------------------------------------------------------------
2854 SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory )
2855 : mxFactory( xFactory )
2859 // -----------------------------------------------------------------------
2860 SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2864 // -----------------------------------------------------------------------
2865 void SfxURLRelocator_Impl::initOfficeInstDirs()
2867 if ( !mxOfficeInstDirs.is() )
2869 osl::MutexGuard aGuard( maMutex );
2870 if ( !mxOfficeInstDirs.is() )
2872 OSL_ENSURE( mxFactory.is(), "No service manager!" );
2874 uno::Reference< XComponentContext > xCtx;
2875 uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY );
2876 if ( xPropSet.is() )
2878 xPropSet->getPropertyValue(
2879 rtl::OUString(
2880 "DefaultContext" ) )
2881 >>= xCtx;
2884 OSL_ENSURE( xCtx.is(),
2885 "Unable to obtain component context from "
2886 "service manager!" );
2888 if ( xCtx.is() )
2890 xCtx->getValueByName(
2891 rtl::OUString(
2892 "/singletons/"
2893 "com.sun.star.util.theOfficeInstallationDirectories" ) )
2894 >>= mxOfficeInstDirs;
2897 OSL_ENSURE( mxOfficeInstDirs.is(),
2898 "Unable to obtain office installation directory "
2899 "singleton!" );
2904 // -----------------------------------------------------------------------
2905 void SfxURLRelocator_Impl::implExpandURL( ::rtl::OUString& io_url )
2907 const INetURLObject aParser( io_url );
2908 if ( aParser.GetProtocol() != INET_PROT_VND_SUN_STAR_EXPAND )
2909 return;
2911 io_url = aParser.GetURLPath( INetURLObject::DECODE_WITH_CHARSET );
2914 if ( !mxMacroExpander.is() )
2916 ::comphelper::ComponentContext aContext( mxFactory );
2917 mxMacroExpander.set( aContext.getSingleton( "com.sun.star.util.theMacroExpander" ), UNO_QUERY_THROW );
2919 io_url = mxMacroExpander->expandMacros( io_url );
2921 catch( const Exception& )
2923 DBG_UNHANDLED_EXCEPTION();
2927 // -----------------------------------------------------------------------
2928 void SfxURLRelocator_Impl::makeRelocatableURL( rtl::OUString & rURL )
2930 if ( !rURL.isEmpty() )
2932 initOfficeInstDirs();
2933 implExpandURL( rURL );
2934 rURL = mxOfficeInstDirs->makeRelocatableURL( rURL );
2938 // -----------------------------------------------------------------------
2939 void SfxURLRelocator_Impl::makeAbsoluteURL( rtl::OUString & rURL )
2941 if ( !rURL.isEmpty() )
2943 initOfficeInstDirs();
2944 implExpandURL( rURL );
2945 rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL );
2950 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */