Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / doc / doctemplates.cxx
blob610684d1d3849cbe0125d4a55cfbc4a44ffcd786
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "doctemplates.hxx"
22 #include <osl/mutex.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/diagnose_ex.h>
25 #include <tools/urlobj.hxx>
26 #include <rtl/ustring.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <tools/resary.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/wrkwin.hxx>
31 #include <unotools/pathoptions.hxx>
32 #include <comphelper/componentcontext.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/sequenceashashmap.hxx>
35 #include <comphelper/storagehelper.hxx>
36 #include <comphelper/string.hxx>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertySetInfo.hpp>
40 #include <com/sun/star/beans/XPropertyContainer.hpp>
41 #include <com/sun/star/beans/StringPair.hpp>
42 #include <com/sun/star/util/theMacroExpander.hpp>
43 #include <com/sun/star/util/theOfficeInstallationDirectories.hpp>
44 #include <com/sun/star/configuration/theDefaultProvider.hpp>
45 #include <com/sun/star/container/XContainerQuery.hpp>
46 #include <com/sun/star/document/XTypeDetection.hpp>
47 #include <com/sun/star/document/DocumentProperties.hpp>
48 #include <com/sun/star/io/TempFile.hpp>
49 #include <com/sun/star/sdbc/XResultSet.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/ucb/NameClash.hpp>
52 #include <com/sun/star/ucb/NameClashException.hpp>
53 #include <com/sun/star/ucb/TransferInfo.hpp>
54 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
55 #include <com/sun/star/ucb/XContentAccess.hpp>
56 #include <com/sun/star/frame/ModuleManager.hpp>
57 #include <com/sun/star/uno/Exception.hpp>
59 #include <svtools/templatefoldercache.hxx>
60 #include <unotools/configmgr.hxx>
61 #include <unotools/ucbhelper.hxx>
63 #include "sfx2/sfxresid.hxx"
64 #include "sfxurlrelocator.hxx"
65 #include "doctemplateslocal.hxx"
66 #include <sfx2/docfac.hxx>
67 #include <sfx2/docfile.hxx>
68 #include "doc.hrc"
70 #include <vector>
72 //-----------------------------------------------------------------------------
74 //=============================================================================
76 #define TEMPLATE_SERVICE_NAME "com.sun.star.frame.DocumentTemplates"
77 #define TEMPLATE_IMPLEMENTATION_NAME "com.sun.star.comp.sfx2.DocumentTemplates"
79 #define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection"
81 #define TEMPLATE_ROOT_URL "vnd.sun.star.hier:/templates"
82 #define TITLE "Title"
83 #define IS_FOLDER "IsFolder"
84 #define IS_DOCUMENT "IsDocument"
85 #define TARGET_URL "TargetURL"
86 #define TEMPLATE_VERSION "TemplateComponentVersion"
87 #define TEMPLATE_VERSION_VALUE "2"
88 #define TYPE_FOLDER "application/vnd.sun.star.hier-folder"
89 #define TYPE_LINK "application/vnd.sun.star.hier-link"
90 #define TYPE_FSYS_FOLDER "application/vnd.sun.staroffice.fsys-folder"
91 #define TYPE_FSYS_FILE "application/vnd.sun.staroffice.fsys-file"
93 #define PROPERTY_DIRLIST "DirectoryList"
94 #define PROPERTY_NEEDSUPDATE "NeedsUpdate"
95 #define PROPERTY_TYPE "TypeDescription"
97 #define TARGET_DIR_URL "TargetDirURL"
98 #define COMMAND_DELETE "delete"
100 #define STANDARD_FOLDER "standard"
102 #define C_DELIM ';'
104 //=============================================================================
106 using namespace ::com::sun::star;
107 using namespace ::com::sun::star::beans;
108 using namespace ::com::sun::star::document;
109 using namespace ::com::sun::star::io;
110 using namespace ::com::sun::star::lang;
111 using namespace ::com::sun::star::sdbc;
112 using namespace ::com::sun::star::ucb;
113 using namespace ::com::sun::star::uno;
114 using namespace ::com::sun::star::container;
115 using namespace ::com::sun::star::util;
117 using namespace ::ucbhelper;
118 using namespace ::comphelper;
120 using ::std::vector;
122 //=============================================================================
124 class WaitWindow_Impl : public WorkWindow
126 Rectangle _aRect;
127 sal_uInt16 _nTextStyle;
128 String _aText;
130 public:
131 WaitWindow_Impl();
132 ~WaitWindow_Impl();
133 virtual void Paint( const Rectangle& rRect );
136 #define X_OFFSET 15
137 #define Y_OFFSET 15
139 //=============================================================================
141 struct NamePair_Impl
143 OUString maShortName;
144 OUString maLongName;
147 class Updater_Impl;
148 class DocTemplates_EntryData_Impl;
149 class GroupData_Impl;
151 typedef vector< NamePair_Impl* > NameList_Impl;
152 typedef vector< GroupData_Impl* > GroupList_Impl;
154 //=============================================================================
155 #include <com/sun/star/task/InteractionHandler.hpp>
156 #include <com/sun/star/ucb/XProgressHandler.hpp>
158 class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment >
160 uno::Reference< task::XInteractionHandler > m_xInteractionHandler;
161 uno::Reference< ucb::XProgressHandler > m_xProgressHandler;
163 public:
164 TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler )
165 : m_xInteractionHandler( rxInteractionHandler )
168 virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException)
169 { return m_xInteractionHandler; }
171 virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler() throw (uno::RuntimeException)
172 { return m_xProgressHandler; }
175 class SfxDocTplService_Impl
177 uno::Reference< XComponentContext > mxContext;
178 uno::Reference< XCommandEnvironment > maCmdEnv;
179 uno::Reference< XDocumentProperties> m_xDocProps;
180 uno::Reference< XTypeDetection > mxType;
182 ::osl::Mutex maMutex;
183 Sequence< OUString > maTemplateDirs;
184 OUString maRootURL;
185 NameList_Impl maNames;
186 Locale maLocale;
187 Content maRootContent;
188 Updater_Impl* mpUpdater;
189 sal_Bool mbIsInitialized : 1;
190 sal_Bool mbLocaleSet : 1;
192 SfxURLRelocator_Impl maRelocator;
194 void init_Impl();
195 void getDefaultLocale();
196 void getDirList();
197 void readFolderList();
198 sal_Bool needsUpdate();
199 OUString getLongName( const OUString& rShortName );
200 sal_Bool setTitleForURL( const OUString& rURL, const OUString& aTitle );
201 sal_Bool getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle );
203 sal_Bool addEntry( Content& rParentFolder,
204 const OUString& rTitle,
205 const OUString& rTargetURL,
206 const OUString& rType );
208 sal_Bool createFolder( const OUString& rNewFolderURL,
209 sal_Bool bCreateParent,
210 sal_Bool bFsysFolder,
211 Content &rNewFolder );
213 sal_Bool CreateNewUniqueFolderWithPrefix( const OUString& aPath,
214 const OUString& aPrefix,
215 OUString& aNewFolderName,
216 OUString& aNewFolderURL,
217 Content& aNewFolder );
218 OUString CreateNewUniqueFileWithPrefix( const OUString& aPath,
219 const OUString& aPrefix,
220 const OUString& aExt );
222 uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const OUString& aUserPath );
223 sal_Bool UpdateUINamesForTemplateDir_Impl( const OUString& aUserPath,
224 const OUString& aGroupName,
225 const OUString& aNewFolderName );
226 sal_Bool ReplaceUINamesForTemplateDir_Impl( const OUString& aUserPath,
227 const OUString& aFsysGroupName,
228 const OUString& aOldGroupName,
229 const OUString& aNewGroupName );
230 sal_Bool RemoveUINamesForTemplateDir_Impl( const OUString& aUserPath,
231 const OUString& aGroupName );
232 sal_Bool WriteUINamesForTemplateDir_Impl( const OUString& aUserPath,
233 const uno::Sequence< beans::StringPair >& aUINames );
235 OUString CreateNewGroupFsys( const OUString& rGroupName, Content& aGroup );
237 sal_Bool removeContent( Content& rContent );
238 sal_Bool removeContent( const OUString& rContentURL );
240 sal_Bool setProperty( Content& rContent,
241 const OUString& rPropName,
242 const Any& rPropValue );
243 sal_Bool getProperty( Content& rContent,
244 const OUString& rPropName,
245 Any& rPropValue );
247 void createFromContent( GroupList_Impl& rList,
248 Content &rContent,
249 sal_Bool bHierarchy,
250 sal_Bool bWriteableContent = sal_False );
251 void addHierGroup( GroupList_Impl& rList,
252 const OUString& rTitle,
253 const OUString& rOwnURL );
254 void addFsysGroup( GroupList_Impl& rList,
255 const OUString& rTitle,
256 const OUString& rUITitle,
257 const OUString& rOwnURL,
258 sal_Bool bWriteableGroup = sal_False );
259 void removeFromHierarchy( DocTemplates_EntryData_Impl *pData );
260 void addToHierarchy( GroupData_Impl *pGroup,
261 DocTemplates_EntryData_Impl *pData );
263 void removeFromHierarchy( GroupData_Impl *pGroup );
264 void addGroupToHierarchy( GroupData_Impl *pGroup );
266 void updateData( DocTemplates_EntryData_Impl *pData );
268 public:
269 SfxDocTplService_Impl( const uno::Reference< XComponentContext > & xContext );
270 ~SfxDocTplService_Impl();
272 sal_Bool init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; }
273 Content getContent() const { return maRootContent; }
275 void setLocale( const Locale & rLocale );
276 Locale getLocale();
278 sal_Bool storeTemplate( const OUString& rGroupName,
279 const OUString& rTemplateName,
280 const uno::Reference< frame::XStorable >& rStorable );
282 sal_Bool addTemplate( const OUString& rGroupName,
283 const OUString& rTemplateName,
284 const OUString& rSourceURL );
285 sal_Bool removeTemplate( const OUString& rGroupName,
286 const OUString& rTemplateName );
287 sal_Bool renameTemplate( const OUString& rGroupName,
288 const OUString& rOldName,
289 const OUString& rNewName );
291 sal_Bool addGroup( const OUString& rGroupName );
292 sal_Bool removeGroup( const OUString& rGroupName );
293 sal_Bool renameGroup( const OUString& rOldName,
294 const OUString& rNewName );
296 void update( sal_Bool bUpdateNow );
297 void doUpdate();
298 void finished() { mpUpdater = NULL; }
301 //=============================================================================
303 class Updater_Impl : public ::osl::Thread
305 private:
306 SfxDocTplService_Impl *mpDocTemplates;
308 public:
309 Updater_Impl( SfxDocTplService_Impl* pTemplates );
310 ~Updater_Impl();
312 virtual void SAL_CALL run();
313 virtual void SAL_CALL onTerminated();
316 //=============================================================================
318 class DocTemplates_EntryData_Impl
320 OUString maTitle;
321 OUString maType;
322 OUString maTargetURL;
323 OUString maHierarchyURL;
325 sal_Bool mbInHierarchy : 1;
326 sal_Bool mbInUse : 1;
327 sal_Bool mbUpdateType : 1;
328 sal_Bool mbUpdateLink : 1;
330 public:
331 DocTemplates_EntryData_Impl( const OUString& rTitle );
333 void setInUse() { mbInUse = sal_True; }
334 void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
335 void setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; }
336 void setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; }
338 sal_Bool getInUse() const { return mbInUse; }
339 sal_Bool getInHierarchy() const { return mbInHierarchy; }
340 sal_Bool getUpdateLink() const { return mbUpdateLink; }
341 sal_Bool getUpdateType() const { return mbUpdateType; }
343 const OUString& getHierarchyURL() const { return maHierarchyURL; }
344 const OUString& getTargetURL() const { return maTargetURL; }
345 const OUString& getTitle() const { return maTitle; }
346 const OUString& getType() const { return maType; }
348 void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
349 void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
350 void setType( const OUString& rType ) { maType = rType; }
353 //=============================================================================
355 class GroupData_Impl
357 vector< DocTemplates_EntryData_Impl* > maEntries;
358 OUString maTitle;
359 OUString maHierarchyURL;
360 OUString maTargetURL;
361 sal_Bool mbInUse : 1;
362 sal_Bool mbInHierarchy : 1;
364 public:
365 GroupData_Impl( const OUString& rTitle );
366 ~GroupData_Impl();
368 void setInUse() { mbInUse = sal_True; }
369 void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
370 void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
371 void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
373 sal_Bool getInUse() const { return mbInUse; }
374 sal_Bool getInHierarchy() const { return mbInHierarchy; }
375 const OUString& getHierarchyURL() const { return maHierarchyURL; }
376 const OUString& getTargetURL() const { return maTargetURL; }
377 const OUString& getTitle() const { return maTitle; }
379 DocTemplates_EntryData_Impl* addEntry( const OUString& rTitle,
380 const OUString& rTargetURL,
381 const OUString& rType,
382 const OUString& rHierURL );
383 size_t count() { return maEntries.size(); }
384 DocTemplates_EntryData_Impl* getEntry( size_t nPos ) { return maEntries[ nPos ]; }
387 //-----------------------------------------------------------------------------
388 // private SfxDocTplService_Impl
389 //-----------------------------------------------------------------------------
390 void SfxDocTplService_Impl::init_Impl()
392 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
393 uno::Reference < task::XInteractionHandler > xInteractionHandler(
394 task::InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
395 maCmdEnv = new TplTaskEnvironment( xInteractionHandler );
397 ::osl::ClearableMutexGuard aGuard( maMutex );
398 sal_Bool bIsInitialized = sal_False;
399 sal_Bool bNeedsUpdate = sal_False;
401 if ( !mbLocaleSet )
402 getDefaultLocale();
404 // convert locale to string
405 OUString aLang = maLocale.Language;
406 aLang += OUString( '-' );
407 aLang += maLocale.Country;
409 // set maRootContent to the root of the templates hierarchy. Create the
410 // entry if necessary
412 maRootURL = OUString( TEMPLATE_ROOT_URL );
413 maRootURL += OUString( '/' );
414 maRootURL += aLang;
416 OUString aTemplVersPropName( TEMPLATE_VERSION );
417 OUString aTemplVers( TEMPLATE_VERSION_VALUE );
418 if ( Content::create( maRootURL, maCmdEnv, comphelper::getProcessComponentContext(), maRootContent ) )
420 uno::Any aValue;
421 OUString aPropValue;
422 if ( getProperty( maRootContent, aTemplVersPropName, aValue )
423 && ( aValue >>= aPropValue )
424 && aPropValue.equals( aTemplVers ) )
426 bIsInitialized = sal_True;
428 else
429 removeContent( maRootContent );
432 if ( !bIsInitialized )
434 if ( createFolder( maRootURL, sal_True, sal_False, maRootContent )
435 && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) )
436 bIsInitialized = sal_True;
438 bNeedsUpdate = sal_True;
441 if ( bIsInitialized )
443 try {
444 m_xDocProps.set(document::DocumentProperties::create(
445 ::comphelper::getProcessComponentContext()));
446 } catch (uno::RuntimeException const& e) {
447 SAL_WARN("sfx2.doc", "SfxDocTplService_Impl::init_Impl: "
448 "cannot create DocumentProperties service:" << e.Message);
451 OUString const aService = OUString( SERVICENAME_TYPEDETECTION );
452 mxType = uno::Reference< XTypeDetection > ( mxContext->getServiceManager()->createInstanceWithContext(aService, mxContext), UNO_QUERY );
454 getDirList();
455 readFolderList();
457 if ( bNeedsUpdate )
459 aGuard.clear();
460 SolarMutexClearableGuard aSolarGuard;
462 WaitWindow_Impl* pWin = new WaitWindow_Impl();
464 aSolarGuard.clear();
465 ::osl::ClearableMutexGuard anotherGuard( maMutex );
467 update( sal_True );
469 anotherGuard.clear();
470 SolarMutexGuard aSecondSolarGuard;
472 delete pWin;
474 else if ( needsUpdate() )
475 // the UI should be shown only on the first update
476 update( sal_True );
478 else
480 SAL_WARN( "sfx2.doc", "init_Impl(): Could not create root" );
483 mbIsInitialized = bIsInitialized;
486 //-----------------------------------------------------------------------------
487 void SfxDocTplService_Impl::getDefaultLocale()
489 if ( !mbLocaleSet )
491 ::osl::MutexGuard aGuard( maMutex );
492 if ( !mbLocaleSet )
494 OUString aLocale( utl::ConfigManager::getLocale() );
495 if ( !aLocale.isEmpty() )
497 sal_Int32 nPos = aLocale.indexOf( sal_Unicode( '-' ) );
498 if ( nPos != -1 )
500 maLocale.Language = aLocale.copy( 0, nPos );
501 nPos = aLocale.indexOf( sal_Unicode( '_' ), nPos + 1 );
502 if ( nPos != -1 )
504 maLocale.Country
505 = aLocale.copy( maLocale.Language.getLength() + 1,
506 nPos - maLocale.Language.getLength() - 1 );
507 maLocale.Variant
508 = aLocale.copy( nPos + 1 );
510 else
512 maLocale.Country
513 = aLocale.copy( maLocale.Language.getLength() + 1 );
519 mbLocaleSet = sal_True;
524 // -----------------------------------------------------------------------
525 void SfxDocTplService_Impl::readFolderList()
527 SolarMutexGuard aGuard;
529 ResStringArray aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) );
530 ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) );
532 NamePair_Impl* pPair;
534 sal_uInt16 nCount = (sal_uInt16)( std::min( aShortNames.Count(), aLongNames.Count() ) );
536 for ( sal_uInt16 i=0; i<nCount; i++ )
538 pPair = new NamePair_Impl;
539 pPair->maShortName = aShortNames.GetString( i );
540 pPair->maLongName = aLongNames.GetString( i );
542 maNames.push_back( pPair );
546 // -----------------------------------------------------------------------
547 OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName )
549 OUString aRet;
551 for ( size_t i = 0, n = maNames.size(); i < n; ++i )
553 NamePair_Impl* pPair = maNames[ i ];
554 if ( pPair->maShortName == rShortName )
556 aRet = pPair->maLongName;
557 break;
561 if ( aRet.isEmpty() )
562 aRet = rShortName;
564 return aRet;
567 //-----------------------------------------------------------------------------
568 void SfxDocTplService_Impl::getDirList()
570 OUString aPropName( PROPERTY_DIRLIST );
571 Any aValue;
573 // Get the template dir list
574 // TODO/LATER: let use service, register listener
575 INetURLObject aURL;
576 String aDirs = SvtPathOptions().GetTemplatePath();
577 sal_uInt16 nCount = comphelper::string::getTokenCount(aDirs, C_DELIM);
579 maTemplateDirs = Sequence< OUString >( nCount );
581 uno::Reference< util::XMacroExpander > xExpander = util::theMacroExpander::get(mxContext);
582 const OUString aPrefix(
583 "vnd.sun.star.expand:" );
585 for ( sal_uInt16 i=0; i<nCount; i++ )
587 aURL.SetSmartProtocol( INET_PROT_FILE );
588 aURL.SetURL( aDirs.GetToken( i, C_DELIM ) );
589 maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE );
591 sal_Int32 nIndex = maTemplateDirs[i].indexOf( aPrefix );
592 if ( nIndex != -1 && xExpander.is() )
594 maTemplateDirs[i] = maTemplateDirs[i].replaceAt(nIndex,
595 aPrefix.getLength(),
596 OUString());
597 maTemplateDirs[i] = xExpander->expandMacros( maTemplateDirs[i] );
601 aValue <<= maTemplateDirs;
603 // Store the template dir list
604 setProperty( maRootContent, aPropName, aValue );
607 //-----------------------------------------------------------------------------
608 sal_Bool SfxDocTplService_Impl::needsUpdate()
610 OUString aPropName( PROPERTY_NEEDSUPDATE );
611 sal_Bool bNeedsUpdate = sal_True;
612 Any aValue;
614 // Get the template dir list
615 sal_Bool bHasProperty = getProperty( maRootContent, aPropName, aValue );
617 if ( bHasProperty )
618 aValue >>= bNeedsUpdate;
620 // the old template component also checks this state, but it is initialized from this component
621 // so if this componend was already updated the old component does not need such an update
622 ::svt::TemplateFolderCache aTempCache;
623 if ( !bNeedsUpdate )
624 bNeedsUpdate = aTempCache.needsUpdate();
626 if ( bNeedsUpdate )
627 aTempCache.storeState();
629 return bNeedsUpdate;
632 // -----------------------------------------------------------------------
633 sal_Bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle )
635 if (m_xDocProps.is())
639 m_xDocProps->loadFromMedium(rURL, Sequence<PropertyValue>());
640 m_xDocProps->setTitle(aTitle);
642 uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
643 rURL, embed::ElementModes::READWRITE);
645 uno::Sequence<beans::PropertyValue> medium(2);
646 medium[0].Name = OUString("DocumentBaseURL");
647 medium[0].Value <<= rURL;
648 medium[1].Name = OUString("URL");
649 medium[1].Value <<= rURL;
651 m_xDocProps->storeToStorage(xStorage, medium);
652 return true;
654 catch ( Exception& )
658 return false;
661 // -----------------------------------------------------------------------
662 sal_Bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle )
664 bDocHasTitle = sal_False;
666 if (m_xDocProps.is())
670 m_xDocProps->loadFromMedium(rURL, Sequence<PropertyValue>());
671 aTitle = m_xDocProps->getTitle();
673 catch ( Exception& )
678 if ( aType.isEmpty() && mxType.is() )
680 OUString aDocType = mxType->queryTypeByURL( rURL );
681 if ( !aDocType.isEmpty() )
684 uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW );
685 SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) );
686 aType = aTypeProps.getUnpackedValueOrDefault(
687 OUString("MediaType"),
688 OUString() );
690 catch( uno::Exception& )
694 if ( aTitle.isEmpty() )
696 INetURLObject aURL( rURL );
697 aURL.CutExtension();
698 aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
699 INetURLObject::DECODE_WITH_CHARSET );
701 else
702 bDocHasTitle = sal_True;
704 return sal_True;
707 // -----------------------------------------------------------------------
708 sal_Bool SfxDocTplService_Impl::addEntry( Content& rParentFolder,
709 const OUString& rTitle,
710 const OUString& rTargetURL,
711 const OUString& rType )
713 sal_Bool bAddedEntry = sal_False;
715 INetURLObject aLinkObj( rParentFolder.getURL() );
716 aLinkObj.insertName( rTitle, false,
717 INetURLObject::LAST_SEGMENT, true,
718 INetURLObject::ENCODE_ALL );
719 OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE );
721 Content aLink;
723 if ( ! Content::create( aLinkURL, maCmdEnv, comphelper::getProcessComponentContext(), aLink ) )
725 Sequence< OUString > aNames(3);
726 aNames[0] = OUString( TITLE );
727 aNames[1] = OUString( IS_FOLDER );
728 aNames[2] = OUString( TARGET_URL );
730 Sequence< Any > aValues(3);
731 aValues[0] = makeAny( rTitle );
732 aValues[1] = makeAny( sal_Bool( sal_False ) );
733 aValues[2] = makeAny( rTargetURL );
735 OUString aType( TYPE_LINK );
736 OUString aAdditionalProp( PROPERTY_TYPE );
740 rParentFolder.insertNewContent( aType, aNames, aValues, aLink );
741 setProperty( aLink, aAdditionalProp, makeAny( rType ) );
742 bAddedEntry = sal_True;
744 catch( Exception& )
747 return bAddedEntry;
750 // -----------------------------------------------------------------------
751 sal_Bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL,
752 sal_Bool bCreateParent,
753 sal_Bool bFsysFolder,
754 Content &rNewFolder )
756 Content aParent;
757 sal_Bool bCreatedFolder = sal_False;
758 INetURLObject aParentURL( rNewFolderURL );
759 OUString aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true,
760 INetURLObject::DECODE_WITH_CHARSET );
762 // compute the parent folder url from the new folder url
763 // and remove the final slash, because Content::create doesn't
764 // like it
765 aParentURL.removeSegment();
766 if ( aParentURL.getSegmentCount() >= 1 )
767 aParentURL.removeFinalSlash();
769 // if the parent exists, we can continue with the creation of the
770 // new folder, we have to create the parent otherwise ( as long as
771 // bCreateParent is set to true )
772 if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, comphelper::getProcessComponentContext(), aParent ) )
776 Sequence< OUString > aNames(2);
777 aNames[0] = OUString( TITLE );
778 aNames[1] = OUString( IS_FOLDER );
780 Sequence< Any > aValues(2);
781 aValues[0] = makeAny( aFolderName );
782 aValues[1] = makeAny( sal_Bool( sal_True ) );
784 OUString aType;
786 if ( bFsysFolder )
787 aType = OUString( TYPE_FSYS_FOLDER );
788 else
789 aType = OUString( TYPE_FOLDER );
791 aParent.insertNewContent( aType, aNames, aValues, rNewFolder );
792 bCreatedFolder = sal_True;
794 catch( RuntimeException& )
796 SAL_WARN( "sfx2.doc", "createFolder(): got runtime exception" );
798 catch( Exception& )
800 SAL_WARN( "sfx2.doc", "createFolder(): Could not create new folder" );
803 else if ( bCreateParent )
805 // if the parent doesn't exists and bCreateParent is set to true,
806 // we try to create the parent and if this was successful, we
807 // try to create the new folder again ( but this time, we set
808 // bCreateParent to false to avoid endless recusions )
809 if ( ( aParentURL.getSegmentCount() >= 1 ) &&
810 createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) )
812 bCreatedFolder = createFolder( rNewFolderURL, sal_False, bFsysFolder, rNewFolder );
816 return bCreatedFolder;
819 // -----------------------------------------------------------------------
820 sal_Bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const OUString& aPath,
821 const OUString& aPrefix,
822 OUString& aNewFolderName,
823 OUString& aNewFolderURL,
824 Content& aNewFolder )
826 sal_Bool bCreated = sal_False;
827 INetURLObject aDirPath( aPath );
829 Content aParent;
830 uno::Reference< XCommandEnvironment > aQuietEnv;
831 if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, comphelper::getProcessComponentContext(), aParent ) )
833 for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
835 OUString aTryName = aPrefix;
836 if ( nInd )
837 aTryName += OUString::valueOf( nInd );
841 Sequence< OUString > aNames(2);
842 aNames[0] = OUString( TITLE );
843 aNames[1] = OUString( IS_FOLDER );
845 Sequence< Any > aValues(2);
846 aValues[0] = makeAny( aTryName );
847 aValues[1] = makeAny( sal_Bool( sal_True ) );
849 OUString aType( TYPE_FSYS_FOLDER );
851 bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder );
853 catch( ucb::NameClashException& )
855 // if there is already an element, retry
857 catch( Exception& )
859 INetURLObject aObjPath( aDirPath );
860 aObjPath.insertName( aTryName, false,
861 INetURLObject::LAST_SEGMENT, true,
862 INetURLObject::ENCODE_ALL );
863 // if there is already an element, retry
864 // if there was another error, do not try any more
865 if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
866 break;
869 if ( bCreated )
871 aNewFolderName = aTryName;
872 aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier();
873 break;
878 return bCreated;
881 // -----------------------------------------------------------------------
882 OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const OUString& aPath,
883 const OUString& aPrefix,
884 const OUString& aExt )
886 OUString aNewFileURL;
887 INetURLObject aDirPath( aPath );
889 Content aParent;
891 uno::Reference< XCommandEnvironment > aQuietEnv;
892 if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, comphelper::getProcessComponentContext(), aParent ) )
894 for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
896 Content aNewFile;
897 sal_Bool bCreated = sal_False;
898 OUString aTryName = aPrefix;
899 if ( nInd )
900 aTryName += OUString::valueOf( nInd );
901 if ( aExt.toChar() != '.' )
902 aTryName += OUString( "." );
903 aTryName += aExt;
907 Sequence< OUString > aNames(2);
908 aNames[0] = OUString( TITLE );
909 aNames[1] = OUString( IS_DOCUMENT );
911 Sequence< Any > aValues(2);
912 aValues[0] = makeAny( aTryName );
913 aValues[1] = makeAny( sal_Bool( sal_True ) );
915 OUString aType( TYPE_FSYS_FILE );
917 bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile );
919 catch( ucb::NameClashException& )
921 // if there is already an element, retry
923 catch( Exception& )
925 INetURLObject aObjPath( aPath );
926 aObjPath.insertName( aTryName, false,
927 INetURLObject::LAST_SEGMENT, true,
928 INetURLObject::ENCODE_ALL );
929 // if there is already an element, retry
930 // if there was another error, do not try any more
931 if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
932 break;
935 if ( bCreated )
937 aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier();
938 break;
943 return aNewFileURL;
946 // -----------------------------------------------------------------------
947 sal_Bool SfxDocTplService_Impl::removeContent( Content& rContent )
949 sal_Bool bRemoved = sal_False;
952 OUString aCmd( COMMAND_DELETE );
953 Any aArg = makeAny( sal_Bool( sal_True ) );
955 rContent.executeCommand( aCmd, aArg );
956 bRemoved = sal_True;
958 catch ( RuntimeException& ) {}
959 catch ( Exception& ) {}
961 return bRemoved;
964 // -----------------------------------------------------------------------
965 sal_Bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL )
967 Content aContent;
969 if ( Content::create( rContentURL, maCmdEnv, comphelper::getProcessComponentContext(), aContent ) )
970 return removeContent( aContent );
971 else
972 return sal_False;
975 // -----------------------------------------------------------------------
976 sal_Bool SfxDocTplService_Impl::setProperty( Content& rContent,
977 const OUString& rPropName,
978 const Any& rPropValue )
980 sal_Bool bPropertySet = sal_False;
982 // Store the property
985 Any aPropValue( rPropValue );
986 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
988 // check, whether or not the property exists, create it, when not
989 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
991 uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY );
992 if ( xProperties.is() )
996 xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue );
998 catch( PropertyExistException& ) {}
999 catch( IllegalTypeException& ) {
1000 SAL_WARN( "sfx2.doc", "IllegalTypeException" );
1002 catch( IllegalArgumentException& ) {
1003 SAL_WARN( "sfx2.doc", "IllegalArgumentException" );
1008 // To ensure a reloctable office installation, the path to the
1009 // office installtion directory must never be stored directly.
1010 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1012 OUString aValue;
1013 if ( rPropValue >>= aValue )
1015 maRelocator.makeRelocatableURL( aValue );
1016 aPropValue = makeAny( aValue );
1018 else
1020 Sequence< OUString > aValues;
1021 if ( rPropValue >>= aValues )
1023 for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1025 maRelocator.makeRelocatableURL( aValues[ n ] );
1027 aPropValue = makeAny( aValues );
1029 else
1031 OSL_FAIL( "Unsupported property value type" );
1036 // now set the property
1038 rContent.setPropertyValue( rPropName, aPropValue );
1039 bPropertySet = sal_True;
1041 catch ( RuntimeException& ) {}
1042 catch ( Exception& ) {}
1044 return bPropertySet;
1047 // -----------------------------------------------------------------------
1048 sal_Bool SfxDocTplService_Impl::getProperty( Content& rContent,
1049 const OUString& rPropName,
1050 Any& rPropValue )
1052 sal_Bool bGotProperty = sal_False;
1054 // Get the property
1057 uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1059 // check, whether or not the property exists
1060 if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1062 return sal_False;
1065 // now get the property
1067 rPropValue = rContent.getPropertyValue( rPropName );
1069 // To ensure a reloctable office installation, the path to the
1070 // office installtion directory must never be stored directly.
1071 if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1073 OUString aValue;
1074 if ( rPropValue >>= aValue )
1076 maRelocator.makeAbsoluteURL( aValue );
1077 rPropValue = makeAny( aValue );
1079 else
1081 Sequence< OUString > aValues;
1082 if ( rPropValue >>= aValues )
1084 for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1086 maRelocator.makeAbsoluteURL( aValues[ n ] );
1088 rPropValue = makeAny( aValues );
1090 else
1092 OSL_FAIL( "Unsupported property value type" );
1097 bGotProperty = sal_True;
1099 catch ( RuntimeException& ) {}
1100 catch ( Exception& ) {}
1102 return bGotProperty;
1105 // -----------------------------------------------------------------------
1106 // static
1107 bool SfxURLRelocator_Impl::propertyCanContainOfficeDir(
1108 const OUString & rPropName )
1110 // Note: TargetURL is handled by UCB itself (because it is a property
1111 // with a predefined semantic). Additional Core properties introduced
1112 // be a client app must be handled by the client app itself, because
1113 // the UCB does not know the semantics of those properties.
1114 return ( rPropName == TARGET_DIR_URL || rPropName == PROPERTY_DIRLIST );
1117 //-----------------------------------------------------------------------------
1118 // public SfxDocTplService_Impl
1119 //-----------------------------------------------------------------------------
1121 SfxDocTplService_Impl::SfxDocTplService_Impl( const uno::Reference< XComponentContext > & xContext )
1122 : maRelocator( xContext )
1124 mxContext = xContext;
1125 mpUpdater = NULL;
1126 mbIsInitialized = sal_False;
1127 mbLocaleSet = sal_False;
1130 //-----------------------------------------------------------------------------
1131 SfxDocTplService_Impl::~SfxDocTplService_Impl()
1133 ::osl::MutexGuard aGuard( maMutex );
1135 if ( mpUpdater )
1137 mpUpdater->terminate();
1138 mpUpdater->join();
1139 delete mpUpdater;
1142 for ( size_t i = 0, n = maNames.size(); i < n; ++i )
1143 delete maNames[ i ];
1144 maNames.clear();
1147 //-----------------------------------------------------------------------------
1148 Locale SfxDocTplService_Impl::getLocale()
1150 ::osl::MutexGuard aGuard( maMutex );
1152 if ( !mbLocaleSet )
1153 getDefaultLocale();
1155 return maLocale;
1158 //-----------------------------------------------------------------------------
1159 void SfxDocTplService_Impl::setLocale( const Locale &rLocale )
1161 ::osl::MutexGuard aGuard( maMutex );
1163 if ( mbLocaleSet &&
1164 ( maLocale.Language != rLocale.Language ) &&
1165 ( maLocale.Country != rLocale.Country ) )
1166 mbIsInitialized = sal_False;
1168 maLocale = rLocale;
1169 mbLocaleSet = sal_True;
1172 //-----------------------------------------------------------------------------
1173 void SfxDocTplService_Impl::update( sal_Bool bUpdateNow )
1175 ::osl::MutexGuard aGuard( maMutex );
1177 if ( bUpdateNow )
1178 doUpdate();
1179 else
1181 mpUpdater = new Updater_Impl( this );
1182 mpUpdater->create();
1186 //-----------------------------------------------------------------------------
1187 void SfxDocTplService_Impl::doUpdate()
1189 ::osl::MutexGuard aGuard( maMutex );
1191 OUString aPropName( PROPERTY_NEEDSUPDATE );
1192 Any aValue;
1194 aValue <<= sal_True;
1195 setProperty( maRootContent, aPropName, aValue );
1197 GroupList_Impl aGroupList;
1199 // get the entries from the hierarchy
1200 createFromContent( aGroupList, maRootContent, sal_True );
1202 // get the entries from the template directories
1203 sal_Int32 nCountDir = maTemplateDirs.getLength();
1204 OUString* pDirs = maTemplateDirs.getArray();
1205 Content aDirContent;
1207 // the last directory in the list must be writable
1208 sal_Bool bWriteableDirectory = sal_True;
1210 // the target folder might not exist, for this reason no interaction handler should be used
1211 uno::Reference< XCommandEnvironment > aQuietEnv;
1213 while ( nCountDir )
1215 nCountDir--;
1216 if ( Content::create( pDirs[ nCountDir ], aQuietEnv, comphelper::getProcessComponentContext(), aDirContent ) )
1218 createFromContent( aGroupList, aDirContent, sal_False, bWriteableDirectory );
1221 bWriteableDirectory = sal_False;
1224 // now check the list
1225 for( size_t j = 0, n = aGroupList.size(); j < n; ++j )
1227 GroupData_Impl *pGroup = aGroupList[ j ];
1228 if ( pGroup->getInUse() )
1230 if ( pGroup->getInHierarchy() )
1232 Content aGroup;
1233 if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1234 setProperty( aGroup,
1235 OUString( TARGET_DIR_URL ),
1236 makeAny( pGroup->getTargetURL() ) );
1238 size_t nCount = pGroup->count();
1239 for ( size_t i=0; i<nCount; i++ )
1241 DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
1242 if ( ! pData->getInUse() )
1244 if ( pData->getInHierarchy() )
1245 removeFromHierarchy( pData ); // delete entry in hierarchy
1246 else
1247 addToHierarchy( pGroup, pData ); // add entry to hierarchy
1249 else if ( pData->getUpdateType() ||
1250 pData->getUpdateLink() )
1252 updateData( pData );
1256 else
1258 addGroupToHierarchy( pGroup ); // add group to hierarchy
1261 else
1262 removeFromHierarchy( pGroup ); // delete group from hierarchy
1264 delete pGroup;
1266 aGroupList.clear();
1268 aValue <<= sal_False;
1269 setProperty( maRootContent, aPropName, aValue );
1272 //-----------------------------------------------------------------------------
1273 uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const OUString& aUserPath )
1275 INetURLObject aLocObj( aUserPath );
1276 aLocObj.insertName( OUString( "groupuinames.xml" ), false,
1277 INetURLObject::LAST_SEGMENT, true,
1278 INetURLObject::ENCODE_ALL );
1279 Content aLocContent;
1281 // TODO/LATER: Use hashmap in future
1282 uno::Sequence< beans::StringPair > aUINames;
1283 if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext(), aLocContent ) )
1287 uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream();
1288 if ( xLocStream.is() )
1289 aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxContext );
1291 catch( uno::Exception& )
1295 return aUINames;
1298 //-----------------------------------------------------------------------------
1299 sal_Bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const OUString& aUserPath,
1300 const OUString& aGroupName,
1301 const OUString& aNewFolderName )
1303 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1304 sal_Int32 nLen = aUINames.getLength();
1306 // it is possible that the name is used already, but it should be checked before
1307 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1308 if ( aUINames[nInd].First.equals( aNewFolderName ) )
1309 return sal_False;
1311 aUINames.realloc( ++nLen );
1312 aUINames[nLen-1].First = aNewFolderName;
1313 aUINames[nLen-1].Second = aGroupName;
1315 return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1318 //-----------------------------------------------------------------------------
1319 sal_Bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const OUString& aUserPath,
1320 const OUString& aDefaultFsysGroupName,
1321 const OUString& aOldGroupName,
1322 const OUString& aNewGroupName )
1324 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1325 sal_Int32 nLen = aUINames.getLength();
1327 sal_Bool bChanged = sal_False;
1328 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1329 if ( aUINames[nInd].Second.equals( aOldGroupName ) )
1331 aUINames[nInd].Second = aNewGroupName;
1332 bChanged = sal_True;
1335 if ( !bChanged )
1337 aUINames.realloc( ++nLen );
1338 aUINames[nLen-1].First = aDefaultFsysGroupName;
1339 aUINames[nLen-1].Second = aNewGroupName;
1341 return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1344 //-----------------------------------------------------------------------------
1345 sal_Bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const OUString& aUserPath,
1346 const OUString& aGroupName )
1348 uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1349 sal_Int32 nLen = aUINames.getLength();
1350 uno::Sequence< beans::StringPair > aNewUINames( nLen );
1351 sal_Int32 nNewLen = 0;
1353 sal_Bool bChanged = sal_False;
1354 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1355 if ( aUINames[nInd].Second.equals( aGroupName ) )
1356 bChanged = sal_True;
1357 else
1359 nNewLen++;
1360 aNewUINames[nNewLen-1].First = aUINames[nInd].First;
1361 aNewUINames[nNewLen-1].Second = aUINames[nInd].Second;
1364 aNewUINames.realloc( nNewLen );
1366 return bChanged ? WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames ) : sal_True;
1370 //-----------------------------------------------------------------------------
1371 sal_Bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const OUString& aUserPath,
1372 const uno::Sequence< beans::StringPair >& aUINames )
1374 sal_Bool bResult = sal_False;
1375 try {
1376 uno::Reference< beans::XPropertySet > xTempFile(
1377 io::TempFile::create(mxContext),
1378 uno::UNO_QUERY_THROW );
1380 OUString aTempURL;
1381 uno::Any aUrl = xTempFile->getPropertyValue( OUString("Uri") );
1382 aUrl >>= aTempURL;
1384 uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW );
1385 uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream();
1386 if ( !xOutStream.is() )
1387 throw uno::RuntimeException();
1389 DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxContext);
1390 try {
1391 // the SAX writer might close the stream
1392 xOutStream->closeOutput();
1393 } catch( uno::Exception& )
1396 Content aTargetContent( aUserPath, maCmdEnv, comphelper::getProcessComponentContext() );
1397 Content aSourceContent( aTempURL, maCmdEnv, comphelper::getProcessComponentContext() );
1398 aTargetContent.transferContent( aSourceContent,
1399 InsertOperation_COPY,
1400 OUString( "groupuinames.xml" ),
1401 ucb::NameClash::OVERWRITE,
1402 OUString( "text/xml" ) );
1403 bResult = sal_True;
1405 catch ( uno::Exception& )
1409 return bResult;
1412 //-----------------------------------------------------------------------------
1413 OUString SfxDocTplService_Impl::CreateNewGroupFsys( const OUString& rGroupName, Content& aGroup )
1415 OUString aResultURL;
1417 if ( maTemplateDirs.getLength() )
1419 OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1421 // create a new folder with the given name
1422 Content aNewFolder;
1423 OUString aNewFolderName;
1425 // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1426 if ( !CreateNewUniqueFolderWithPrefix( aTargetPath,
1427 rGroupName,
1428 aNewFolderName,
1429 aResultURL,
1430 aNewFolder )
1431 && !CreateNewUniqueFolderWithPrefix( aTargetPath,
1432 OUString( "UserGroup" ),
1433 aNewFolderName,
1434 aResultURL,
1435 aNewFolder ) )
1437 return OUString();
1439 if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) )
1441 // we could not create the groupuinames for the folder, so we delete the group in the
1442 // the folder and return
1443 removeContent( aNewFolder );
1444 return OUString();
1447 // Now set the target url for this group and we are done
1448 OUString aPropName( TARGET_DIR_URL );
1449 Any aValue = makeAny( aResultURL );
1451 if ( ! setProperty( aGroup, aPropName, aValue ) )
1453 removeContent( aNewFolder );
1454 return OUString();
1458 return aResultURL;
1461 //-----------------------------------------------------------------------------
1462 sal_Bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName )
1464 ::osl::MutexGuard aGuard( maMutex );
1466 // Check, whether or not there is a group with this name
1467 Content aNewGroup;
1468 OUString aNewGroupURL;
1469 INetURLObject aNewGroupObj( maRootURL );
1471 aNewGroupObj.insertName( rGroupName, false,
1472 INetURLObject::LAST_SEGMENT, true,
1473 INetURLObject::ENCODE_ALL );
1475 aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1477 if ( Content::create( aNewGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aNewGroup ) ||
1478 ! createFolder( aNewGroupURL, sal_False, sal_False, aNewGroup ) )
1480 // if there already was a group with this name or the new group
1481 // could not be created, we return here
1482 return sal_False;
1485 // Get the user template path entry ( new group will always
1486 // be added in the user template path )
1487 sal_Int32 nIndex;
1488 OUString aUserPath;
1490 nIndex = maTemplateDirs.getLength();
1491 if ( nIndex )
1492 nIndex--;
1493 else
1494 return sal_False; // We don't know where to add the group
1496 aUserPath = maTemplateDirs[ nIndex ];
1498 // create a new folder with the given name
1499 Content aNewFolder;
1500 OUString aNewFolderName;
1501 OUString aNewFolderURL;
1503 // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1504 if ( !CreateNewUniqueFolderWithPrefix( aUserPath,
1505 rGroupName,
1506 aNewFolderName,
1507 aNewFolderURL,
1508 aNewFolder )
1509 && !CreateNewUniqueFolderWithPrefix( aUserPath,
1510 OUString( "UserGroup" ),
1511 aNewFolderName,
1512 aNewFolderURL,
1513 aNewFolder ) )
1515 // we could not create the folder, so we delete the group in the
1516 // hierarchy and return
1517 removeContent( aNewGroup );
1518 return sal_False;
1521 if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) )
1523 // we could not create the groupuinames for the folder, so we delete the group in the
1524 // hierarchy, the folder and return
1525 removeContent( aNewGroup );
1526 removeContent( aNewFolder );
1527 return sal_False;
1530 // Now set the target url for this group and we are done
1531 OUString aPropName( TARGET_DIR_URL );
1532 Any aValue = makeAny( aNewFolderURL );
1534 if ( ! setProperty( aNewGroup, aPropName, aValue ) )
1536 removeContent( aNewGroup );
1537 removeContent( aNewFolder );
1538 return sal_False;
1541 return sal_True;
1544 //-----------------------------------------------------------------------------
1545 sal_Bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName )
1547 // remove all the elements that have the prefix aTargetURL
1548 // if the group does not have other elements remove it
1550 ::osl::MutexGuard aGuard( maMutex );
1552 sal_Bool bResult = sal_False;
1554 // create the group url
1555 INetURLObject aGroupObj( maRootURL );
1556 aGroupObj.insertName( rGroupName, false,
1557 INetURLObject::LAST_SEGMENT, true,
1558 INetURLObject::ENCODE_ALL );
1560 // Get the target url
1561 Content aGroup;
1562 OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1564 if ( Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1566 OUString aPropName( TARGET_DIR_URL );
1567 Any aValue;
1569 OUString aGroupTargetURL;
1570 if ( getProperty( aGroup, aPropName, aValue ) )
1571 aValue >>= aGroupTargetURL;
1573 if ( aGroupTargetURL.isEmpty() )
1574 return sal_False; // nothing is allowed to be removed
1576 if ( !maTemplateDirs.getLength() )
1577 return sal_False;
1578 OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1580 // check that the fs location is in writeble folder and this is not a "My templates" folder
1581 INetURLObject aGroupParentFolder( aGroupTargetURL );
1582 if ( !aGroupParentFolder.removeSegment()
1583 || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1584 aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1585 return sal_False;
1587 // now get the content of the Group
1588 uno::Reference< XResultSet > xResultSet;
1589 Sequence< OUString > aProps( 1 );
1591 aProps[0] = OUString(TARGET_URL );
1595 sal_Bool bHasNonRemovable = sal_False;
1596 sal_Bool bHasShared = sal_False;
1598 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1599 xResultSet = aGroup.createCursor( aProps, eInclude );
1601 if ( xResultSet.is() )
1603 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1604 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1606 while ( xResultSet->next() )
1608 OUString aTemplTargetURL( xRow->getString( 1 ) );
1609 OUString aHierURL = xContentAccess->queryContentIdentifierString();
1611 if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1613 // this is a user template, and it can be removed
1614 if ( removeContent( aTemplTargetURL ) )
1615 removeContent( aHierURL );
1616 else
1617 bHasNonRemovable = sal_True;
1619 else
1620 bHasShared = sal_True;
1623 if ( !bHasNonRemovable && !bHasShared )
1625 if ( removeContent( aGroupTargetURL )
1626 || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1628 removeContent( aGroupURL );
1629 RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1630 bResult = sal_True; // the operation is successful only if the whole group is removed
1633 else if ( !bHasNonRemovable )
1635 if ( removeContent( aGroupTargetURL )
1636 || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1638 RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1639 setProperty( aGroup, aPropName, uno::makeAny( OUString() ) );
1644 catch ( Exception& ) {}
1647 return bResult;
1650 //-----------------------------------------------------------------------------
1651 sal_Bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName,
1652 const OUString& rNewName )
1654 ::osl::MutexGuard aGuard( maMutex );
1656 // create the group url
1657 Content aGroup;
1658 INetURLObject aGroupObj( maRootURL );
1659 aGroupObj.insertName( rNewName, false,
1660 INetURLObject::LAST_SEGMENT, true,
1661 INetURLObject::ENCODE_ALL );
1662 OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1664 // Check, if there is a group with the new name, return false
1665 // if there is one.
1666 if ( Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1667 return sal_False;
1669 aGroupObj.removeSegment();
1670 aGroupObj.insertName( rOldName, false,
1671 INetURLObject::LAST_SEGMENT, true,
1672 INetURLObject::ENCODE_ALL );
1673 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1675 // When there is no group with the old name, we can't rename it
1676 if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1677 return sal_False;
1679 OUString aGroupTargetURL;
1680 // there is no need to check whether target dir url is in target path, since if the target path is changed
1681 // the target dir url should be already generated new
1682 OUString aPropName( TARGET_DIR_URL );
1683 Any aValue;
1684 if ( getProperty( aGroup, aPropName, aValue ) )
1685 aValue >>= aGroupTargetURL;
1687 if ( aGroupTargetURL.isEmpty() )
1688 return sal_False;
1690 if ( !maTemplateDirs.getLength() )
1691 return sal_False;
1692 OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1694 // check that the fs location is in writeble folder and this is not a "My templates" folder
1695 INetURLObject aGroupParentFolder( aGroupTargetURL );
1696 if ( !aGroupParentFolder.removeSegment()
1697 || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath,
1698 aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) )
1699 return sal_False;
1701 // check that the group can be renamed ( all the contents must be in target location )
1702 sal_Bool bCanBeRenamed = sal_False;
1705 uno::Reference< XResultSet > xResultSet;
1706 Sequence< OUString > aProps( 1 );
1708 aProps[0] = OUString(TARGET_URL );
1709 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1710 xResultSet = aGroup.createCursor( aProps, eInclude );
1712 if ( xResultSet.is() )
1714 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1715 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1717 while ( xResultSet->next() )
1719 OUString aTemplTargetURL( xRow->getString( 1 ) );
1721 if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1722 throw uno::Exception();
1725 bCanBeRenamed = sal_True;
1728 catch ( Exception& ) {}
1730 if ( bCanBeRenamed )
1732 INetURLObject aGroupTargetObj( aGroupTargetURL );
1733 OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1735 if ( aGroupTargetObj.removeSegment()
1736 && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ),
1737 aFsysName,
1738 rOldName,
1739 rNewName ) )
1741 // rename the group in the hierarchy
1742 OUString aTitleProp( TITLE );
1743 Any aTitleValue;
1744 aTitleValue <<= rNewName;
1746 return setProperty( aGroup, aTitleProp, aTitleValue );
1750 return sal_False;
1753 //-----------------------------------------------------------------------------
1754 sal_Bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName,
1755 const OUString& rTemplateName,
1756 const uno::Reference< frame::XStorable >& rStorable )
1758 ::osl::MutexGuard aGuard( maMutex );
1760 // Check, whether or not there is a group with this name
1761 // Return false, if there is no group with the given name
1762 Content aGroup, aTemplate, aTargetGroup, aTemplateToRemove;
1763 OUString aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL;
1764 INetURLObject aGroupObj( maRootURL );
1765 sal_Bool bRemoveOldTemplateContent = sal_False;
1766 OUString sDocServiceName;
1768 aGroupObj.insertName( rGroupName, false,
1769 INetURLObject::LAST_SEGMENT, true,
1770 INetURLObject::ENCODE_ALL );
1771 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1773 if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1774 return sal_False;
1776 OUString aGroupTargetURL;
1777 OUString aPropName( TARGET_DIR_URL );
1778 Any aValue;
1779 if ( getProperty( aGroup, aPropName, aValue ) )
1780 aValue >>= aGroupTargetURL;
1783 // Check, if there's a template with the given name in this group
1784 // the target template should be overwritten if it is imported by user
1785 // in case the template is installed by office installation of by an add-in
1786 // it can not be replaced
1787 aGroupObj.insertName( rTemplateName, false,
1788 INetURLObject::LAST_SEGMENT, true,
1789 INetURLObject::ENCODE_ALL );
1790 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1792 if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplateToRemove ) )
1794 OUString aTargetTemplPropName( TARGET_URL );
1796 bRemoveOldTemplateContent = sal_True;
1797 if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) )
1798 aValue >>= aTemplateToRemoveTargetURL;
1800 if ( aGroupTargetURL.isEmpty() || !maTemplateDirs.getLength()
1801 || (!aTemplateToRemoveTargetURL.isEmpty() && !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTemplateToRemoveTargetURL )) )
1802 return sal_False; // it is not allowed to remove the template
1807 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
1808 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1810 // get document service name
1811 uno::Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) );
1812 sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) );
1813 if ( sDocServiceName.isEmpty() )
1814 throw uno::RuntimeException();
1816 // get the actual filter name
1817 OUString aFilterName;
1819 uno::Reference< lang::XMultiServiceFactory > xConfigProvider =
1820 configuration::theDefaultProvider::get( xContext );
1822 uno::Sequence< uno::Any > aArgs( 1 );
1823 beans::PropertyValue aPathProp;
1824 aPathProp.Name = OUString("nodepath");
1825 aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" );
1826 aArgs[0] <<= aPathProp;
1828 uno::Reference< container::XNameAccess > xSOFConfig(
1829 xConfigProvider->createInstanceWithArguments(
1830 OUString("com.sun.star.configuration.ConfigurationAccess"),
1831 aArgs ),
1832 uno::UNO_QUERY_THROW );
1834 uno::Reference< container::XNameAccess > xApplConfig;
1835 xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig;
1836 if ( !xApplConfig.is() )
1837 throw uno::RuntimeException();
1839 xApplConfig->getByName( OUString( "ooSetupFactoryActualTemplateFilter" ) ) >>= aFilterName;
1840 if ( aFilterName.isEmpty() )
1841 throw uno::RuntimeException();
1843 // find the related type name
1844 OUString aTypeName;
1845 uno::Reference< container::XNameAccess > xFilterFactory(
1846 xFactory->createInstance( OUString("com.sun.star.document.FilterFactory") ),
1847 uno::UNO_QUERY_THROW );
1849 uno::Sequence< beans::PropertyValue > aFilterData;
1850 xFilterFactory->getByName( aFilterName ) >>= aFilterData;
1851 for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
1852 if ( aFilterData[nInd].Name == "Type" )
1853 aFilterData[nInd].Value >>= aTypeName;
1855 if ( aTypeName.isEmpty() )
1856 throw uno::RuntimeException();
1858 // find the mediatype and extension
1859 uno::Reference< container::XNameAccess > xTypeDetection;
1861 xTypeDetection =
1862 mxType.is() ?
1863 uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) :
1864 uno::Reference< container::XNameAccess >(
1865 xFactory->createInstance( OUString("com.sun.star.document.TypeDetection") ),
1866 uno::UNO_QUERY_THROW );
1868 SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) );
1869 uno::Sequence< OUString > aAllExt =
1870 aTypeProps.getUnpackedValueOrDefault( OUString("Extensions"), Sequence< OUString >() );
1871 if ( !aAllExt.getLength() )
1872 throw uno::RuntimeException();
1874 OUString aMediaType = aTypeProps.getUnpackedValueOrDefault( OUString("MediaType"), OUString() );
1875 OUString aExt = aAllExt[0];
1877 if ( aMediaType.isEmpty() || aExt.isEmpty() )
1878 throw uno::RuntimeException();
1880 // construct destination url
1881 if ( aGroupTargetURL.isEmpty() )
1883 aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1885 if ( aGroupTargetURL.isEmpty() )
1886 throw uno::RuntimeException();
1889 OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt );
1890 if ( aNewTemplateTargetURL.isEmpty() )
1892 aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, OUString( "UserTemplate" ), aExt );
1894 if ( aNewTemplateTargetURL.isEmpty() )
1895 throw uno::RuntimeException();
1898 // store template
1899 uno::Sequence< PropertyValue > aStoreArgs( 2 );
1900 aStoreArgs[0].Name = OUString("FilterName");
1901 aStoreArgs[0].Value <<= aFilterName;
1902 aStoreArgs[1].Name = OUString("DocumentTitle");
1903 aStoreArgs[1].Value <<= rTemplateName;
1905 if( !::utl::UCBContentHelper::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() ))
1906 rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs );
1907 else
1908 rStorable->store();
1910 // the storing was successful, now the old template with the same name can be removed if it existed
1911 if ( !aTemplateToRemoveTargetURL.isEmpty() )
1913 removeContent( aTemplateToRemoveTargetURL );
1916 * pb: #i79496#
1917 * if the old template was the standard template
1918 * it is necessary to change the standard template with the new file name
1920 String sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName );
1921 if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) )
1923 SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL );
1927 if ( bRemoveOldTemplateContent )
1928 removeContent( aTemplateToRemove );
1930 // add the template to hierarchy
1931 return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType );
1933 catch( Exception& )
1935 // the template was not stored
1936 return sal_False;
1940 //-----------------------------------------------------------------------------
1941 sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName,
1942 const OUString& rTemplateName,
1943 const OUString& rSourceURL )
1945 ::osl::MutexGuard aGuard( maMutex );
1947 // Check, whether or not there is a group with this name
1948 // Return false, if there is no group with the given name
1949 Content aGroup, aTemplate, aTargetGroup;
1950 OUString aGroupURL, aTemplateURL;
1951 INetURLObject aGroupObj( maRootURL );
1953 aGroupObj.insertName( rGroupName, false,
1954 INetURLObject::LAST_SEGMENT, true,
1955 INetURLObject::ENCODE_ALL );
1956 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1958 if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1959 return sal_False;
1961 // Check, if there's a template with the given name in this group
1962 // Return false, if there already is a template
1963 aGroupObj.insertName( rTemplateName, false,
1964 INetURLObject::LAST_SEGMENT, true,
1965 INetURLObject::ENCODE_ALL );
1966 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1968 if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
1969 return sal_False;
1971 // get the target url of the group
1972 OUString aTargetURL;
1973 OUString aPropName( TARGET_DIR_URL );
1974 Any aValue;
1976 if ( getProperty( aGroup, aPropName, aValue ) )
1977 aValue >>= aTargetURL;
1979 if ( aTargetURL.isEmpty() )
1981 aTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1983 if ( aTargetURL.isEmpty() )
1984 return sal_False;
1987 // Get the content type
1988 OUString aTitle, aType, aTargetURL2;
1990 sal_Bool bDocHasTitle = sal_False;
1991 if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) )
1992 return sal_False;
1994 INetURLObject aSourceObj( rSourceURL );
1995 if ( rTemplateName.equals( aTitle ) )
1997 // addTemplate will sometimes be called just to add an entry in the
1998 // hierarchy; the target URL and the source URL will be the same in
1999 // this scenario
2000 // TODO/LATER: get rid of this old hack
2002 INetURLObject aTargetObj( aTargetURL );
2004 aTargetObj.insertName( rTemplateName, false,
2005 INetURLObject::LAST_SEGMENT, true,
2006 INetURLObject::ENCODE_ALL );
2007 aTargetObj.setExtension( aSourceObj.getExtension() );
2009 aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE );
2011 if ( aTargetURL2 == rSourceURL )
2012 return addEntry( aGroup, rTemplateName, aTargetURL2, aType );
2015 // copy the template into the new group (targeturl)
2017 INetURLObject aTmpURL( aSourceObj );
2018 aTmpURL.CutExtension();
2019 OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2021 OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() );
2022 INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL );
2023 OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2024 if ( aNewTemplateTargetURL.isEmpty() || aNewTemplateTargetName.isEmpty() )
2025 return sal_False;
2027 // get access to source file
2028 Content aSourceContent;
2029 uno::Reference < ucb::XCommandEnvironment > xEnv;
2030 INetURLObject aSourceURL( rSourceURL );
2031 if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent ) )
2032 return sal_False;
2034 if( ! Content::create( aTargetURL, xEnv, comphelper::getProcessComponentContext(), aTargetGroup ) )
2035 return sal_False;
2037 // transfer source file
2040 if( ! aTargetGroup.transferContent( aSourceContent,
2041 InsertOperation_COPY,
2042 aNewTemplateTargetName,
2043 NameClash::OVERWRITE,
2044 aType ) )
2045 return sal_False;
2047 // allow to edit the added template
2048 Content aResultContent;
2049 if ( Content::create( aNewTemplateTargetURL, xEnv, comphelper::getProcessComponentContext(), aResultContent ) )
2051 OUString aPropertyName( "IsReadOnly" );
2052 uno::Any aProperty;
2053 sal_Bool bReadOnly = sal_False;
2054 if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly )
2055 setProperty( aResultContent, aPropertyName, uno::makeAny( (sal_Bool)sal_False ) );
2058 catch ( ContentCreationException& )
2059 { return sal_False; }
2060 catch ( Exception& )
2061 { return sal_False; }
2064 // either the document has title and it is the same as requested, or we have to set it
2065 sal_Bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) );
2066 if ( !bCorrectTitle )
2068 if ( !bDocHasTitle )
2070 INetURLObject aNewTmpObj( aNewTemplateTargetObj );
2071 aNewTmpObj.CutExtension();
2072 bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) );
2075 if ( !bCorrectTitle )
2076 bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName );
2079 if ( bCorrectTitle )
2081 // create a new entry in the hierarchy
2082 return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType );
2085 // TODO/LATER: The user could be notified here that the renaming has failed
2086 // create a new entry in the hierarchy
2087 addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType );
2088 return sal_False;
2091 //-----------------------------------------------------------------------------
2092 sal_Bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName,
2093 const OUString& rTemplateName )
2095 ::osl::MutexGuard aGuard( maMutex );
2097 // Check, whether or not there is a group with this name
2098 // Return false, if there is no group with the given name
2099 Content aGroup, aTemplate;
2100 OUString aGroupURL, aTemplateURL;
2101 INetURLObject aGroupObj( maRootURL );
2103 aGroupObj.insertName( rGroupName, false,
2104 INetURLObject::LAST_SEGMENT, true,
2105 INetURLObject::ENCODE_ALL );
2106 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2108 if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2109 return sal_False;
2111 // Check, if there's a template with the given name in this group
2112 // Return false, if there is no template
2113 aGroupObj.insertName( rTemplateName, false,
2114 INetURLObject::LAST_SEGMENT, true,
2115 INetURLObject::ENCODE_ALL );
2116 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2118 if ( !Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2119 return sal_False;
2121 // get the target URL from the template
2122 OUString aTargetURL;
2123 OUString aPropName( TARGET_URL );
2124 Any aValue;
2126 if ( getProperty( aTemplate, aPropName, aValue ) )
2127 aValue >>= aTargetURL;
2129 // delete the target template
2130 if ( !aTargetURL.isEmpty() )
2132 if ( !maTemplateDirs.getLength()
2133 || !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTargetURL ) )
2134 return sal_False;
2136 removeContent( aTargetURL );
2139 // delete the template entry
2140 return removeContent( aTemplate );
2143 //-----------------------------------------------------------------------------
2144 sal_Bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName,
2145 const OUString& rOldName,
2146 const OUString& rNewName )
2148 ::osl::MutexGuard aGuard( maMutex );
2150 // Check, whether or not there is a group with this name
2151 // Return false, if there is no group with the given name
2152 Content aGroup, aTemplate;
2153 OUString aGroupURL, aTemplateURL;
2154 INetURLObject aGroupObj( maRootURL );
2156 aGroupObj.insertName( rGroupName, false,
2157 INetURLObject::LAST_SEGMENT, true,
2158 INetURLObject::ENCODE_ALL );
2159 aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2161 if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2162 return sal_False;
2164 // Check, if there's a template with the new name in this group
2165 // Return false, if there is one
2166 aGroupObj.insertName( rNewName, false,
2167 INetURLObject::LAST_SEGMENT, true,
2168 INetURLObject::ENCODE_ALL );
2169 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2171 if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2172 return sal_False;
2174 // Check, if there's a template with the old name in this group
2175 // Return false, if there is no template
2176 aGroupObj.removeSegment();
2177 aGroupObj.insertName( rOldName, false,
2178 INetURLObject::LAST_SEGMENT, true,
2179 INetURLObject::ENCODE_ALL );
2180 aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2182 if ( !Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2183 return sal_False;
2185 OUString aTemplateTargetURL;
2186 OUString aTargetProp( TARGET_URL );
2187 Any aTargetValue;
2189 if ( getProperty( aTemplate, aTargetProp, aTargetValue ) )
2190 aTargetValue >>= aTemplateTargetURL;
2192 if ( !setTitleForURL( aTemplateTargetURL, rNewName ) )
2193 return sal_False;
2195 // rename the template entry in the cache
2196 OUString aTitleProp( TITLE );
2197 Any aTitleValue;
2198 aTitleValue <<= rNewName;
2200 return setProperty( aTemplate, aTitleProp, aTitleValue );
2203 //-----------------------------------------------------------------------------
2205 SFX_IMPL_XSERVICEINFO( SfxDocTplService, TEMPLATE_SERVICE_NAME, TEMPLATE_IMPLEMENTATION_NAME )
2206 SFX_IMPL_SINGLEFACTORY( SfxDocTplService )
2208 //-----------------------------------------------------------------------------
2209 SfxDocTplService::SfxDocTplService( const uno::Reference< XMultiServiceFactory >& xFactory )
2211 pImp = new SfxDocTplService_Impl( comphelper::getComponentContext(xFactory) );
2214 //-----------------------------------------------------------------------------
2216 SfxDocTplService::~SfxDocTplService()
2218 delete pImp;
2221 //-----------------------------------------------------------------------------
2222 //--- XLocalizable ---
2223 //-----------------------------------------------------------------------------
2225 Locale SAL_CALL SfxDocTplService::getLocale()
2226 throw( uno::RuntimeException )
2228 return pImp->getLocale();
2231 //-----------------------------------------------------------------------------
2233 void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale )
2234 throw( uno::RuntimeException )
2236 pImp->setLocale( rLocale );
2239 //-----------------------------------------------------------------------------
2240 //--- XDocumentTemplates ---
2241 //-----------------------------------------------------------------------------
2242 uno::Reference< ucb::XContent > SAL_CALL SfxDocTplService::getContent()
2243 throw( uno::RuntimeException )
2245 if ( pImp->init() )
2246 return pImp->getContent().get();
2247 else
2248 return NULL;
2251 //-----------------------------------------------------------------------------
2252 sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName,
2253 const OUString& TemplateName,
2254 const uno::Reference< frame::XStorable >& Storable )
2255 throw( uno::RuntimeException )
2257 if ( pImp->init() )
2258 return pImp->storeTemplate( GroupName, TemplateName, Storable );
2259 else
2260 return sal_False;
2263 //-----------------------------------------------------------------------------
2264 sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName,
2265 const OUString& rTemplateName,
2266 const OUString& rSourceURL )
2267 throw( uno::RuntimeException )
2269 if ( pImp->init() )
2270 return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL );
2271 else
2272 return sal_False;
2275 //-----------------------------------------------------------------------------
2276 sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName,
2277 const OUString& rTemplateName )
2278 throw( uno::RuntimeException )
2280 if ( pImp->init() )
2281 return pImp->removeTemplate( rGroupName, rTemplateName );
2282 else
2283 return sal_False;
2286 //-----------------------------------------------------------------------------
2287 sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName,
2288 const OUString& rOldName,
2289 const OUString& rNewName )
2290 throw( uno::RuntimeException )
2292 if ( rOldName == rNewName )
2293 return sal_True;
2295 if ( pImp->init() )
2296 return pImp->renameTemplate( rGroupName, rOldName, rNewName );
2297 else
2298 return sal_False;
2301 //-----------------------------------------------------------------------------
2302 sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName )
2303 throw( uno::RuntimeException )
2305 if ( pImp->init() )
2306 return pImp->addGroup( rGroupName );
2307 else
2308 return sal_False;
2311 //-----------------------------------------------------------------------------
2312 sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName )
2313 throw( uno::RuntimeException )
2315 if ( pImp->init() )
2316 return pImp->removeGroup( rGroupName );
2317 else
2318 return sal_False;
2321 //-----------------------------------------------------------------------------
2322 sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName,
2323 const OUString& rNewName )
2324 throw( uno::RuntimeException )
2326 if ( rOldName == rNewName )
2327 return sal_True;
2329 if ( pImp->init() )
2330 return pImp->renameGroup( rOldName, rNewName );
2331 else
2332 return sal_False;
2335 //-----------------------------------------------------------------------------
2336 void SAL_CALL SfxDocTplService::update()
2337 throw( uno::RuntimeException )
2339 if ( pImp->init() )
2340 pImp->update( sal_True );
2343 //------------------------------------------------------------------------
2345 Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2347 mpDocTemplates = pTemplates;
2350 //------------------------------------------------------------------------
2351 Updater_Impl::~Updater_Impl()
2355 //------------------------------------------------------------------------
2356 void SAL_CALL Updater_Impl::run()
2358 mpDocTemplates->doUpdate();
2361 //------------------------------------------------------------------------
2362 void SAL_CALL Updater_Impl::onTerminated()
2364 mpDocTemplates->finished();
2365 delete this;
2368 //-----------------------------------------------------------------------------
2369 WaitWindow_Impl::WaitWindow_Impl()
2370 : WorkWindow( NULL, WB_BORDER | WB_3DLOOK )
2372 Rectangle aRect = Rectangle( 0, 0, 300, 30000 );
2373 _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE;
2374 _aText = SfxResId( RID_CNT_STR_WAITING ).toString();
2375 _aRect = GetTextRect( aRect, _aText, _nTextStyle );
2376 aRect = _aRect;
2377 aRect.Right() += 2*X_OFFSET;
2378 aRect.Bottom() += 2*Y_OFFSET;
2379 _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) );
2380 SetOutputSizePixel( aRect.GetSize() );
2381 Show();
2382 Update();
2383 Flush();
2386 //-----------------------------------------------------------------------------
2387 WaitWindow_Impl::~WaitWindow_Impl()
2389 Hide();
2392 //-----------------------------------------------------------------------------
2393 void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ )
2395 DrawText( _aRect, _aText, _nTextStyle );
2398 //-----------------------------------------------------------------------------
2399 void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList,
2400 const OUString& rTitle,
2401 const OUString& rOwnURL )
2403 // now get the content of the Group
2404 Content aContent;
2405 uno::Reference< XResultSet > xResultSet;
2406 Sequence< OUString > aProps(3);
2408 aProps[0] = OUString(TITLE );
2409 aProps[1] = OUString(TARGET_URL );
2410 aProps[2] = OUString(PROPERTY_TYPE );
2414 aContent = Content( rOwnURL, maCmdEnv, comphelper::getProcessComponentContext() );
2415 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2416 xResultSet = aContent.createCursor( aProps, eInclude );
2418 catch ( ContentCreationException& )
2420 SAL_WARN( "sfx2.doc", "addHierGroup: ContentCreationException" );
2422 catch ( Exception& ) {}
2424 if ( xResultSet.is() )
2426 GroupData_Impl *pGroup = new GroupData_Impl( rTitle );
2427 pGroup->setHierarchy( sal_True );
2428 pGroup->setHierarchyURL( rOwnURL );
2429 rList.push_back( pGroup );
2431 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2432 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2436 while ( xResultSet->next() )
2438 sal_Bool bUpdateType = sal_False;
2439 DocTemplates_EntryData_Impl *pData;
2441 OUString aTitle( xRow->getString( 1 ) );
2442 OUString aTargetDir( xRow->getString( 2 ) );
2443 OUString aType( xRow->getString( 3 ) );
2444 OUString aHierURL = xContentAccess->queryContentIdentifierString();
2446 if ( aType.isEmpty() )
2448 OUString aTmpTitle;
2450 sal_Bool bDocHasTitle = sal_False;
2451 if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) )
2453 SAL_WARN( "sfx2.doc", "addHierGroup(): template of alien format" );
2454 continue;
2457 if ( !aType.isEmpty() )
2458 bUpdateType = sal_True;
2461 pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL );
2462 pData->setUpdateType( bUpdateType );
2465 catch ( Exception& ) {}
2469 //-----------------------------------------------------------------------------
2470 void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList,
2471 const OUString& rTitle,
2472 const OUString& rUITitle,
2473 const OUString& rOwnURL,
2474 sal_Bool bWriteableGroup )
2476 OUString aTitle;
2478 if ( rUITitle.isEmpty() )
2480 // reserved FS names that should not be used
2481 if ( rTitle.compareToAscii( "wizard" ) == 0 )
2482 return;
2483 else if ( rTitle.compareToAscii( "internal" ) == 0 )
2484 return;
2486 aTitle = getLongName( rTitle );
2488 else
2489 aTitle = rUITitle;
2491 if ( aTitle.isEmpty() )
2492 return;
2494 GroupData_Impl* pGroup = NULL;
2495 for ( size_t i = 0, n = rList.size(); i < n; ++i )
2497 if ( rList[ i ]->getTitle() == aTitle )
2499 pGroup = rList[ i ];
2500 break;
2504 if ( !pGroup )
2506 pGroup = new GroupData_Impl( aTitle );
2507 rList.push_back( pGroup );
2510 if ( bWriteableGroup )
2511 pGroup->setTargetURL( rOwnURL );
2513 pGroup->setInUse();
2515 // now get the content of the Group
2516 Content aContent;
2517 uno::Reference< XResultSet > xResultSet;
2518 Sequence< OUString > aProps(1);
2519 aProps[0] = OUString(TITLE );
2523 // this method is only used during checking of the available template-folders
2524 // that should happen quietly
2525 uno::Reference< XCommandEnvironment > aQuietEnv;
2526 aContent = Content( rOwnURL, aQuietEnv, comphelper::getProcessComponentContext() );
2527 ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2528 xResultSet = aContent.createCursor( aProps, eInclude );
2530 catch ( Exception& ) {}
2532 if ( xResultSet.is() )
2534 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2535 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2539 while ( xResultSet->next() )
2541 OUString aChildTitle( xRow->getString( 1 ) );
2542 OUString aTargetURL = xContentAccess->queryContentIdentifierString();
2543 OUString aType;
2544 OUString aHierURL;
2546 if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0 || aChildTitle == "groupuinames.xml" )
2547 continue;
2549 sal_Bool bDocHasTitle = sal_False;
2550 if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) )
2551 continue;
2553 pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL );
2556 catch ( Exception& ) {}
2560 // -----------------------------------------------------------------------
2561 void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList,
2562 Content &rContent,
2563 sal_Bool bHierarchy,
2564 sal_Bool bWriteableContent )
2566 OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier();
2568 // when scanning the file system, we have to add the 'standard' group, too
2569 if ( ! bHierarchy )
2571 OUString aUIStdTitle = getLongName( OUString( STANDARD_FOLDER ) );
2572 addFsysGroup( rList, OUString(), aUIStdTitle, aTargetURL, bWriteableContent );
2575 // search for predefined UI names
2576 INetURLObject aLayerObj( aTargetURL );
2578 // TODO/LATER: Use hashmap in future
2579 uno::Sequence< beans::StringPair > aUINames;
2580 if ( !bHierarchy )
2581 aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) );
2583 uno::Reference< XResultSet > xResultSet;
2584 Sequence< OUString > aProps(1);
2585 aProps[0] = OUString(TITLE );
2589 ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
2590 xResultSet = rContent.createCursor( aProps, eInclude );
2592 catch ( Exception& ) {}
2594 if ( xResultSet.is() )
2596 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2597 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2601 while ( xResultSet->next() )
2603 // TODO/LATER: clarify the encoding of the Title
2604 OUString aTitle( xRow->getString( 1 ) );
2605 OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() );
2607 if ( bHierarchy )
2608 addHierGroup( rList, aTitle, aTargetSubfolderURL );
2609 else
2611 OUString aUITitle;
2612 for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ )
2613 if ( aUINames[nInd].First.equals( aTitle ) )
2615 aUITitle = aUINames[nInd].Second;
2616 break;
2619 addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent );
2623 catch ( Exception& ) {}
2627 //-----------------------------------------------------------------------------
2628 void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData )
2630 Content aTemplate;
2632 if ( Content::create( pData->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2634 removeContent( aTemplate );
2638 //-----------------------------------------------------------------------------
2639 void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup,
2640 DocTemplates_EntryData_Impl *pData )
2642 Content aGroup, aTemplate;
2644 if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2645 return;
2647 // Check, if there's a template with the given name in this group
2648 // Return if there is already a template
2649 INetURLObject aGroupObj( pGroup->getHierarchyURL() );
2651 aGroupObj.insertName( pData->getTitle(), false,
2652 INetURLObject::LAST_SEGMENT, true,
2653 INetURLObject::ENCODE_ALL );
2655 OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2657 if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2658 return;
2660 addEntry( aGroup, pData->getTitle(),
2661 pData->getTargetURL(),
2662 pData->getType() );
2665 //-----------------------------------------------------------------------------
2666 void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData )
2668 Content aTemplate;
2670 if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2671 return;
2673 OUString aPropName;
2675 if ( pData->getUpdateType() )
2677 aPropName = OUString( PROPERTY_TYPE );
2678 setProperty( aTemplate, aPropName, makeAny( pData->getType() ) );
2681 if ( pData->getUpdateLink() )
2683 aPropName = OUString( TARGET_URL );
2684 setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) );
2688 //-----------------------------------------------------------------------------
2689 void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup )
2691 OUString aAdditionalProp( TARGET_DIR_URL );
2692 Content aGroup;
2694 INetURLObject aNewGroupObj( maRootURL );
2695 aNewGroupObj.insertName( pGroup->getTitle(), false,
2696 INetURLObject::LAST_SEGMENT, true,
2697 INetURLObject::ENCODE_ALL );
2699 OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2701 if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) )
2703 setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) );
2704 pGroup->setHierarchyURL( aNewGroupURL );
2706 sal_uIntPtr nCount = pGroup->count();
2707 for ( sal_uIntPtr i=0; i<nCount; i++ )
2709 DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
2710 addToHierarchy( pGroup, pData ); // add entry to hierarchy
2715 //-----------------------------------------------------------------------------
2716 void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup )
2718 Content aGroup;
2720 if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2722 removeContent( aGroup );
2726 // -----------------------------------------------------------------------
2727 GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2729 maTitle = rTitle;
2730 mbInUse = sal_False;
2731 mbInHierarchy = sal_False;
2734 // -----------------------------------------------------------------------
2735 GroupData_Impl::~GroupData_Impl()
2737 for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2738 delete maEntries[ i ];
2739 maEntries.clear();
2742 // -----------------------------------------------------------------------
2743 DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle,
2744 const OUString& rTargetURL,
2745 const OUString& rType,
2746 const OUString& rHierURL )
2748 DocTemplates_EntryData_Impl* pData = NULL;
2749 bool EntryFound = false;
2751 for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2753 pData = maEntries[ i ];
2754 if ( pData->getTitle() == rTitle )
2756 EntryFound = true;
2757 break;
2761 if ( !EntryFound )
2763 pData = new DocTemplates_EntryData_Impl( rTitle );
2764 pData->setTargetURL( rTargetURL );
2765 pData->setType( rType );
2766 if ( !rHierURL.isEmpty() )
2768 pData->setHierarchyURL( rHierURL );
2769 pData->setHierarchy( sal_True );
2771 maEntries.push_back( pData );
2773 else
2775 if ( !rHierURL.isEmpty() )
2777 pData->setHierarchyURL( rHierURL );
2778 pData->setHierarchy( sal_True );
2781 if ( pData->getInHierarchy() )
2782 pData->setInUse();
2784 if ( rTargetURL != pData->getTargetURL() )
2786 pData->setTargetURL( rTargetURL );
2787 pData->setUpdateLink( sal_True );
2791 return pData;
2794 // -----------------------------------------------------------------------
2795 DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle )
2797 maTitle = rTitle;
2798 mbInUse = sal_False;
2799 mbInHierarchy = sal_False;
2800 mbUpdateType = sal_False;
2801 mbUpdateLink = sal_False;
2804 // -----------------------------------------------------------------------
2805 SfxURLRelocator_Impl::SfxURLRelocator_Impl( const uno::Reference< XComponentContext > & xContext )
2806 : mxContext( xContext )
2810 // -----------------------------------------------------------------------
2811 SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2815 // -----------------------------------------------------------------------
2816 void SfxURLRelocator_Impl::initOfficeInstDirs()
2818 if ( !mxOfficeInstDirs.is() )
2820 osl::MutexGuard aGuard( maMutex );
2821 if ( !mxOfficeInstDirs.is() )
2823 OSL_ENSURE( mxContext.is(), "No service manager!" );
2825 mxOfficeInstDirs = theOfficeInstallationDirectories::get(mxContext);
2830 // -----------------------------------------------------------------------
2831 void SfxURLRelocator_Impl::implExpandURL( OUString& io_url )
2833 const INetURLObject aParser( io_url );
2834 if ( aParser.GetProtocol() != INET_PROT_VND_SUN_STAR_EXPAND )
2835 return;
2837 io_url = aParser.GetURLPath( INetURLObject::DECODE_WITH_CHARSET );
2840 if ( !mxMacroExpander.is() )
2842 mxMacroExpander.set( theMacroExpander::get(mxContext), UNO_QUERY_THROW );
2844 io_url = mxMacroExpander->expandMacros( io_url );
2846 catch( const Exception& )
2848 DBG_UNHANDLED_EXCEPTION();
2852 // -----------------------------------------------------------------------
2853 void SfxURLRelocator_Impl::makeRelocatableURL( OUString & rURL )
2855 if ( !rURL.isEmpty() )
2857 initOfficeInstDirs();
2858 implExpandURL( rURL );
2859 rURL = mxOfficeInstDirs->makeRelocatableURL( rURL );
2863 // -----------------------------------------------------------------------
2864 void SfxURLRelocator_Impl::makeAbsoluteURL( OUString & rURL )
2866 if ( !rURL.isEmpty() )
2868 initOfficeInstDirs();
2869 implExpandURL( rURL );
2870 rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL );
2875 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */