Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <osl/mutex.hxx>
21 : #include <tools/diagnose_ex.h>
22 : #include <tools/urlobj.hxx>
23 : #include <rtl/ustring.hxx>
24 : #include <rtl/ustrbuf.hxx>
25 : #include <tools/resary.hxx>
26 : #include <vcl/svapp.hxx>
27 : #include <vcl/wrkwin.hxx>
28 : #include <unotools/pathoptions.hxx>
29 : #include <comphelper/processfactory.hxx>
30 : #include <comphelper/sequenceashashmap.hxx>
31 : #include <comphelper/storagehelper.hxx>
32 : #include <comphelper/string.hxx>
33 : #include <cppuhelper/implbase3.hxx>
34 : #include <cppuhelper/supportsservice.hxx>
35 : #include <com/sun/star/beans/PropertyAttribute.hpp>
36 : #include <com/sun/star/beans/XPropertySet.hpp>
37 : #include <com/sun/star/beans/XPropertySetInfo.hpp>
38 : #include <com/sun/star/beans/XPropertyContainer.hpp>
39 : #include <com/sun/star/beans/StringPair.hpp>
40 : #include <com/sun/star/util/theMacroExpander.hpp>
41 : #include <com/sun/star/util/theOfficeInstallationDirectories.hpp>
42 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
43 : #include <com/sun/star/container/XContainerQuery.hpp>
44 : #include <com/sun/star/document/XTypeDetection.hpp>
45 : #include <com/sun/star/document/DocumentProperties.hpp>
46 : #include <com/sun/star/io/TempFile.hpp>
47 : #include <com/sun/star/sdbc/XResultSet.hpp>
48 : #include <com/sun/star/sdbc/XRow.hpp>
49 : #include <com/sun/star/ucb/NameClash.hpp>
50 : #include <com/sun/star/ucb/NameClashException.hpp>
51 : #include <com/sun/star/ucb/TransferInfo.hpp>
52 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
53 : #include <com/sun/star/ucb/XContentAccess.hpp>
54 : #include <com/sun/star/frame/ModuleManager.hpp>
55 : #include <com/sun/star/uno/Exception.hpp>
56 : #include <com/sun/star/task/InteractionHandler.hpp>
57 : #include <com/sun/star/ucb/XProgressHandler.hpp>
58 : #include <com/sun/star/container/XNameAccess.hpp>
59 : #include <com/sun/star/frame/XDocumentTemplates.hpp>
60 : #include <com/sun/star/frame/XStorable.hpp>
61 : #include <com/sun/star/lang/Locale.hpp>
62 : #include <com/sun/star/lang/XLocalizable.hpp>
63 : #include <com/sun/star/lang/XServiceInfo.hpp>
64 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
65 : #include <com/sun/star/ucb/XContent.hpp>
66 : #include <com/sun/star/beans/PropertyValue.hpp>
67 : #include <com/sun/star/uno/RuntimeException.hpp>
68 : #include <com/sun/star/uno/XComponentContext.hpp>
69 : #include <com/sun/star/util/thePathSettings.hpp>
70 :
71 : #include <rtl/ref.hxx>
72 : #include <svtools/templatefoldercache.hxx>
73 : #include <unotools/configmgr.hxx>
74 : #include <unotools/ucbhelper.hxx>
75 :
76 : #include <sfx2/sfxresid.hxx>
77 : #include "sfxurlrelocator.hxx"
78 : #include "doctemplateslocal.hxx"
79 : #include <sfx2/docfac.hxx>
80 : #include <sfx2/docfile.hxx>
81 : #include "doc.hrc"
82 :
83 : #include <vector>
84 :
85 : #define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection"
86 :
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"
98 :
99 : #define PROPERTY_DIRLIST "DirectoryList"
100 : #define PROPERTY_NEEDSUPDATE "NeedsUpdate"
101 : #define PROPERTY_TYPE "TypeDescription"
102 :
103 : #define TARGET_DIR_URL "TargetDirURL"
104 : #define COMMAND_DELETE "delete"
105 :
106 : #define STANDARD_FOLDER "standard"
107 :
108 : #define C_DELIM ';'
109 :
110 : using namespace ::com::sun::star;
111 : using namespace ::com::sun::star::beans;
112 : using namespace ::com::sun::star::document;
113 : using namespace ::com::sun::star::io;
114 : using namespace ::com::sun::star::lang;
115 : using namespace ::com::sun::star::sdbc;
116 : using namespace ::com::sun::star::ucb;
117 : using namespace ::com::sun::star::uno;
118 : using namespace ::com::sun::star::container;
119 : using namespace ::com::sun::star::util;
120 :
121 : using namespace ::ucbhelper;
122 : using namespace ::comphelper;
123 :
124 : using ::std::vector;
125 :
126 : namespace {
127 :
128 : class WaitWindow_Impl : public WorkWindow
129 : {
130 : Rectangle maRect;
131 : DrawTextFlags mnTextStyle;
132 : OUString maText;
133 :
134 : public:
135 : WaitWindow_Impl();
136 : virtual ~WaitWindow_Impl();
137 : virtual void dispose() SAL_OVERRIDE;
138 : virtual void Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) SAL_OVERRIDE;
139 : };
140 :
141 : #define X_OFFSET 15
142 : #define Y_OFFSET 15
143 :
144 :
145 :
146 0 : struct NamePair_Impl
147 : {
148 : OUString maShortName;
149 : OUString maLongName;
150 : };
151 :
152 : class Updater_Impl;
153 : class DocTemplates_EntryData_Impl;
154 : class GroupData_Impl;
155 :
156 : typedef vector< NamePair_Impl* > NameList_Impl;
157 : typedef vector< GroupData_Impl* > GroupList_Impl;
158 :
159 :
160 74 : class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment >
161 : {
162 : uno::Reference< task::XInteractionHandler > m_xInteractionHandler;
163 : uno::Reference< ucb::XProgressHandler > m_xProgressHandler;
164 :
165 : public:
166 40 : TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler )
167 40 : : m_xInteractionHandler( rxInteractionHandler )
168 40 : {}
169 :
170 0 : virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
171 0 : { return m_xInteractionHandler; }
172 :
173 0 : virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
174 0 : { return m_xProgressHandler; }
175 : };
176 :
177 : class SfxDocTplService_Impl
178 : {
179 : uno::Reference< XComponentContext > mxContext;
180 : uno::Reference< XCommandEnvironment > maCmdEnv;
181 : uno::Reference< XDocumentProperties> m_xDocProps;
182 : uno::Reference< XTypeDetection > mxType;
183 :
184 : ::osl::Mutex maMutex;
185 : Sequence< OUString > maTemplateDirs;
186 : Sequence< OUString > maInternalTemplateDirs;
187 : OUString maRootURL;
188 : NameList_Impl maNames;
189 : lang::Locale maLocale;
190 : Content maRootContent;
191 : Updater_Impl* mpUpdater;
192 : bool mbIsInitialized : 1;
193 : bool mbLocaleSet : 1;
194 :
195 : SfxURLRelocator_Impl maRelocator;
196 :
197 : void init_Impl();
198 : void getDefaultLocale();
199 : void getDirList();
200 : void readFolderList();
201 : bool needsUpdate();
202 : OUString getLongName( const OUString& rShortName );
203 : bool setTitleForURL( const OUString& rURL, const OUString& aTitle );
204 : bool getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, bool& bDocHasTitle );
205 :
206 : bool addEntry( Content& rParentFolder,
207 : const OUString& rTitle,
208 : const OUString& rTargetURL,
209 : const OUString& rType );
210 :
211 : bool createFolder( const OUString& rNewFolderURL,
212 : bool bCreateParent,
213 : bool bFsysFolder,
214 : Content &rNewFolder );
215 :
216 : static bool CreateNewUniqueFolderWithPrefix( const OUString& aPath,
217 : const OUString& aPrefix,
218 : OUString& aNewFolderName,
219 : OUString& aNewFolderURL,
220 : Content& aNewFolder );
221 : static OUString CreateNewUniqueFileWithPrefix( const OUString& aPath,
222 : const OUString& aPrefix,
223 : const OUString& aExt );
224 :
225 : uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const OUString& aUserPath );
226 : bool UpdateUINamesForTemplateDir_Impl( const OUString& aUserPath,
227 : const OUString& aGroupName,
228 : const OUString& aNewFolderName );
229 : bool ReplaceUINamesForTemplateDir_Impl( const OUString& aUserPath,
230 : const OUString& aFsysGroupName,
231 : const OUString& aOldGroupName,
232 : const OUString& aNewGroupName );
233 : bool RemoveUINamesForTemplateDir_Impl( const OUString& aUserPath,
234 : const OUString& aGroupName );
235 : bool WriteUINamesForTemplateDir_Impl( const OUString& aUserPath,
236 : const uno::Sequence< beans::StringPair >& aUINames );
237 :
238 : OUString CreateNewGroupFsys( const OUString& rGroupName, Content& aGroup );
239 :
240 : static bool removeContent( Content& rContent );
241 : bool removeContent( const OUString& rContentURL );
242 :
243 : bool setProperty( Content& rContent,
244 : const OUString& rPropName,
245 : const Any& rPropValue );
246 : bool getProperty( Content& rContent,
247 : const OUString& rPropName,
248 : Any& rPropValue );
249 :
250 : void createFromContent( GroupList_Impl& rList,
251 : Content &rContent,
252 : bool bHierarchy,
253 : bool bWriteableContent = false );
254 : void addHierGroup( GroupList_Impl& rList,
255 : const OUString& rTitle,
256 : const OUString& rOwnURL );
257 : void addFsysGroup( GroupList_Impl& rList,
258 : const OUString& rTitle,
259 : const OUString& rUITitle,
260 : const OUString& rOwnURL,
261 : bool bWriteableGroup = false );
262 : void removeFromHierarchy( DocTemplates_EntryData_Impl *pData );
263 : void addToHierarchy( GroupData_Impl *pGroup,
264 : DocTemplates_EntryData_Impl *pData );
265 :
266 : void removeFromHierarchy( GroupData_Impl *pGroup );
267 : void addGroupToHierarchy( GroupData_Impl *pGroup );
268 :
269 : void updateData( DocTemplates_EntryData_Impl *pData );
270 :
271 : //See: #i66157# and rhbz#1065807
272 : //return which template dir the rURL is a subpath of
273 : OUString findParentTemplateDir(const OUString& rURL) const;
274 :
275 : //See: #i66157# and rhbz#1065807
276 : //return true if rURL is a path (or subpath of) a dir which is not a user path
277 : //which implies neither it or its contents can be removed
278 : bool isInternalTemplateDir(const OUString& rURL) const;
279 : public:
280 : SfxDocTplService_Impl( const uno::Reference< XComponentContext > & xContext );
281 : ~SfxDocTplService_Impl();
282 :
283 40 : bool init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; }
284 0 : Content getContent() const { return maRootContent; }
285 :
286 : void setLocale( const lang::Locale & rLocale );
287 : lang::Locale getLocale();
288 :
289 : bool storeTemplate( const OUString& rGroupName,
290 : const OUString& rTemplateName,
291 : const uno::Reference< frame::XStorable >& rStorable );
292 :
293 : bool addTemplate( const OUString& rGroupName,
294 : const OUString& rTemplateName,
295 : const OUString& rSourceURL );
296 : bool removeTemplate( const OUString& rGroupName,
297 : const OUString& rTemplateName );
298 : bool renameTemplate( const OUString& rGroupName,
299 : const OUString& rOldName,
300 : const OUString& rNewName );
301 :
302 : bool addGroup( const OUString& rGroupName );
303 : bool removeGroup( const OUString& rGroupName );
304 : bool renameGroup( const OUString& rOldName,
305 : const OUString& rNewName );
306 :
307 : void update( bool bUpdateNow );
308 : void doUpdate();
309 0 : void finished() { mpUpdater = NULL; }
310 : };
311 :
312 :
313 :
314 : class Updater_Impl : public ::osl::Thread
315 : {
316 : private:
317 : SfxDocTplService_Impl *mpDocTemplates;
318 :
319 : public:
320 : Updater_Impl( SfxDocTplService_Impl* pTemplates );
321 : virtual ~Updater_Impl();
322 :
323 : virtual void SAL_CALL run() SAL_OVERRIDE;
324 : virtual void SAL_CALL onTerminated() SAL_OVERRIDE;
325 : };
326 :
327 :
328 :
329 0 : class DocTemplates_EntryData_Impl
330 : {
331 : OUString maTitle;
332 : OUString maType;
333 : OUString maTargetURL;
334 : OUString maHierarchyURL;
335 :
336 : bool mbInHierarchy : 1;
337 : bool mbInUse : 1;
338 : bool mbUpdateType : 1;
339 : bool mbUpdateLink : 1;
340 :
341 : public:
342 : DocTemplates_EntryData_Impl( const OUString& rTitle );
343 :
344 0 : void setInUse() { mbInUse = true; }
345 0 : void setHierarchy( bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
346 0 : void setUpdateLink( bool bUpdateLink ) { mbUpdateLink = bUpdateLink; }
347 0 : void setUpdateType( bool bUpdateType ) { mbUpdateType = bUpdateType; }
348 :
349 0 : bool getInUse() const { return mbInUse; }
350 0 : bool getInHierarchy() const { return mbInHierarchy; }
351 0 : bool getUpdateLink() const { return mbUpdateLink; }
352 0 : bool getUpdateType() const { return mbUpdateType; }
353 :
354 0 : const OUString& getHierarchyURL() const { return maHierarchyURL; }
355 0 : const OUString& getTargetURL() const { return maTargetURL; }
356 0 : const OUString& getTitle() const { return maTitle; }
357 0 : const OUString& getType() const { return maType; }
358 :
359 0 : void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
360 0 : void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
361 0 : void setType( const OUString& rType ) { maType = rType; }
362 : };
363 :
364 :
365 :
366 : class GroupData_Impl
367 : {
368 : vector< DocTemplates_EntryData_Impl* > maEntries;
369 : OUString maTitle;
370 : OUString maHierarchyURL;
371 : OUString maTargetURL;
372 : bool mbInUse : 1;
373 : bool mbInHierarchy : 1;
374 :
375 : public:
376 : GroupData_Impl( const OUString& rTitle );
377 : ~GroupData_Impl();
378 :
379 0 : void setInUse() { mbInUse = true; }
380 0 : void setHierarchy( bool bInHierarchy ) { mbInHierarchy = bInHierarchy; }
381 0 : void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; }
382 0 : void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
383 :
384 0 : bool getInUse() const { return mbInUse; }
385 0 : bool getInHierarchy() const { return mbInHierarchy; }
386 0 : const OUString& getHierarchyURL() const { return maHierarchyURL; }
387 0 : const OUString& getTargetURL() const { return maTargetURL; }
388 0 : const OUString& getTitle() const { return maTitle; }
389 :
390 : DocTemplates_EntryData_Impl* addEntry( const OUString& rTitle,
391 : const OUString& rTargetURL,
392 : const OUString& rType,
393 : const OUString& rHierURL );
394 0 : size_t count() { return maEntries.size(); }
395 0 : DocTemplates_EntryData_Impl* getEntry( size_t nPos ) { return maEntries[ nPos ]; }
396 : };
397 :
398 :
399 : // private SfxDocTplService_Impl
400 :
401 40 : void SfxDocTplService_Impl::init_Impl()
402 : {
403 40 : uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
404 : uno::Reference < task::XInteractionHandler > xInteractionHandler(
405 80 : task::InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
406 40 : maCmdEnv = new TplTaskEnvironment( xInteractionHandler );
407 :
408 80 : ::osl::ClearableMutexGuard aGuard( maMutex );
409 40 : bool bIsInitialized = false;
410 40 : bool bNeedsUpdate = false;
411 :
412 40 : if ( !mbLocaleSet )
413 0 : getDefaultLocale();
414 :
415 : // convert locale to string
416 80 : OUString aLang = LanguageTag::convertToBcp47( maLocale);
417 :
418 : // set maRootContent to the root of the templates hierarchy. Create the
419 : // entry if necessary
420 :
421 40 : maRootURL = ( TEMPLATE_ROOT_URL "/" ) + aLang;
422 :
423 80 : OUString aTemplVersPropName( TEMPLATE_VERSION );
424 80 : OUString aTemplVers( TEMPLATE_VERSION_VALUE );
425 40 : if ( Content::create( maRootURL, maCmdEnv, comphelper::getProcessComponentContext(), maRootContent ) )
426 : {
427 0 : uno::Any aValue;
428 0 : OUString aPropValue;
429 0 : if ( getProperty( maRootContent, aTemplVersPropName, aValue )
430 0 : && ( aValue >>= aPropValue )
431 0 : && aPropValue.equals( aTemplVers ) )
432 : {
433 0 : bIsInitialized = true;
434 : }
435 : else
436 0 : removeContent( maRootContent );
437 : }
438 :
439 40 : if ( !bIsInitialized )
440 : {
441 160 : if ( createFolder( maRootURL, true, false, maRootContent )
442 120 : && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) )
443 0 : bIsInitialized = true;
444 :
445 40 : bNeedsUpdate = true;
446 : }
447 :
448 40 : if ( bIsInitialized )
449 : {
450 : try {
451 : m_xDocProps.set(document::DocumentProperties::create(
452 0 : ::comphelper::getProcessComponentContext()));
453 0 : } catch (uno::RuntimeException const& e) {
454 : SAL_WARN("sfx.doc", "SfxDocTplService_Impl::init_Impl: "
455 : "cannot create DocumentProperties service:" << e.Message);
456 : }
457 :
458 0 : OUString const aService = SERVICENAME_TYPEDETECTION;
459 0 : mxType = uno::Reference< XTypeDetection > ( mxContext->getServiceManager()->createInstanceWithContext(aService, mxContext), UNO_QUERY );
460 :
461 0 : getDirList();
462 0 : readFolderList();
463 :
464 0 : if ( bNeedsUpdate )
465 : {
466 0 : aGuard.clear();
467 0 : SolarMutexClearableGuard aSolarGuard;
468 :
469 0 : VclPtrInstance< WaitWindow_Impl > pWin;
470 0 : aSolarGuard.clear();
471 0 : ::osl::ClearableMutexGuard anotherGuard( maMutex );
472 :
473 0 : update( true );
474 :
475 0 : anotherGuard.clear();
476 0 : SolarMutexGuard aSecondSolarGuard;
477 :
478 0 : pWin.disposeAndClear();
479 : }
480 0 : else if ( needsUpdate() )
481 : // the UI should be shown only on the first update
482 0 : update( true );
483 : }
484 : else
485 : {
486 : SAL_WARN( "sfx.doc", "init_Impl(): Could not create root" );
487 : }
488 :
489 80 : mbIsInitialized = bIsInitialized;
490 40 : }
491 :
492 :
493 39 : void SfxDocTplService_Impl::getDefaultLocale()
494 : {
495 39 : if ( !mbLocaleSet )
496 : {
497 39 : ::osl::MutexGuard aGuard( maMutex );
498 39 : if ( !mbLocaleSet )
499 : {
500 39 : maLocale = LanguageTag( utl::ConfigManager::getLocale()).getLocale( false);
501 39 : mbLocaleSet = true;
502 39 : }
503 : }
504 39 : }
505 :
506 :
507 0 : void SfxDocTplService_Impl::readFolderList()
508 : {
509 0 : SolarMutexGuard aGuard;
510 :
511 0 : ResStringArray aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) );
512 0 : ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) );
513 :
514 :
515 0 : sal_uInt16 nCount = (sal_uInt16)( std::min( aShortNames.Count(), aLongNames.Count() ) );
516 :
517 0 : for ( sal_uInt16 i=0; i<nCount; i++ )
518 : {
519 0 : NamePair_Impl* pPair = new NamePair_Impl;
520 0 : pPair->maShortName = aShortNames.GetString( i );
521 0 : pPair->maLongName = aLongNames.GetString( i );
522 :
523 0 : maNames.push_back( pPair );
524 0 : }
525 0 : }
526 :
527 :
528 0 : OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName )
529 : {
530 0 : OUString aRet;
531 :
532 0 : for ( size_t i = 0, n = maNames.size(); i < n; ++i )
533 : {
534 0 : NamePair_Impl* pPair = maNames[ i ];
535 0 : if ( pPair->maShortName == rShortName )
536 : {
537 0 : aRet = pPair->maLongName;
538 0 : break;
539 : }
540 : }
541 :
542 0 : if ( aRet.isEmpty() )
543 0 : aRet = rShortName;
544 :
545 0 : return aRet;
546 : }
547 :
548 :
549 0 : void SfxDocTplService_Impl::getDirList()
550 : {
551 0 : OUString aPropName( PROPERTY_DIRLIST );
552 0 : Any aValue;
553 :
554 : // Get the template dir list
555 : // TODO/LATER: let use service, register listener
556 0 : INetURLObject aURL;
557 0 : OUString aDirs = SvtPathOptions().GetTemplatePath();
558 0 : sal_Int32 nCount = comphelper::string::getTokenCount(aDirs, C_DELIM);
559 :
560 0 : maTemplateDirs = Sequence< OUString >( nCount );
561 :
562 0 : uno::Reference< util::XMacroExpander > xExpander = util::theMacroExpander::get(mxContext);
563 : const OUString aPrefix(
564 0 : "vnd.sun.star.expand:" );
565 :
566 0 : for (sal_Int32 i = 0; i < nCount; ++i)
567 : {
568 0 : aURL.SetSmartProtocol( INetProtocol::File );
569 0 : aURL.SetURL( aDirs.getToken( i, C_DELIM ) );
570 0 : maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE );
571 :
572 0 : sal_Int32 nIndex = maTemplateDirs[i].indexOf( aPrefix );
573 0 : if ( nIndex != -1 && xExpander.is() )
574 : {
575 0 : maTemplateDirs[i] = maTemplateDirs[i].replaceAt(nIndex,
576 : aPrefix.getLength(),
577 0 : OUString());
578 0 : maTemplateDirs[i] = xExpander->expandMacros( maTemplateDirs[i] );
579 : }
580 : }
581 :
582 0 : aValue <<= maTemplateDirs;
583 :
584 : css::uno::Reference< css::util::XPathSettings > xPathSettings =
585 0 : css::util::thePathSettings::get(mxContext);
586 :
587 : // load internal paths
588 0 : OUString sProp( "Template_internal" );
589 0 : Any aAny = xPathSettings->getPropertyValue( sProp );
590 0 : aAny >>= maInternalTemplateDirs;
591 :
592 0 : nCount = maInternalTemplateDirs.getLength();
593 0 : for (sal_Int32 i = 0; i < nCount; ++i)
594 : {
595 : //expand vnd.sun.star.expand: and remove "..." from them
596 : //to normalize into the expected url patterns
597 0 : maRelocator.makeRelocatableURL(maInternalTemplateDirs[i]);
598 0 : maRelocator.makeAbsoluteURL(maInternalTemplateDirs[i]);
599 : }
600 :
601 : // Store the template dir list
602 0 : setProperty( maRootContent, aPropName, aValue );
603 0 : }
604 :
605 :
606 0 : bool SfxDocTplService_Impl::needsUpdate()
607 : {
608 0 : OUString aPropName( PROPERTY_NEEDSUPDATE );
609 0 : bool bNeedsUpdate = true;
610 0 : Any aValue;
611 :
612 : // Get the template dir list
613 0 : bool bHasProperty = getProperty( maRootContent, aPropName, aValue );
614 :
615 0 : if ( bHasProperty )
616 0 : aValue >>= bNeedsUpdate;
617 :
618 : // the old template component also checks this state, but it is initialized from this component
619 : // so if this componend was already updated the old component does not need such an update
620 0 : ::svt::TemplateFolderCache aTempCache;
621 0 : if ( !bNeedsUpdate )
622 0 : bNeedsUpdate = aTempCache.needsUpdate();
623 :
624 0 : if ( bNeedsUpdate )
625 0 : aTempCache.storeState();
626 :
627 0 : return bNeedsUpdate;
628 : }
629 :
630 :
631 0 : bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle )
632 : {
633 0 : if (m_xDocProps.is())
634 : {
635 : try
636 : {
637 0 : m_xDocProps->loadFromMedium(rURL, Sequence<PropertyValue>());
638 0 : m_xDocProps->setTitle(aTitle);
639 :
640 : uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
641 0 : rURL, embed::ElementModes::READWRITE);
642 :
643 0 : uno::Sequence<beans::PropertyValue> medium(2);
644 0 : medium[0].Name = "DocumentBaseURL";
645 0 : medium[0].Value <<= rURL;
646 0 : medium[1].Name = "URL";
647 0 : medium[1].Value <<= rURL;
648 :
649 0 : m_xDocProps->storeToStorage(xStorage, medium);
650 0 : return true;
651 : }
652 0 : catch ( Exception& )
653 : {
654 : }
655 : }
656 0 : return false;
657 : }
658 :
659 :
660 0 : bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, bool& bDocHasTitle )
661 : {
662 0 : bDocHasTitle = false;
663 :
664 0 : if (m_xDocProps.is())
665 : {
666 : try
667 : {
668 0 : m_xDocProps->loadFromMedium(rURL, Sequence<PropertyValue>());
669 0 : aTitle = m_xDocProps->getTitle();
670 : }
671 0 : catch ( Exception& )
672 : {
673 : }
674 : }
675 :
676 0 : if ( aType.isEmpty() && mxType.is() )
677 : {
678 0 : OUString aDocType = mxType->queryTypeByURL( rURL );
679 0 : if ( !aDocType.isEmpty() )
680 : try
681 : {
682 0 : uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW );
683 0 : SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) );
684 0 : aType = aTypeProps.getUnpackedValueOrDefault(
685 : OUString("MediaType"),
686 0 : OUString() );
687 : }
688 0 : catch( uno::Exception& )
689 0 : {}
690 : }
691 :
692 0 : if ( aTitle.isEmpty() )
693 : {
694 0 : INetURLObject aURL( rURL );
695 0 : aURL.CutExtension();
696 0 : aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
697 0 : INetURLObject::DECODE_WITH_CHARSET );
698 : }
699 : else
700 0 : bDocHasTitle = true;
701 :
702 0 : return true;
703 : }
704 :
705 :
706 0 : bool SfxDocTplService_Impl::addEntry( Content& rParentFolder,
707 : const OUString& rTitle,
708 : const OUString& rTargetURL,
709 : const OUString& rType )
710 : {
711 0 : bool bAddedEntry = false;
712 :
713 0 : INetURLObject aLinkObj( rParentFolder.getURL() );
714 : aLinkObj.insertName( rTitle, false,
715 : INetURLObject::LAST_SEGMENT, true,
716 0 : INetURLObject::ENCODE_ALL );
717 0 : OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE );
718 :
719 0 : Content aLink;
720 :
721 0 : if ( ! Content::create( aLinkURL, maCmdEnv, comphelper::getProcessComponentContext(), aLink ) )
722 : {
723 0 : Sequence< OUString > aNames(3);
724 0 : aNames[0] = TITLE;
725 0 : aNames[1] = IS_FOLDER;
726 0 : aNames[2] = TARGET_URL;
727 :
728 0 : Sequence< Any > aValues(3);
729 0 : aValues[0] = makeAny( rTitle );
730 0 : aValues[1] = makeAny( false );
731 0 : aValues[2] = makeAny( rTargetURL );
732 :
733 0 : OUString aType( TYPE_LINK );
734 0 : OUString aAdditionalProp( PROPERTY_TYPE );
735 :
736 : try
737 : {
738 0 : rParentFolder.insertNewContent( aType, aNames, aValues, aLink );
739 0 : setProperty( aLink, aAdditionalProp, makeAny( rType ) );
740 0 : bAddedEntry = true;
741 : }
742 0 : catch( Exception& )
743 0 : {}
744 : }
745 0 : return bAddedEntry;
746 : }
747 :
748 :
749 80 : bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL,
750 : bool bCreateParent,
751 : bool bFsysFolder,
752 : Content &rNewFolder )
753 : {
754 80 : Content aParent;
755 80 : bool bCreatedFolder = false;
756 160 : INetURLObject aParentURL( rNewFolderURL );
757 : OUString aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true,
758 160 : INetURLObject::DECODE_WITH_CHARSET );
759 :
760 : // compute the parent folder url from the new folder url
761 : // and remove the final slash, because Content::create doesn't
762 : // like it
763 80 : aParentURL.removeSegment();
764 80 : if ( aParentURL.getSegmentCount() >= 1 )
765 40 : aParentURL.removeFinalSlash();
766 :
767 : // if the parent exists, we can continue with the creation of the
768 : // new folder, we have to create the parent otherwise ( as long as
769 : // bCreateParent is set to true )
770 80 : if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, comphelper::getProcessComponentContext(), aParent ) )
771 : {
772 : try
773 : {
774 0 : Sequence< OUString > aNames(2);
775 0 : aNames[0] = TITLE;
776 0 : aNames[1] = IS_FOLDER;
777 :
778 0 : Sequence< Any > aValues(2);
779 0 : aValues[0] = makeAny( aFolderName );
780 0 : aValues[1] = makeAny( true );
781 :
782 0 : OUString aType;
783 :
784 0 : if ( bFsysFolder )
785 0 : aType = TYPE_FSYS_FOLDER;
786 : else
787 0 : aType = TYPE_FOLDER;
788 :
789 0 : aParent.insertNewContent( aType, aNames, aValues, rNewFolder );
790 0 : bCreatedFolder = true;
791 : }
792 0 : catch( RuntimeException& )
793 : {
794 : SAL_WARN( "sfx.doc", "createFolder(): got runtime exception" );
795 : }
796 0 : catch( Exception& )
797 : {
798 : SAL_WARN( "sfx.doc", "createFolder(): Could not create new folder" );
799 : }
800 : }
801 80 : else if ( bCreateParent )
802 : {
803 : // if the parent doesn't exists and bCreateParent is set to true,
804 : // we try to create the parent and if this was successful, we
805 : // try to create the new folder again ( but this time, we set
806 : // bCreateParent to false to avoid endless recusions )
807 280 : if ( ( aParentURL.getSegmentCount() >= 1 ) &&
808 200 : createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) )
809 : {
810 0 : bCreatedFolder = createFolder( rNewFolderURL, false, bFsysFolder, rNewFolder );
811 : }
812 : }
813 :
814 160 : return bCreatedFolder;
815 : }
816 :
817 :
818 0 : bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const OUString& aPath,
819 : const OUString& aPrefix,
820 : OUString& aNewFolderName,
821 : OUString& aNewFolderURL,
822 : Content& aNewFolder )
823 : {
824 0 : bool bCreated = false;
825 0 : INetURLObject aDirPath( aPath );
826 :
827 0 : Content aParent;
828 0 : uno::Reference< XCommandEnvironment > aQuietEnv;
829 0 : if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, comphelper::getProcessComponentContext(), aParent ) )
830 : {
831 0 : for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
832 : {
833 0 : OUString aTryName = aPrefix;
834 0 : if ( nInd )
835 0 : aTryName += OUString::number( nInd );
836 :
837 : try
838 : {
839 0 : Sequence< OUString > aNames(2);
840 0 : aNames[0] = TITLE;
841 0 : aNames[1] = IS_FOLDER;
842 :
843 0 : Sequence< Any > aValues(2);
844 0 : aValues[0] = makeAny( aTryName );
845 0 : aValues[1] = makeAny( true );
846 :
847 0 : OUString aType( TYPE_FSYS_FOLDER );
848 :
849 0 : bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder );
850 : }
851 0 : catch( ucb::NameClashException& )
852 : {
853 : // if there is already an element, retry
854 : }
855 0 : catch( Exception& )
856 : {
857 0 : INetURLObject aObjPath( aDirPath );
858 : aObjPath.insertName( aTryName, false,
859 : INetURLObject::LAST_SEGMENT, true,
860 0 : INetURLObject::ENCODE_ALL );
861 : // if there is already an element, retry
862 : // if there was another error, do not try any more
863 0 : if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
864 0 : break;
865 0 : }
866 :
867 0 : if ( bCreated )
868 : {
869 0 : aNewFolderName = aTryName;
870 0 : aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier();
871 0 : break;
872 : }
873 0 : }
874 : }
875 :
876 0 : return bCreated;
877 : }
878 :
879 :
880 0 : OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const OUString& aPath,
881 : const OUString& aPrefix,
882 : const OUString& aExt )
883 : {
884 0 : OUString aNewFileURL;
885 0 : INetURLObject aDirPath( aPath );
886 :
887 0 : Content aParent;
888 :
889 0 : uno::Reference< XCommandEnvironment > aQuietEnv;
890 0 : if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, comphelper::getProcessComponentContext(), aParent ) )
891 : {
892 0 : for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ )
893 : {
894 0 : Content aNewFile;
895 0 : bool bCreated = false;
896 0 : OUString aTryName = aPrefix;
897 0 : if ( nInd )
898 0 : aTryName += OUString::number( nInd );
899 0 : if ( aExt.toChar() != '.' )
900 0 : aTryName += ".";
901 0 : aTryName += aExt;
902 :
903 : try
904 : {
905 0 : Sequence< OUString > aNames(2);
906 0 : aNames[0] = TITLE;
907 0 : aNames[1] = IS_DOCUMENT;
908 :
909 0 : Sequence< Any > aValues(2);
910 0 : aValues[0] = makeAny( aTryName );
911 0 : aValues[1] = makeAny( true );
912 :
913 0 : OUString aType( TYPE_FSYS_FILE );
914 :
915 0 : bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile );
916 : }
917 0 : catch( ucb::NameClashException& )
918 : {
919 : // if there is already an element, retry
920 : }
921 0 : catch( Exception& )
922 : {
923 0 : INetURLObject aObjPath( aPath );
924 : aObjPath.insertName( aTryName, false,
925 : INetURLObject::LAST_SEGMENT, true,
926 0 : INetURLObject::ENCODE_ALL );
927 : // if there is already an element, retry
928 : // if there was another error, do not try any more
929 0 : if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) )
930 0 : break;
931 0 : }
932 :
933 0 : if ( bCreated )
934 : {
935 0 : aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier();
936 0 : break;
937 : }
938 0 : }
939 : }
940 :
941 0 : return aNewFileURL;
942 : }
943 :
944 :
945 0 : bool SfxDocTplService_Impl::removeContent( Content& rContent )
946 : {
947 0 : bool bRemoved = false;
948 : try
949 : {
950 0 : OUString aCmd( COMMAND_DELETE );
951 0 : Any aArg = makeAny( true );
952 :
953 0 : rContent.executeCommand( aCmd, aArg );
954 0 : bRemoved = true;
955 : }
956 0 : catch ( RuntimeException& ) {}
957 0 : catch ( Exception& ) {}
958 :
959 0 : return bRemoved;
960 : }
961 :
962 :
963 0 : bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL )
964 : {
965 0 : Content aContent;
966 :
967 0 : if ( Content::create( rContentURL, maCmdEnv, comphelper::getProcessComponentContext(), aContent ) )
968 0 : return removeContent( aContent );
969 : else
970 0 : return false;
971 : }
972 :
973 :
974 0 : bool SfxDocTplService_Impl::setProperty( Content& rContent,
975 : const OUString& rPropName,
976 : const Any& rPropValue )
977 : {
978 0 : bool bPropertySet = false;
979 :
980 : // Store the property
981 : try
982 : {
983 0 : Any aPropValue( rPropValue );
984 0 : uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
985 :
986 : // check, whether or not the property exists, create it, when not
987 0 : if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
988 : {
989 0 : uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY );
990 0 : if ( xProperties.is() )
991 : {
992 : try
993 : {
994 0 : xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue );
995 : }
996 0 : catch( PropertyExistException& ) {}
997 0 : catch( IllegalTypeException& ) {
998 : SAL_WARN( "sfx.doc", "IllegalTypeException" );
999 : }
1000 0 : catch( IllegalArgumentException& ) {
1001 : SAL_WARN( "sfx.doc", "IllegalArgumentException" );
1002 : }
1003 0 : }
1004 : }
1005 :
1006 : // To ensure a reloctable office installation, the path to the
1007 : // office installtion directory must never be stored directly.
1008 0 : if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1009 : {
1010 0 : OUString aValue;
1011 0 : if ( rPropValue >>= aValue )
1012 : {
1013 0 : maRelocator.makeRelocatableURL( aValue );
1014 0 : aPropValue = makeAny( aValue );
1015 : }
1016 : else
1017 : {
1018 0 : Sequence< OUString > aValues;
1019 0 : if ( rPropValue >>= aValues )
1020 : {
1021 0 : for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1022 : {
1023 0 : maRelocator.makeRelocatableURL( aValues[ n ] );
1024 : }
1025 0 : aPropValue = makeAny( aValues );
1026 : }
1027 : else
1028 : {
1029 : OSL_FAIL( "Unsupported property value type" );
1030 0 : }
1031 0 : }
1032 : }
1033 :
1034 : // now set the property
1035 :
1036 0 : rContent.setPropertyValue( rPropName, aPropValue );
1037 0 : bPropertySet = true;
1038 : }
1039 0 : catch ( RuntimeException& ) {}
1040 0 : catch ( Exception& ) {}
1041 :
1042 0 : return bPropertySet;
1043 : }
1044 :
1045 :
1046 0 : bool SfxDocTplService_Impl::getProperty(Content& rContent, const OUString& rPropName, Any& rPropValue)
1047 : {
1048 0 : bool bGotProperty = false;
1049 :
1050 : // Get the property
1051 : try
1052 : {
1053 0 : uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1054 :
1055 : // check, whether or not the property exists
1056 0 : if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1057 : {
1058 0 : return false;
1059 : }
1060 :
1061 : // now get the property
1062 :
1063 0 : rPropValue = rContent.getPropertyValue( rPropName );
1064 :
1065 : // To ensure a reloctable office installation, the path to the
1066 : // office installtion directory must never be stored directly.
1067 0 : if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1068 : {
1069 0 : OUString aValue;
1070 0 : if ( rPropValue >>= aValue )
1071 : {
1072 0 : maRelocator.makeAbsoluteURL( aValue );
1073 0 : rPropValue = makeAny( aValue );
1074 : }
1075 : else
1076 : {
1077 0 : Sequence< OUString > aValues;
1078 0 : if ( rPropValue >>= aValues )
1079 : {
1080 0 : for ( sal_Int32 n = 0; n < aValues.getLength(); n++ )
1081 : {
1082 0 : maRelocator.makeAbsoluteURL( aValues[ n ] );
1083 : }
1084 0 : rPropValue = makeAny( aValues );
1085 : }
1086 : else
1087 : {
1088 : OSL_FAIL( "Unsupported property value type" );
1089 0 : }
1090 0 : }
1091 : }
1092 :
1093 0 : bGotProperty = true;
1094 : }
1095 0 : catch ( RuntimeException& ) {}
1096 0 : catch ( Exception& ) {}
1097 :
1098 0 : return bGotProperty;
1099 : }
1100 :
1101 40 : SfxDocTplService_Impl::SfxDocTplService_Impl( const uno::Reference< XComponentContext > & xContext )
1102 40 : : maRelocator(xContext)
1103 : {
1104 40 : mxContext = xContext;
1105 40 : mpUpdater = NULL;
1106 40 : mbIsInitialized = false;
1107 40 : mbLocaleSet = false;
1108 40 : }
1109 :
1110 :
1111 74 : SfxDocTplService_Impl::~SfxDocTplService_Impl()
1112 : {
1113 37 : ::osl::MutexGuard aGuard( maMutex );
1114 :
1115 37 : if ( mpUpdater )
1116 : {
1117 0 : mpUpdater->terminate();
1118 0 : mpUpdater->join();
1119 0 : delete mpUpdater;
1120 : }
1121 :
1122 37 : for ( size_t i = 0, n = maNames.size(); i < n; ++i )
1123 0 : delete maNames[ i ];
1124 37 : maNames.clear();
1125 37 : }
1126 :
1127 :
1128 39 : lang::Locale SfxDocTplService_Impl::getLocale()
1129 : {
1130 39 : ::osl::MutexGuard aGuard( maMutex );
1131 :
1132 39 : if ( !mbLocaleSet )
1133 39 : getDefaultLocale();
1134 :
1135 39 : return maLocale;
1136 : }
1137 :
1138 :
1139 0 : void SfxDocTplService_Impl::setLocale( const lang::Locale &rLocale )
1140 : {
1141 0 : ::osl::MutexGuard aGuard( maMutex );
1142 :
1143 0 : if ( mbLocaleSet && (
1144 0 : ( maLocale.Language != rLocale.Language ) ||
1145 0 : ( maLocale.Country != rLocale.Country ) ||
1146 0 : ( maLocale.Variant != rLocale.Variant ) ) )
1147 0 : mbIsInitialized = false;
1148 :
1149 0 : maLocale = rLocale;
1150 0 : mbLocaleSet = true;
1151 0 : }
1152 :
1153 :
1154 0 : void SfxDocTplService_Impl::update( bool bUpdateNow )
1155 : {
1156 0 : ::osl::MutexGuard aGuard( maMutex );
1157 :
1158 0 : if ( bUpdateNow )
1159 0 : doUpdate();
1160 : else
1161 : {
1162 0 : mpUpdater = new Updater_Impl( this );
1163 0 : mpUpdater->create();
1164 0 : }
1165 0 : }
1166 :
1167 :
1168 0 : void SfxDocTplService_Impl::doUpdate()
1169 : {
1170 0 : ::osl::MutexGuard aGuard( maMutex );
1171 :
1172 0 : OUString aPropName( PROPERTY_NEEDSUPDATE );
1173 0 : Any aValue;
1174 :
1175 0 : aValue <<= sal_True;
1176 0 : setProperty( maRootContent, aPropName, aValue );
1177 :
1178 0 : GroupList_Impl aGroupList;
1179 :
1180 : // get the entries from the hierarchy
1181 0 : createFromContent( aGroupList, maRootContent, true );
1182 :
1183 : // get the entries from the template directories
1184 0 : sal_Int32 nCountDir = maTemplateDirs.getLength();
1185 0 : OUString* pDirs = maTemplateDirs.getArray();
1186 0 : Content aDirContent;
1187 :
1188 : // the last directory in the list must be writable
1189 0 : bool bWriteableDirectory = true;
1190 :
1191 : // the target folder might not exist, for this reason no interaction handler should be used
1192 0 : uno::Reference< XCommandEnvironment > aQuietEnv;
1193 :
1194 0 : while ( nCountDir )
1195 : {
1196 0 : nCountDir--;
1197 0 : if ( Content::create( pDirs[ nCountDir ], aQuietEnv, comphelper::getProcessComponentContext(), aDirContent ) )
1198 : {
1199 0 : createFromContent( aGroupList, aDirContent, false, bWriteableDirectory );
1200 : }
1201 :
1202 0 : bWriteableDirectory = false;
1203 : }
1204 :
1205 : // now check the list
1206 0 : for( size_t j = 0, n = aGroupList.size(); j < n; ++j )
1207 : {
1208 0 : GroupData_Impl *pGroup = aGroupList[ j ];
1209 0 : if ( pGroup->getInUse() )
1210 : {
1211 0 : if ( pGroup->getInHierarchy() )
1212 : {
1213 0 : Content aGroup;
1214 0 : if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1215 : setProperty( aGroup,
1216 : OUString( TARGET_DIR_URL ),
1217 0 : makeAny( pGroup->getTargetURL() ) );
1218 :
1219 0 : size_t nCount = pGroup->count();
1220 0 : for ( size_t i=0; i<nCount; i++ )
1221 : {
1222 0 : DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
1223 0 : if ( ! pData->getInUse() )
1224 : {
1225 0 : if ( pData->getInHierarchy() )
1226 0 : removeFromHierarchy( pData ); // delete entry in hierarchy
1227 : else
1228 0 : addToHierarchy( pGroup, pData ); // add entry to hierarchy
1229 : }
1230 0 : else if ( pData->getUpdateType() ||
1231 0 : pData->getUpdateLink() )
1232 : {
1233 0 : updateData( pData );
1234 : }
1235 0 : }
1236 : }
1237 : else
1238 : {
1239 0 : addGroupToHierarchy( pGroup ); // add group to hierarchy
1240 : }
1241 : }
1242 : else
1243 0 : removeFromHierarchy( pGroup ); // delete group from hierarchy
1244 :
1245 0 : delete pGroup;
1246 : }
1247 0 : aGroupList.clear();
1248 :
1249 0 : aValue <<= sal_False;
1250 0 : setProperty( maRootContent, aPropName, aValue );
1251 0 : }
1252 :
1253 :
1254 0 : uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const OUString& aUserPath )
1255 : {
1256 0 : INetURLObject aLocObj( aUserPath );
1257 : aLocObj.insertName( OUString( "groupuinames.xml" ), false,
1258 : INetURLObject::LAST_SEGMENT, true,
1259 0 : INetURLObject::ENCODE_ALL );
1260 0 : Content aLocContent;
1261 :
1262 : // TODO/LATER: Use hashmap in future
1263 0 : uno::Sequence< beans::StringPair > aUINames;
1264 0 : if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext(), aLocContent ) )
1265 : {
1266 : try
1267 : {
1268 0 : uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream();
1269 0 : if ( xLocStream.is() )
1270 0 : aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxContext );
1271 : }
1272 0 : catch( uno::Exception& )
1273 : {}
1274 : }
1275 :
1276 0 : return aUINames;
1277 : }
1278 :
1279 :
1280 0 : bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const OUString& aUserPath,
1281 : const OUString& aGroupName,
1282 : const OUString& aNewFolderName )
1283 : {
1284 0 : uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1285 0 : sal_Int32 nLen = aUINames.getLength();
1286 :
1287 : // it is possible that the name is used already, but it should be checked before
1288 0 : for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1289 0 : if ( aUINames[nInd].First.equals( aNewFolderName ) )
1290 0 : return false;
1291 :
1292 0 : aUINames.realloc( ++nLen );
1293 0 : aUINames[nLen-1].First = aNewFolderName;
1294 0 : aUINames[nLen-1].Second = aGroupName;
1295 :
1296 0 : return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1297 : }
1298 :
1299 :
1300 0 : bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const OUString& aUserPath,
1301 : const OUString& aDefaultFsysGroupName,
1302 : const OUString& aOldGroupName,
1303 : const OUString& aNewGroupName )
1304 : {
1305 0 : uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1306 0 : sal_Int32 nLen = aUINames.getLength();
1307 :
1308 0 : bool bChanged = false;
1309 0 : for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1310 0 : if ( aUINames[nInd].Second.equals( aOldGroupName ) )
1311 : {
1312 0 : aUINames[nInd].Second = aNewGroupName;
1313 0 : bChanged = true;
1314 : }
1315 :
1316 0 : if ( !bChanged )
1317 : {
1318 0 : aUINames.realloc( ++nLen );
1319 0 : aUINames[nLen-1].First = aDefaultFsysGroupName;
1320 0 : aUINames[nLen-1].Second = aNewGroupName;
1321 : }
1322 0 : return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames );
1323 : }
1324 :
1325 :
1326 0 : bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const OUString& aUserPath,
1327 : const OUString& aGroupName )
1328 : {
1329 0 : uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath );
1330 0 : sal_Int32 nLen = aUINames.getLength();
1331 0 : uno::Sequence< beans::StringPair > aNewUINames( nLen );
1332 0 : sal_Int32 nNewLen = 0;
1333 :
1334 0 : bool bChanged = false;
1335 0 : for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
1336 0 : if ( aUINames[nInd].Second.equals( aGroupName ) )
1337 0 : bChanged = true;
1338 : else
1339 : {
1340 0 : nNewLen++;
1341 0 : aNewUINames[nNewLen-1].First = aUINames[nInd].First;
1342 0 : aNewUINames[nNewLen-1].Second = aUINames[nInd].Second;
1343 : }
1344 :
1345 0 : aNewUINames.realloc( nNewLen );
1346 :
1347 0 : return !bChanged || WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames );
1348 : }
1349 :
1350 :
1351 :
1352 0 : bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const OUString& aUserPath,
1353 : const uno::Sequence< beans::StringPair >& aUINames )
1354 : {
1355 0 : bool bResult = false;
1356 : try {
1357 : uno::Reference< beans::XPropertySet > xTempFile(
1358 : io::TempFile::create(mxContext),
1359 0 : uno::UNO_QUERY_THROW );
1360 :
1361 0 : OUString aTempURL;
1362 0 : uno::Any aUrl = xTempFile->getPropertyValue("Uri");
1363 0 : aUrl >>= aTempURL;
1364 :
1365 0 : uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW );
1366 0 : uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream();
1367 0 : if ( !xOutStream.is() )
1368 0 : throw uno::RuntimeException();
1369 :
1370 0 : DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxContext);
1371 : try {
1372 : // the SAX writer might close the stream
1373 0 : xOutStream->closeOutput();
1374 0 : } catch( uno::Exception& )
1375 : {}
1376 :
1377 0 : Content aTargetContent( aUserPath, maCmdEnv, comphelper::getProcessComponentContext() );
1378 0 : Content aSourceContent( aTempURL, maCmdEnv, comphelper::getProcessComponentContext() );
1379 : aTargetContent.transferContent( aSourceContent,
1380 : InsertOperation_COPY,
1381 : OUString( "groupuinames.xml" ),
1382 : ucb::NameClash::OVERWRITE,
1383 0 : OUString( "text/xml" ) );
1384 0 : bResult = true;
1385 : }
1386 0 : catch ( uno::Exception& )
1387 : {
1388 : }
1389 :
1390 0 : return bResult;
1391 : }
1392 :
1393 :
1394 0 : OUString SfxDocTplService_Impl::CreateNewGroupFsys( const OUString& rGroupName, Content& aGroup )
1395 : {
1396 0 : OUString aResultURL;
1397 :
1398 0 : if ( maTemplateDirs.getLength() )
1399 : {
1400 0 : OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ];
1401 :
1402 : // create a new folder with the given name
1403 0 : Content aNewFolder;
1404 0 : OUString aNewFolderName;
1405 :
1406 : // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1407 0 : if ( !CreateNewUniqueFolderWithPrefix( aTargetPath,
1408 : rGroupName,
1409 : aNewFolderName,
1410 : aResultURL,
1411 0 : aNewFolder )
1412 0 : && !CreateNewUniqueFolderWithPrefix( aTargetPath,
1413 : OUString( "UserGroup" ),
1414 : aNewFolderName,
1415 : aResultURL,
1416 0 : aNewFolder ) )
1417 :
1418 0 : return OUString();
1419 :
1420 0 : if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) )
1421 : {
1422 : // we could not create the groupuinames for the folder, so we delete the group in the
1423 : // the folder and return
1424 0 : removeContent( aNewFolder );
1425 0 : return OUString();
1426 : }
1427 :
1428 : // Now set the target url for this group and we are done
1429 0 : OUString aPropName( TARGET_DIR_URL );
1430 0 : Any aValue = makeAny( aResultURL );
1431 :
1432 0 : if ( ! setProperty( aGroup, aPropName, aValue ) )
1433 : {
1434 0 : removeContent( aNewFolder );
1435 0 : return OUString();
1436 0 : }
1437 : }
1438 :
1439 0 : return aResultURL;
1440 : }
1441 :
1442 :
1443 0 : bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName )
1444 : {
1445 0 : ::osl::MutexGuard aGuard( maMutex );
1446 :
1447 : // Check, whether or not there is a group with this name
1448 0 : Content aNewGroup;
1449 0 : OUString aNewGroupURL;
1450 0 : INetURLObject aNewGroupObj( maRootURL );
1451 :
1452 : aNewGroupObj.insertName( rGroupName, false,
1453 : INetURLObject::LAST_SEGMENT, true,
1454 0 : INetURLObject::ENCODE_ALL );
1455 :
1456 0 : aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1457 :
1458 0 : if ( Content::create( aNewGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aNewGroup ) ||
1459 0 : ! createFolder( aNewGroupURL, false, false, aNewGroup ) )
1460 : {
1461 : // if there already was a group with this name or the new group
1462 : // could not be created, we return here
1463 0 : return false;
1464 : }
1465 :
1466 : // Get the user template path entry ( new group will always
1467 : // be added in the user template path )
1468 : sal_Int32 nIndex;
1469 0 : OUString aUserPath;
1470 :
1471 0 : nIndex = maTemplateDirs.getLength();
1472 0 : if ( nIndex )
1473 0 : nIndex--;
1474 : else
1475 0 : return false; // We don't know where to add the group
1476 :
1477 0 : aUserPath = maTemplateDirs[ nIndex ];
1478 :
1479 : // create a new folder with the given name
1480 0 : Content aNewFolder;
1481 0 : OUString aNewFolderName;
1482 0 : OUString aNewFolderURL;
1483 :
1484 : // the Fsys name instead of GroupName should be used, the groupuinames must be added also
1485 0 : if ( !CreateNewUniqueFolderWithPrefix( aUserPath,
1486 : rGroupName,
1487 : aNewFolderName,
1488 : aNewFolderURL,
1489 0 : aNewFolder )
1490 0 : && !CreateNewUniqueFolderWithPrefix( aUserPath,
1491 : OUString( "UserGroup" ),
1492 : aNewFolderName,
1493 : aNewFolderURL,
1494 0 : aNewFolder ) )
1495 : {
1496 : // we could not create the folder, so we delete the group in the
1497 : // hierarchy and return
1498 0 : removeContent( aNewGroup );
1499 0 : return false;
1500 : }
1501 :
1502 0 : if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) )
1503 : {
1504 : // we could not create the groupuinames for the folder, so we delete the group in the
1505 : // hierarchy, the folder and return
1506 0 : removeContent( aNewGroup );
1507 0 : removeContent( aNewFolder );
1508 0 : return false;
1509 : }
1510 :
1511 : // Now set the target url for this group and we are done
1512 0 : OUString aPropName( TARGET_DIR_URL );
1513 0 : Any aValue = makeAny( aNewFolderURL );
1514 :
1515 0 : if ( ! setProperty( aNewGroup, aPropName, aValue ) )
1516 : {
1517 0 : removeContent( aNewGroup );
1518 0 : removeContent( aNewFolder );
1519 0 : return false;
1520 : }
1521 :
1522 0 : return true;
1523 : }
1524 :
1525 :
1526 0 : bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName )
1527 : {
1528 : // remove all the elements that have the prefix aTargetURL
1529 : // if the group does not have other elements remove it
1530 :
1531 0 : ::osl::MutexGuard aGuard( maMutex );
1532 :
1533 0 : bool bResult = false;
1534 :
1535 : // create the group url
1536 0 : INetURLObject aGroupObj( maRootURL );
1537 : aGroupObj.insertName( rGroupName, false,
1538 : INetURLObject::LAST_SEGMENT, true,
1539 0 : INetURLObject::ENCODE_ALL );
1540 :
1541 : // Get the target url
1542 0 : Content aGroup;
1543 0 : OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1544 :
1545 0 : if ( Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1546 : {
1547 0 : OUString aPropName( TARGET_DIR_URL );
1548 0 : Any aValue;
1549 :
1550 0 : OUString aGroupTargetURL;
1551 0 : if ( getProperty( aGroup, aPropName, aValue ) )
1552 0 : aValue >>= aGroupTargetURL;
1553 :
1554 0 : if ( aGroupTargetURL.isEmpty() )
1555 0 : return false; // nothing is allowed to be removed
1556 :
1557 0 : if ( !maTemplateDirs.getLength() )
1558 0 : return false;
1559 :
1560 : // check that the fs location is in writable folder and this is not a "My templates" folder
1561 0 : INetURLObject aGroupParentFolder( aGroupTargetURL );
1562 0 : if (!aGroupParentFolder.removeSegment())
1563 0 : return false;
1564 :
1565 : OUString aGeneralTempPath = findParentTemplateDir(
1566 0 : aGroupParentFolder.GetMainURL(INetURLObject::NO_DECODE));
1567 :
1568 0 : if (aGeneralTempPath.isEmpty())
1569 0 : return false;
1570 :
1571 : // now get the content of the Group
1572 0 : uno::Reference< XResultSet > xResultSet;
1573 0 : Sequence< OUString > aProps( 1 );
1574 :
1575 0 : aProps[0] = TARGET_URL;
1576 :
1577 : try
1578 : {
1579 0 : ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1580 0 : xResultSet = aGroup.createCursor( aProps, eInclude );
1581 :
1582 0 : if ( xResultSet.is() )
1583 : {
1584 0 : bool bHasNonRemovable = false;
1585 0 : bool bHasShared = false;
1586 :
1587 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1588 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1589 :
1590 0 : while ( xResultSet->next() )
1591 : {
1592 0 : OUString aTemplTargetURL( xRow->getString( 1 ) );
1593 0 : OUString aHierURL = xContentAccess->queryContentIdentifierString();
1594 :
1595 0 : if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1596 : {
1597 : // this is a user template, and it can be removed
1598 0 : if ( removeContent( aTemplTargetURL ) )
1599 0 : removeContent( aHierURL );
1600 : else
1601 0 : bHasNonRemovable = true;
1602 : }
1603 : else
1604 0 : bHasShared = true;
1605 0 : }
1606 :
1607 0 : if ( !bHasNonRemovable && !bHasShared )
1608 : {
1609 0 : if ( removeContent( aGroupTargetURL )
1610 0 : || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1611 : {
1612 0 : removeContent( aGroupURL );
1613 0 : RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1614 0 : bResult = true; // the operation is successful only if the whole group is removed
1615 : }
1616 : }
1617 0 : else if ( !bHasNonRemovable )
1618 : {
1619 0 : if ( removeContent( aGroupTargetURL )
1620 0 : || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) )
1621 : {
1622 0 : RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName );
1623 0 : setProperty( aGroup, aPropName, uno::makeAny( OUString() ) );
1624 : }
1625 0 : }
1626 : }
1627 : }
1628 0 : catch ( Exception& ) {}
1629 : }
1630 :
1631 0 : return bResult;
1632 : }
1633 :
1634 :
1635 0 : bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName,
1636 : const OUString& rNewName )
1637 : {
1638 0 : ::osl::MutexGuard aGuard( maMutex );
1639 :
1640 : // create the group url
1641 0 : Content aGroup;
1642 0 : INetURLObject aGroupObj( maRootURL );
1643 : aGroupObj.insertName( rNewName, false,
1644 : INetURLObject::LAST_SEGMENT, true,
1645 0 : INetURLObject::ENCODE_ALL );
1646 0 : OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1647 :
1648 : // Check, if there is a group with the new name, return false
1649 : // if there is one.
1650 0 : if ( Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1651 0 : return false;
1652 :
1653 0 : aGroupObj.removeSegment();
1654 : aGroupObj.insertName( rOldName, false,
1655 : INetURLObject::LAST_SEGMENT, true,
1656 0 : INetURLObject::ENCODE_ALL );
1657 0 : aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1658 :
1659 : // When there is no group with the old name, we can't rename it
1660 0 : if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1661 0 : return false;
1662 :
1663 0 : OUString aGroupTargetURL;
1664 : // there is no need to check whether target dir url is in target path, since if the target path is changed
1665 : // the target dir url should be already generated new
1666 0 : OUString aPropName( TARGET_DIR_URL );
1667 0 : Any aValue;
1668 0 : if ( getProperty( aGroup, aPropName, aValue ) )
1669 0 : aValue >>= aGroupTargetURL;
1670 :
1671 0 : if ( aGroupTargetURL.isEmpty() )
1672 0 : return false;
1673 :
1674 0 : if ( !maTemplateDirs.getLength() )
1675 0 : return false;
1676 :
1677 : // check that the fs location is in writable folder and this is not a "My templates" folder
1678 0 : INetURLObject aGroupParentFolder( aGroupTargetURL );
1679 0 : if (!aGroupParentFolder.removeSegment() ||
1680 0 : isInternalTemplateDir(aGroupParentFolder.GetMainURL(INetURLObject::NO_DECODE)))
1681 : {
1682 0 : return false;
1683 : }
1684 :
1685 : // check that the group can be renamed ( all the contents must be in target location )
1686 0 : bool bCanBeRenamed = false;
1687 : try
1688 : {
1689 0 : uno::Reference< XResultSet > xResultSet;
1690 0 : Sequence< OUString > aProps( 1 );
1691 :
1692 0 : aProps[0] = TARGET_URL;
1693 0 : ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
1694 0 : xResultSet = aGroup.createCursor( aProps, eInclude );
1695 :
1696 0 : if ( xResultSet.is() )
1697 : {
1698 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
1699 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
1700 :
1701 0 : while ( xResultSet->next() )
1702 : {
1703 0 : OUString aTemplTargetURL( xRow->getString( 1 ) );
1704 :
1705 0 : if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) )
1706 0 : throw uno::Exception();
1707 0 : }
1708 :
1709 0 : bCanBeRenamed = true;
1710 0 : }
1711 : }
1712 0 : catch ( Exception& ) {}
1713 :
1714 0 : if ( bCanBeRenamed )
1715 : {
1716 0 : INetURLObject aGroupTargetObj( aGroupTargetURL );
1717 0 : OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1718 :
1719 0 : if ( aGroupTargetObj.removeSegment()
1720 0 : && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ),
1721 : aFsysName,
1722 : rOldName,
1723 0 : rNewName ) )
1724 : {
1725 : // rename the group in the hierarchy
1726 0 : OUString aTitleProp( TITLE );
1727 0 : Any aTitleValue;
1728 0 : aTitleValue <<= rNewName;
1729 :
1730 0 : return setProperty( aGroup, aTitleProp, aTitleValue );
1731 0 : }
1732 : }
1733 :
1734 0 : return false;
1735 : }
1736 :
1737 :
1738 0 : bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName,
1739 : const OUString& rTemplateName,
1740 : const uno::Reference< frame::XStorable >& rStorable )
1741 : {
1742 0 : ::osl::MutexGuard aGuard( maMutex );
1743 :
1744 : // Check, whether or not there is a group with this name
1745 : // Return false, if there is no group with the given name
1746 0 : Content aGroup, aTemplate, aTargetGroup, aTemplateToRemove;
1747 0 : OUString aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL;
1748 0 : INetURLObject aGroupObj( maRootURL );
1749 0 : bool bRemoveOldTemplateContent = false;
1750 0 : OUString sDocServiceName;
1751 :
1752 : aGroupObj.insertName( rGroupName, false,
1753 : INetURLObject::LAST_SEGMENT, true,
1754 0 : INetURLObject::ENCODE_ALL );
1755 0 : aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1756 :
1757 0 : if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1758 0 : return false;
1759 :
1760 0 : OUString aGroupTargetURL;
1761 0 : OUString aPropName( TARGET_DIR_URL );
1762 0 : Any aValue;
1763 0 : if ( getProperty( aGroup, aPropName, aValue ) )
1764 0 : aValue >>= aGroupTargetURL;
1765 :
1766 :
1767 : // Check, if there's a template with the given name in this group
1768 : // the target template should be overwritten if it is imported by user
1769 : // in case the template is installed by office installation of by an add-in
1770 : // it can not be replaced
1771 : aGroupObj.insertName( rTemplateName, false,
1772 : INetURLObject::LAST_SEGMENT, true,
1773 0 : INetURLObject::ENCODE_ALL );
1774 0 : aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1775 :
1776 0 : if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplateToRemove ) )
1777 : {
1778 0 : OUString aTargetTemplPropName( TARGET_URL );
1779 :
1780 0 : bRemoveOldTemplateContent = true;
1781 0 : if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) )
1782 0 : aValue >>= aTemplateToRemoveTargetURL;
1783 :
1784 0 : if ( aGroupTargetURL.isEmpty() || !maTemplateDirs.getLength()
1785 0 : || (!aTemplateToRemoveTargetURL.isEmpty() && isInternalTemplateDir(aTemplateToRemoveTargetURL)) )
1786 0 : return false; // it is not allowed to remove the template
1787 : }
1788 :
1789 : try
1790 : {
1791 0 : uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1792 :
1793 : // get document service name
1794 0 : uno::Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) );
1795 0 : sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) );
1796 0 : if ( sDocServiceName.isEmpty() )
1797 0 : throw uno::RuntimeException();
1798 :
1799 : // get the actual filter name
1800 0 : OUString aFilterName;
1801 :
1802 : uno::Reference< lang::XMultiServiceFactory > xConfigProvider =
1803 0 : configuration::theDefaultProvider::get( xContext );
1804 :
1805 0 : uno::Sequence< uno::Any > aArgs( 1 );
1806 0 : beans::PropertyValue aPathProp;
1807 0 : aPathProp.Name = "nodepath";
1808 0 : aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" );
1809 0 : aArgs[0] <<= aPathProp;
1810 :
1811 : uno::Reference< container::XNameAccess > xSOFConfig(
1812 0 : xConfigProvider->createInstanceWithArguments(
1813 : OUString("com.sun.star.configuration.ConfigurationAccess"),
1814 0 : aArgs ),
1815 0 : uno::UNO_QUERY_THROW );
1816 :
1817 0 : uno::Reference< container::XNameAccess > xApplConfig;
1818 0 : xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig;
1819 0 : if ( !xApplConfig.is() )
1820 0 : throw uno::RuntimeException();
1821 :
1822 0 : xApplConfig->getByName("ooSetupFactoryActualTemplateFilter") >>= aFilterName;
1823 0 : if ( aFilterName.isEmpty() )
1824 0 : throw uno::RuntimeException();
1825 :
1826 : // find the related type name
1827 0 : OUString aTypeName;
1828 : uno::Reference< container::XNameAccess > xFilterFactory(
1829 0 : mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", mxContext),
1830 0 : uno::UNO_QUERY_THROW );
1831 :
1832 0 : uno::Sequence< beans::PropertyValue > aFilterData;
1833 0 : xFilterFactory->getByName( aFilterName ) >>= aFilterData;
1834 0 : for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
1835 0 : if ( aFilterData[nInd].Name == "Type" )
1836 0 : aFilterData[nInd].Value >>= aTypeName;
1837 :
1838 0 : if ( aTypeName.isEmpty() )
1839 0 : throw uno::RuntimeException();
1840 :
1841 : // find the mediatype and extension
1842 0 : uno::Reference< container::XNameAccess > xTypeDetection;
1843 :
1844 0 : xTypeDetection =
1845 0 : mxType.is() ?
1846 : uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) :
1847 : uno::Reference< container::XNameAccess >(
1848 0 : mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", mxContext),
1849 0 : uno::UNO_QUERY_THROW );
1850 :
1851 0 : SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) );
1852 : uno::Sequence< OUString > aAllExt =
1853 0 : aTypeProps.getUnpackedValueOrDefault("Extensions", Sequence< OUString >() );
1854 0 : if ( !aAllExt.getLength() )
1855 0 : throw uno::RuntimeException();
1856 :
1857 0 : OUString aMediaType = aTypeProps.getUnpackedValueOrDefault("MediaType", OUString() );
1858 0 : OUString aExt = aAllExt[0];
1859 :
1860 0 : if ( aMediaType.isEmpty() || aExt.isEmpty() )
1861 0 : throw uno::RuntimeException();
1862 :
1863 : // construct destination url
1864 0 : if ( aGroupTargetURL.isEmpty() )
1865 : {
1866 0 : aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1867 :
1868 0 : if ( aGroupTargetURL.isEmpty() )
1869 0 : throw uno::RuntimeException();
1870 : }
1871 :
1872 0 : OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt );
1873 0 : if ( aNewTemplateTargetURL.isEmpty() )
1874 : {
1875 0 : aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, OUString( "UserTemplate" ), aExt );
1876 :
1877 0 : if ( aNewTemplateTargetURL.isEmpty() )
1878 0 : throw uno::RuntimeException();
1879 : }
1880 :
1881 : // store template
1882 0 : uno::Sequence< PropertyValue > aStoreArgs( 2 );
1883 0 : aStoreArgs[0].Name = "FilterName";
1884 0 : aStoreArgs[0].Value <<= aFilterName;
1885 0 : aStoreArgs[1].Name = "DocumentTitle";
1886 0 : aStoreArgs[1].Value <<= rTemplateName;
1887 :
1888 0 : if( !::utl::UCBContentHelper::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() ))
1889 0 : rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs );
1890 : else
1891 0 : rStorable->store();
1892 :
1893 : // the storing was successful, now the old template with the same name can be removed if it existed
1894 0 : if ( !aTemplateToRemoveTargetURL.isEmpty() )
1895 : {
1896 0 : removeContent( aTemplateToRemoveTargetURL );
1897 :
1898 : /*
1899 : * pb: #i79496#
1900 : * if the old template was the standard template
1901 : * it is necessary to change the standard template with the new file name
1902 : */
1903 0 : OUString sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName );
1904 0 : if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) )
1905 : {
1906 0 : SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL );
1907 0 : }
1908 : }
1909 :
1910 0 : if ( bRemoveOldTemplateContent )
1911 0 : removeContent( aTemplateToRemove );
1912 :
1913 : // add the template to hierarchy
1914 0 : return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType );
1915 : }
1916 0 : catch( Exception& )
1917 : {
1918 : // the template was not stored
1919 0 : return false;
1920 0 : }
1921 : }
1922 :
1923 :
1924 0 : bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName,
1925 : const OUString& rTemplateName,
1926 : const OUString& rSourceURL )
1927 : {
1928 0 : ::osl::MutexGuard aGuard( maMutex );
1929 :
1930 : // Check, whether or not there is a group with this name
1931 : // Return false, if there is no group with the given name
1932 0 : Content aGroup, aTemplate, aTargetGroup;
1933 0 : OUString aGroupURL, aTemplateURL;
1934 0 : INetURLObject aGroupObj( maRootURL );
1935 :
1936 : aGroupObj.insertName( rGroupName, false,
1937 : INetURLObject::LAST_SEGMENT, true,
1938 0 : INetURLObject::ENCODE_ALL );
1939 0 : aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1940 :
1941 0 : if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
1942 0 : return false;
1943 :
1944 : // Check, if there's a template with the given name in this group
1945 : // Return false, if there already is a template
1946 : aGroupObj.insertName( rTemplateName, false,
1947 : INetURLObject::LAST_SEGMENT, true,
1948 0 : INetURLObject::ENCODE_ALL );
1949 0 : aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
1950 :
1951 0 : if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
1952 0 : return false;
1953 :
1954 : // get the target url of the group
1955 0 : OUString aTargetURL;
1956 0 : OUString aPropName( TARGET_DIR_URL );
1957 0 : Any aValue;
1958 :
1959 0 : if ( getProperty( aGroup, aPropName, aValue ) )
1960 0 : aValue >>= aTargetURL;
1961 :
1962 0 : if ( aTargetURL.isEmpty() )
1963 : {
1964 0 : aTargetURL = CreateNewGroupFsys( rGroupName, aGroup );
1965 :
1966 0 : if ( aTargetURL.isEmpty() )
1967 0 : return false;
1968 : }
1969 :
1970 : // Get the content type
1971 0 : OUString aTitle, aType, aTargetURL2;
1972 :
1973 0 : bool bDocHasTitle = false;
1974 0 : if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) )
1975 0 : return false;
1976 :
1977 0 : INetURLObject aSourceObj( rSourceURL );
1978 0 : if ( rTemplateName.equals( aTitle ) )
1979 : {
1980 : // addTemplate will sometimes be called just to add an entry in the
1981 : // hierarchy; the target URL and the source URL will be the same in
1982 : // this scenario
1983 : // TODO/LATER: get rid of this old hack
1984 :
1985 0 : INetURLObject aTargetObj( aTargetURL );
1986 :
1987 : aTargetObj.insertName( rTemplateName, false,
1988 : INetURLObject::LAST_SEGMENT, true,
1989 0 : INetURLObject::ENCODE_ALL );
1990 0 : aTargetObj.setExtension( aSourceObj.getExtension() );
1991 :
1992 0 : aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE );
1993 :
1994 0 : if ( aTargetURL2 == rSourceURL )
1995 0 : return addEntry( aGroup, rTemplateName, aTargetURL2, aType );
1996 : }
1997 :
1998 : // copy the template into the new group (targeturl)
1999 :
2000 0 : INetURLObject aTmpURL( aSourceObj );
2001 0 : aTmpURL.CutExtension();
2002 0 : OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2003 :
2004 0 : OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() );
2005 0 : INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL );
2006 0 : OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2007 0 : if ( aNewTemplateTargetURL.isEmpty() || aNewTemplateTargetName.isEmpty() )
2008 0 : return false;
2009 :
2010 : // get access to source file
2011 0 : Content aSourceContent;
2012 0 : uno::Reference < ucb::XCommandEnvironment > xEnv;
2013 0 : INetURLObject aSourceURL( rSourceURL );
2014 0 : if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent ) )
2015 0 : return false;
2016 :
2017 0 : if( ! Content::create( aTargetURL, xEnv, comphelper::getProcessComponentContext(), aTargetGroup ) )
2018 0 : return false;
2019 :
2020 : // transfer source file
2021 : try
2022 : {
2023 0 : if( ! aTargetGroup.transferContent( aSourceContent,
2024 : InsertOperation_COPY,
2025 : aNewTemplateTargetName,
2026 : NameClash::OVERWRITE,
2027 0 : aType ) )
2028 0 : return false;
2029 :
2030 : // allow to edit the added template
2031 0 : Content aResultContent;
2032 0 : if ( Content::create( aNewTemplateTargetURL, xEnv, comphelper::getProcessComponentContext(), aResultContent ) )
2033 : {
2034 0 : OUString aPropertyName( "IsReadOnly" );
2035 0 : uno::Any aProperty;
2036 0 : bool bReadOnly = false;
2037 0 : if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly )
2038 0 : setProperty( aResultContent, aPropertyName, uno::makeAny( false ) );
2039 0 : }
2040 : }
2041 0 : catch ( ContentCreationException& )
2042 0 : { return false; }
2043 0 : catch ( Exception& )
2044 0 : { return false; }
2045 :
2046 :
2047 : // either the document has title and it is the same as requested, or we have to set it
2048 0 : bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) );
2049 0 : if ( !bCorrectTitle )
2050 : {
2051 0 : if ( !bDocHasTitle )
2052 : {
2053 0 : INetURLObject aNewTmpObj( aNewTemplateTargetObj );
2054 0 : aNewTmpObj.CutExtension();
2055 0 : bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) );
2056 : }
2057 :
2058 0 : if ( !bCorrectTitle )
2059 0 : bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName );
2060 : }
2061 :
2062 0 : if ( bCorrectTitle )
2063 : {
2064 : // create a new entry in the hierarchy
2065 0 : return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType );
2066 : }
2067 :
2068 : // TODO/LATER: The user could be notified here that the renaming has failed
2069 : // create a new entry in the hierarchy
2070 0 : addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType );
2071 0 : return false;
2072 : }
2073 :
2074 0 : bool SfxDocTplService_Impl::isInternalTemplateDir(const OUString& rURL) const
2075 : {
2076 0 : const sal_Int32 nDirs = maInternalTemplateDirs.getLength();
2077 0 : const OUString* pDirs = maInternalTemplateDirs.getConstArray();
2078 0 : for (sal_Int32 i = 0; i < nDirs; ++i, ++pDirs)
2079 : {
2080 0 : if (::utl::UCBContentHelper::IsSubPath(*pDirs, rURL))
2081 0 : return true;
2082 : }
2083 0 : return false;
2084 : }
2085 :
2086 0 : OUString SfxDocTplService_Impl::findParentTemplateDir(const OUString& rURL) const
2087 : {
2088 0 : const sal_Int32 nDirs = maTemplateDirs.getLength();
2089 0 : const OUString* pDirs = maTemplateDirs.getConstArray();
2090 0 : for (sal_Int32 i = 0; i < nDirs; ++i, ++pDirs)
2091 : {
2092 0 : if (::utl::UCBContentHelper::IsSubPath(*pDirs, rURL))
2093 0 : return *pDirs;
2094 : }
2095 0 : return OUString();
2096 : }
2097 :
2098 0 : bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName,
2099 : const OUString& rTemplateName )
2100 : {
2101 0 : ::osl::MutexGuard aGuard( maMutex );
2102 :
2103 : // Check, whether or not there is a group with this name
2104 : // Return false, if there is no group with the given name
2105 0 : Content aGroup, aTemplate;
2106 0 : OUString aGroupURL, aTemplateURL;
2107 0 : INetURLObject aGroupObj( maRootURL );
2108 :
2109 : aGroupObj.insertName( rGroupName, false,
2110 : INetURLObject::LAST_SEGMENT, true,
2111 0 : INetURLObject::ENCODE_ALL );
2112 0 : aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2113 :
2114 0 : if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2115 0 : return false;
2116 :
2117 : // Check, if there's a template with the given name in this group
2118 : // Return false, if there is no template
2119 : aGroupObj.insertName( rTemplateName, false,
2120 : INetURLObject::LAST_SEGMENT, true,
2121 0 : INetURLObject::ENCODE_ALL );
2122 0 : aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2123 :
2124 0 : if ( !Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2125 0 : return false;
2126 :
2127 : // get the target URL from the template
2128 0 : OUString aTargetURL;
2129 0 : OUString aPropName( TARGET_URL );
2130 0 : Any aValue;
2131 :
2132 0 : if ( getProperty( aTemplate, aPropName, aValue ) )
2133 0 : aValue >>= aTargetURL;
2134 :
2135 : // delete the target template
2136 0 : if ( !aTargetURL.isEmpty() )
2137 : {
2138 0 : if (isInternalTemplateDir(aTargetURL))
2139 0 : return false;
2140 :
2141 0 : removeContent( aTargetURL );
2142 : }
2143 :
2144 : // delete the template entry
2145 0 : return removeContent( aTemplate );
2146 : }
2147 :
2148 :
2149 0 : bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName,
2150 : const OUString& rOldName,
2151 : const OUString& rNewName )
2152 : {
2153 0 : ::osl::MutexGuard aGuard( maMutex );
2154 :
2155 : // Check, whether or not there is a group with this name
2156 : // Return false, if there is no group with the given name
2157 0 : Content aGroup, aTemplate;
2158 0 : OUString aGroupURL, aTemplateURL;
2159 0 : INetURLObject aGroupObj( maRootURL );
2160 :
2161 : aGroupObj.insertName( rGroupName, false,
2162 : INetURLObject::LAST_SEGMENT, true,
2163 0 : INetURLObject::ENCODE_ALL );
2164 0 : aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2165 :
2166 0 : if ( ! Content::create( aGroupURL, maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2167 0 : return false;
2168 :
2169 : // Check, if there's a template with the new name in this group
2170 : // Return false, if there is one
2171 : aGroupObj.insertName( rNewName, false,
2172 : INetURLObject::LAST_SEGMENT, true,
2173 0 : INetURLObject::ENCODE_ALL );
2174 0 : aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2175 :
2176 0 : if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2177 0 : return false;
2178 :
2179 : // Check, if there's a template with the old name in this group
2180 : // Return false, if there is no template
2181 0 : aGroupObj.removeSegment();
2182 : aGroupObj.insertName( rOldName, false,
2183 : INetURLObject::LAST_SEGMENT, true,
2184 0 : INetURLObject::ENCODE_ALL );
2185 0 : aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2186 :
2187 0 : if ( !Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2188 0 : return false;
2189 :
2190 0 : OUString aTemplateTargetURL;
2191 0 : OUString aTargetProp( TARGET_URL );
2192 0 : Any aTargetValue;
2193 :
2194 0 : if ( getProperty( aTemplate, aTargetProp, aTargetValue ) )
2195 0 : aTargetValue >>= aTemplateTargetURL;
2196 :
2197 0 : if ( !setTitleForURL( aTemplateTargetURL, rNewName ) )
2198 0 : return false;
2199 :
2200 : // rename the template entry in the cache
2201 0 : OUString aTitleProp( TITLE );
2202 0 : Any aTitleValue;
2203 0 : aTitleValue <<= rNewName;
2204 :
2205 0 : return setProperty( aTemplate, aTitleProp, aTitleValue );
2206 : }
2207 :
2208 :
2209 : class SfxDocTplService: public ::cppu::WeakImplHelper3< css::lang::XLocalizable, css::frame::XDocumentTemplates, css::lang::XServiceInfo >
2210 : {
2211 : SfxDocTplService_Impl *pImp;
2212 :
2213 : public:
2214 : SfxDocTplService( const css::uno::Reference < uno::XComponentContext >& xContext );
2215 : virtual ~SfxDocTplService();
2216 :
2217 1 : virtual OUString SAL_CALL getImplementationName()
2218 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
2219 : {
2220 1 : return OUString("com.sun.star.comp.sfx2.DocumentTemplates");
2221 : }
2222 :
2223 0 : virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
2224 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
2225 : {
2226 0 : return cppu::supportsService(this, ServiceName);
2227 : }
2228 :
2229 1 : virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
2230 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
2231 : {
2232 1 : css::uno::Sequence< OUString > aSeq(1);
2233 1 : aSeq[0] = "com.sun.star.frame.DocumentTemplates";
2234 1 : return aSeq;
2235 : }
2236 :
2237 :
2238 : // --- XLocalizable ---
2239 : void SAL_CALL setLocale( const css::lang::Locale & eLocale ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2240 : css::lang::Locale SAL_CALL getLocale() throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2241 :
2242 : // --- XDocumentTemplates ---
2243 : css::uno::Reference< css::ucb::XContent > SAL_CALL getContent() throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2244 : sal_Bool SAL_CALL storeTemplate( const OUString& GroupName,
2245 : const OUString& TemplateName,
2246 : const css::uno::Reference< css::frame::XStorable >& Storable ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2247 : sal_Bool SAL_CALL addTemplate( const OUString& GroupName,
2248 : const OUString& TemplateName,
2249 : const OUString& SourceURL ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2250 : sal_Bool SAL_CALL removeTemplate( const OUString& GroupName,
2251 : const OUString& TemplateName ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2252 : sal_Bool SAL_CALL renameTemplate( const OUString& GroupName,
2253 : const OUString& OldTemplateName,
2254 : const OUString& NewTemplateName ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2255 : sal_Bool SAL_CALL addGroup( const OUString& GroupName ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2256 : sal_Bool SAL_CALL removeGroup( const OUString& GroupName ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2257 : sal_Bool SAL_CALL renameGroup( const OUString& OldGroupName,
2258 : const OUString& NewGroupName ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2259 : void SAL_CALL update() throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
2260 : };
2261 :
2262 :
2263 40 : SfxDocTplService::SfxDocTplService( const uno::Reference< XComponentContext >& xContext )
2264 : {
2265 40 : pImp = new SfxDocTplService_Impl(xContext);
2266 40 : }
2267 :
2268 :
2269 :
2270 111 : SfxDocTplService::~SfxDocTplService()
2271 : {
2272 37 : delete pImp;
2273 74 : }
2274 :
2275 :
2276 : //--- XLocalizable ---
2277 :
2278 :
2279 39 : lang::Locale SAL_CALL SfxDocTplService::getLocale()
2280 : throw( uno::RuntimeException, std::exception )
2281 : {
2282 39 : return pImp->getLocale();
2283 : }
2284 :
2285 :
2286 :
2287 0 : void SAL_CALL SfxDocTplService::setLocale( const lang::Locale & rLocale )
2288 : throw( uno::RuntimeException, std::exception )
2289 : {
2290 0 : pImp->setLocale( rLocale );
2291 0 : }
2292 :
2293 :
2294 : //--- XDocumentTemplates ---
2295 :
2296 40 : uno::Reference< ucb::XContent > SAL_CALL SfxDocTplService::getContent()
2297 : throw( uno::RuntimeException, std::exception )
2298 : {
2299 40 : if ( pImp->init() )
2300 0 : return pImp->getContent().get();
2301 : else
2302 40 : return NULL;
2303 : }
2304 :
2305 :
2306 0 : sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName,
2307 : const OUString& TemplateName,
2308 : const uno::Reference< frame::XStorable >& Storable )
2309 : throw( uno::RuntimeException, std::exception )
2310 : {
2311 0 : if ( pImp->init() )
2312 0 : return pImp->storeTemplate( GroupName, TemplateName, Storable );
2313 : else
2314 0 : return sal_False;
2315 : }
2316 :
2317 :
2318 0 : sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName,
2319 : const OUString& rTemplateName,
2320 : const OUString& rSourceURL )
2321 : throw( uno::RuntimeException, std::exception )
2322 : {
2323 0 : if ( pImp->init() )
2324 0 : return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL );
2325 : else
2326 0 : return sal_False;
2327 : }
2328 :
2329 :
2330 0 : sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName,
2331 : const OUString& rTemplateName )
2332 : throw( uno::RuntimeException, std::exception )
2333 : {
2334 0 : if ( pImp->init() )
2335 0 : return pImp->removeTemplate( rGroupName, rTemplateName );
2336 : else
2337 0 : return sal_False;
2338 : }
2339 :
2340 :
2341 0 : sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName,
2342 : const OUString& rOldName,
2343 : const OUString& rNewName )
2344 : throw( uno::RuntimeException, std::exception )
2345 : {
2346 0 : if ( rOldName == rNewName )
2347 0 : return sal_True;
2348 :
2349 0 : if ( pImp->init() )
2350 0 : return pImp->renameTemplate( rGroupName, rOldName, rNewName );
2351 : else
2352 0 : return sal_False;
2353 : }
2354 :
2355 :
2356 0 : sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName )
2357 : throw( uno::RuntimeException, std::exception )
2358 : {
2359 0 : if ( pImp->init() )
2360 0 : return pImp->addGroup( rGroupName );
2361 : else
2362 0 : return sal_False;
2363 : }
2364 :
2365 :
2366 0 : sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName )
2367 : throw( uno::RuntimeException, std::exception )
2368 : {
2369 0 : if ( pImp->init() )
2370 0 : return pImp->removeGroup( rGroupName );
2371 : else
2372 0 : return sal_False;
2373 : }
2374 :
2375 :
2376 0 : sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName,
2377 : const OUString& rNewName )
2378 : throw( uno::RuntimeException, std::exception )
2379 : {
2380 0 : if ( rOldName == rNewName )
2381 0 : return sal_True;
2382 :
2383 0 : if ( pImp->init() )
2384 0 : return pImp->renameGroup( rOldName, rNewName );
2385 : else
2386 0 : return sal_False;
2387 : }
2388 :
2389 :
2390 0 : void SAL_CALL SfxDocTplService::update()
2391 : throw( uno::RuntimeException, std::exception )
2392 : {
2393 0 : if ( pImp->init() )
2394 0 : pImp->update( true );
2395 0 : }
2396 :
2397 :
2398 :
2399 0 : Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates )
2400 : {
2401 0 : mpDocTemplates = pTemplates;
2402 0 : }
2403 :
2404 :
2405 0 : Updater_Impl::~Updater_Impl()
2406 : {
2407 0 : }
2408 :
2409 :
2410 0 : void SAL_CALL Updater_Impl::run()
2411 : {
2412 0 : osl_setThreadName("Updater_Impl");
2413 :
2414 0 : mpDocTemplates->doUpdate();
2415 0 : }
2416 :
2417 :
2418 0 : void SAL_CALL Updater_Impl::onTerminated()
2419 : {
2420 0 : mpDocTemplates->finished();
2421 0 : delete this;
2422 0 : }
2423 :
2424 :
2425 0 : WaitWindow_Impl::WaitWindow_Impl() : WorkWindow(NULL, WB_BORDER | WB_3DLOOK)
2426 : {
2427 0 : Rectangle aRect = Rectangle(0, 0, 300, 30000);
2428 0 : mnTextStyle = DrawTextFlags::Center | DrawTextFlags::VCenter | DrawTextFlags::WordBreak | DrawTextFlags::MultiLine;
2429 0 : maText = SfxResId(RID_CNT_STR_WAITING).toString();
2430 0 : maRect = GetTextRect(aRect, maText, mnTextStyle);
2431 0 : aRect = maRect;
2432 0 : aRect.Right() += 2 * X_OFFSET;
2433 0 : aRect.Bottom() += 2 * Y_OFFSET;
2434 0 : maRect.SetPos(Point(X_OFFSET, Y_OFFSET));
2435 0 : SetOutputSizePixel(aRect.GetSize());
2436 :
2437 0 : Show();
2438 0 : Update();
2439 0 : Flush();
2440 0 : }
2441 :
2442 :
2443 0 : WaitWindow_Impl::~WaitWindow_Impl()
2444 : {
2445 0 : disposeOnce();
2446 0 : }
2447 :
2448 0 : void WaitWindow_Impl::dispose()
2449 : {
2450 0 : Hide();
2451 0 : WorkWindow::dispose();
2452 0 : }
2453 :
2454 :
2455 0 : void WaitWindow_Impl::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rRect*/)
2456 : {
2457 0 : rRenderContext.DrawText(maRect, maText, mnTextStyle);
2458 0 : }
2459 :
2460 0 : void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList,
2461 : const OUString& rTitle,
2462 : const OUString& rOwnURL )
2463 : {
2464 : // now get the content of the Group
2465 0 : Content aContent;
2466 0 : uno::Reference<XResultSet> xResultSet;
2467 0 : Sequence<OUString> aProps(3);
2468 :
2469 0 : aProps[0] = TITLE;
2470 0 : aProps[1] = TARGET_URL;
2471 0 : aProps[2] = PROPERTY_TYPE;
2472 :
2473 : try
2474 : {
2475 0 : aContent = Content(rOwnURL, maCmdEnv, comphelper::getProcessComponentContext());
2476 0 : ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2477 0 : xResultSet = aContent.createCursor( aProps, eInclude );
2478 : }
2479 0 : catch (ContentCreationException&)
2480 : {
2481 : SAL_WARN( "sfx.doc", "addHierGroup: ContentCreationException" );
2482 : }
2483 0 : catch (Exception&) {}
2484 :
2485 0 : if ( xResultSet.is() )
2486 : {
2487 0 : GroupData_Impl *pGroup = new GroupData_Impl( rTitle );
2488 0 : pGroup->setHierarchy( true );
2489 0 : pGroup->setHierarchyURL( rOwnURL );
2490 0 : rList.push_back( pGroup );
2491 :
2492 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2493 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2494 :
2495 : try
2496 : {
2497 0 : while ( xResultSet->next() )
2498 : {
2499 0 : bool bUpdateType = false;
2500 : DocTemplates_EntryData_Impl *pData;
2501 :
2502 0 : OUString aTitle( xRow->getString( 1 ) );
2503 0 : OUString aTargetDir( xRow->getString( 2 ) );
2504 0 : OUString aType( xRow->getString( 3 ) );
2505 0 : OUString aHierURL = xContentAccess->queryContentIdentifierString();
2506 :
2507 0 : if ( aType.isEmpty() )
2508 : {
2509 0 : OUString aTmpTitle;
2510 :
2511 0 : bool bDocHasTitle = false;
2512 0 : if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) )
2513 : {
2514 : SAL_WARN( "sfx.doc", "addHierGroup(): template of alien format" );
2515 0 : continue;
2516 : }
2517 :
2518 0 : if ( !aType.isEmpty() )
2519 0 : bUpdateType = true;
2520 : }
2521 :
2522 0 : pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL );
2523 0 : pData->setUpdateType( bUpdateType );
2524 0 : }
2525 : }
2526 0 : catch ( Exception& ) {}
2527 0 : }
2528 0 : }
2529 :
2530 :
2531 0 : void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList,
2532 : const OUString& rTitle,
2533 : const OUString& rUITitle,
2534 : const OUString& rOwnURL,
2535 : bool bWriteableGroup )
2536 : {
2537 0 : OUString aTitle;
2538 :
2539 0 : if ( rUITitle.isEmpty() )
2540 : {
2541 : // reserved FS names that should not be used
2542 0 : if ( rTitle == "wizard" )
2543 0 : return;
2544 0 : else if ( rTitle == "internal" )
2545 0 : return;
2546 :
2547 0 : aTitle = getLongName( rTitle );
2548 : }
2549 : else
2550 0 : aTitle = rUITitle;
2551 :
2552 0 : if ( aTitle.isEmpty() )
2553 0 : return;
2554 :
2555 0 : GroupData_Impl* pGroup = NULL;
2556 0 : for ( size_t i = 0, n = rList.size(); i < n; ++i )
2557 : {
2558 0 : if ( rList[ i ]->getTitle() == aTitle )
2559 : {
2560 0 : pGroup = rList[ i ];
2561 0 : break;
2562 : }
2563 : }
2564 :
2565 0 : if ( !pGroup )
2566 : {
2567 0 : pGroup = new GroupData_Impl( aTitle );
2568 0 : rList.push_back( pGroup );
2569 : }
2570 :
2571 0 : if ( bWriteableGroup )
2572 0 : pGroup->setTargetURL( rOwnURL );
2573 :
2574 0 : pGroup->setInUse();
2575 :
2576 : // now get the content of the Group
2577 0 : Content aContent;
2578 0 : uno::Reference< XResultSet > xResultSet;
2579 0 : Sequence< OUString > aProps(1);
2580 0 : aProps[0] = TITLE;
2581 :
2582 : try
2583 : {
2584 : // this method is only used during checking of the available template-folders
2585 : // that should happen quietly
2586 0 : uno::Reference< XCommandEnvironment > aQuietEnv;
2587 0 : aContent = Content( rOwnURL, aQuietEnv, comphelper::getProcessComponentContext() );
2588 0 : ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
2589 0 : xResultSet = aContent.createCursor( aProps, eInclude );
2590 : }
2591 0 : catch ( Exception& ) {}
2592 :
2593 0 : if ( xResultSet.is() )
2594 : {
2595 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2596 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2597 :
2598 : try
2599 : {
2600 0 : while ( xResultSet->next() )
2601 : {
2602 0 : OUString aChildTitle( xRow->getString( 1 ) );
2603 0 : OUString aTargetURL = xContentAccess->queryContentIdentifierString();
2604 0 : OUString aType;
2605 0 : OUString aHierURL;
2606 :
2607 0 : if ( aChildTitle == "sfx.tlx" || aChildTitle == "groupuinames.xml" )
2608 0 : continue;
2609 :
2610 0 : bool bDocHasTitle = false;
2611 0 : if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) )
2612 0 : continue;
2613 :
2614 0 : pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL );
2615 0 : }
2616 : }
2617 0 : catch ( Exception& ) {}
2618 0 : }
2619 : }
2620 :
2621 :
2622 0 : void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList,
2623 : Content &rContent,
2624 : bool bHierarchy,
2625 : bool bWriteableContent )
2626 : {
2627 0 : OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier();
2628 :
2629 : // when scanning the file system, we have to add the 'standard' group, too
2630 0 : if ( ! bHierarchy )
2631 : {
2632 0 : OUString aUIStdTitle = getLongName( OUString( STANDARD_FOLDER ) );
2633 0 : addFsysGroup( rList, OUString(), aUIStdTitle, aTargetURL, bWriteableContent );
2634 : }
2635 :
2636 : // search for predefined UI names
2637 0 : INetURLObject aLayerObj( aTargetURL );
2638 :
2639 : // TODO/LATER: Use hashmap in future
2640 0 : uno::Sequence< beans::StringPair > aUINames;
2641 0 : if ( !bHierarchy )
2642 0 : aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) );
2643 :
2644 0 : uno::Reference< XResultSet > xResultSet;
2645 0 : Sequence< OUString > aProps(1);
2646 0 : aProps[0] = TITLE;
2647 :
2648 : try
2649 : {
2650 0 : ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
2651 0 : xResultSet = rContent.createCursor( aProps, eInclude );
2652 : }
2653 0 : catch ( Exception& ) {}
2654 :
2655 0 : if ( xResultSet.is() )
2656 : {
2657 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2658 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
2659 :
2660 : try
2661 : {
2662 0 : while ( xResultSet->next() )
2663 : {
2664 : // TODO/LATER: clarify the encoding of the Title
2665 0 : OUString aTitle( xRow->getString( 1 ) );
2666 0 : OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() );
2667 :
2668 0 : if ( bHierarchy )
2669 0 : addHierGroup( rList, aTitle, aTargetSubfolderURL );
2670 : else
2671 : {
2672 0 : OUString aUITitle;
2673 0 : for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ )
2674 0 : if ( aUINames[nInd].First.equals( aTitle ) )
2675 : {
2676 0 : aUITitle = aUINames[nInd].Second;
2677 0 : break;
2678 : }
2679 :
2680 0 : addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent );
2681 : }
2682 0 : }
2683 : }
2684 0 : catch ( Exception& ) {}
2685 0 : }
2686 0 : }
2687 :
2688 :
2689 0 : void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData )
2690 : {
2691 0 : Content aTemplate;
2692 :
2693 0 : if ( Content::create( pData->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2694 : {
2695 0 : removeContent( aTemplate );
2696 0 : }
2697 0 : }
2698 :
2699 :
2700 0 : void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup,
2701 : DocTemplates_EntryData_Impl *pData )
2702 : {
2703 0 : Content aGroup, aTemplate;
2704 :
2705 0 : if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2706 0 : return;
2707 :
2708 : // Check, if there's a template with the given name in this group
2709 : // Return if there is already a template
2710 0 : INetURLObject aGroupObj( pGroup->getHierarchyURL() );
2711 :
2712 0 : aGroupObj.insertName( pData->getTitle(), false,
2713 : INetURLObject::LAST_SEGMENT, true,
2714 0 : INetURLObject::ENCODE_ALL );
2715 :
2716 0 : OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2717 :
2718 0 : if ( Content::create( aTemplateURL, maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2719 0 : return;
2720 :
2721 0 : addEntry( aGroup, pData->getTitle(),
2722 0 : pData->getTargetURL(),
2723 0 : pData->getType() );
2724 : }
2725 :
2726 :
2727 0 : void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData )
2728 : {
2729 0 : Content aTemplate;
2730 :
2731 0 : if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
2732 0 : return;
2733 :
2734 0 : OUString aPropName;
2735 :
2736 0 : if ( pData->getUpdateType() )
2737 : {
2738 0 : aPropName = PROPERTY_TYPE;
2739 0 : setProperty( aTemplate, aPropName, makeAny( pData->getType() ) );
2740 : }
2741 :
2742 0 : if ( pData->getUpdateLink() )
2743 : {
2744 0 : aPropName = TARGET_URL;
2745 0 : setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) );
2746 0 : }
2747 : }
2748 :
2749 :
2750 0 : void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup )
2751 : {
2752 0 : OUString aAdditionalProp( TARGET_DIR_URL );
2753 0 : Content aGroup;
2754 :
2755 0 : INetURLObject aNewGroupObj( maRootURL );
2756 0 : aNewGroupObj.insertName( pGroup->getTitle(), false,
2757 : INetURLObject::LAST_SEGMENT, true,
2758 0 : INetURLObject::ENCODE_ALL );
2759 :
2760 0 : OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE );
2761 :
2762 0 : if ( createFolder( aNewGroupURL, false, false, aGroup ) )
2763 : {
2764 0 : setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) );
2765 0 : pGroup->setHierarchyURL( aNewGroupURL );
2766 :
2767 0 : sal_uIntPtr nCount = pGroup->count();
2768 0 : for ( sal_uIntPtr i=0; i<nCount; i++ )
2769 : {
2770 0 : DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i );
2771 0 : addToHierarchy( pGroup, pData ); // add entry to hierarchy
2772 : }
2773 0 : }
2774 0 : }
2775 :
2776 :
2777 0 : void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup )
2778 : {
2779 0 : Content aGroup;
2780 :
2781 0 : if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, comphelper::getProcessComponentContext(), aGroup ) )
2782 : {
2783 0 : removeContent( aGroup );
2784 0 : }
2785 0 : }
2786 :
2787 :
2788 0 : GroupData_Impl::GroupData_Impl( const OUString& rTitle )
2789 : {
2790 0 : maTitle = rTitle;
2791 0 : mbInUse = false;
2792 0 : mbInHierarchy = false;
2793 0 : }
2794 :
2795 :
2796 0 : GroupData_Impl::~GroupData_Impl()
2797 : {
2798 0 : for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2799 0 : delete maEntries[ i ];
2800 0 : maEntries.clear();
2801 0 : }
2802 :
2803 :
2804 0 : DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle,
2805 : const OUString& rTargetURL,
2806 : const OUString& rType,
2807 : const OUString& rHierURL )
2808 : {
2809 0 : DocTemplates_EntryData_Impl* pData = NULL;
2810 0 : bool EntryFound = false;
2811 :
2812 0 : for ( size_t i = 0, n = maEntries.size(); i < n; ++i )
2813 : {
2814 0 : pData = maEntries[ i ];
2815 0 : if ( pData->getTitle() == rTitle )
2816 : {
2817 0 : EntryFound = true;
2818 0 : break;
2819 : }
2820 : }
2821 :
2822 0 : if ( !EntryFound )
2823 : {
2824 0 : pData = new DocTemplates_EntryData_Impl( rTitle );
2825 0 : pData->setTargetURL( rTargetURL );
2826 0 : pData->setType( rType );
2827 0 : if ( !rHierURL.isEmpty() )
2828 : {
2829 0 : pData->setHierarchyURL( rHierURL );
2830 0 : pData->setHierarchy( true );
2831 : }
2832 0 : maEntries.push_back( pData );
2833 : }
2834 : else
2835 : {
2836 0 : if ( !rHierURL.isEmpty() )
2837 : {
2838 0 : pData->setHierarchyURL( rHierURL );
2839 0 : pData->setHierarchy( true );
2840 : }
2841 :
2842 0 : if ( pData->getInHierarchy() )
2843 0 : pData->setInUse();
2844 :
2845 0 : if ( rTargetURL != pData->getTargetURL() )
2846 : {
2847 0 : pData->setTargetURL( rTargetURL );
2848 0 : pData->setUpdateLink( true );
2849 : }
2850 : }
2851 :
2852 0 : return pData;
2853 : }
2854 :
2855 :
2856 0 : DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle )
2857 : {
2858 0 : maTitle = rTitle;
2859 0 : mbInUse = false;
2860 0 : mbInHierarchy = false;
2861 0 : mbUpdateType = false;
2862 0 : mbUpdateLink = false;
2863 0 : }
2864 :
2865 : }
2866 :
2867 : // static
2868 0 : bool SfxURLRelocator_Impl::propertyCanContainOfficeDir(
2869 : const OUString & rPropName )
2870 : {
2871 : // Note: TargetURL is handled by UCB itself (because it is a property
2872 : // with a predefined semantic). Additional Core properties introduced
2873 : // be a client app must be handled by the client app itself, because
2874 : // the UCB does not know the semantics of those properties.
2875 0 : return ( rPropName == TARGET_DIR_URL || rPropName == PROPERTY_DIRLIST );
2876 : }
2877 :
2878 :
2879 40 : SfxURLRelocator_Impl::SfxURLRelocator_Impl( const uno::Reference< XComponentContext > & xContext )
2880 40 : : mxContext( xContext )
2881 : {
2882 40 : }
2883 :
2884 :
2885 37 : SfxURLRelocator_Impl::~SfxURLRelocator_Impl()
2886 : {
2887 37 : }
2888 :
2889 :
2890 0 : void SfxURLRelocator_Impl::initOfficeInstDirs()
2891 : {
2892 0 : if ( !mxOfficeInstDirs.is() )
2893 : {
2894 0 : osl::MutexGuard aGuard( maMutex );
2895 0 : if ( !mxOfficeInstDirs.is() )
2896 : {
2897 : OSL_ENSURE( mxContext.is(), "No service manager!" );
2898 :
2899 0 : mxOfficeInstDirs = theOfficeInstallationDirectories::get(mxContext);
2900 0 : }
2901 : }
2902 0 : }
2903 :
2904 :
2905 0 : void SfxURLRelocator_Impl::implExpandURL( OUString& io_url )
2906 : {
2907 0 : const INetURLObject aParser( io_url );
2908 0 : if ( aParser.GetProtocol() != INetProtocol::VndSunStarExpand )
2909 0 : return;
2910 :
2911 0 : io_url = aParser.GetURLPath( INetURLObject::DECODE_WITH_CHARSET );
2912 : try
2913 : {
2914 0 : if ( !mxMacroExpander.is() )
2915 : {
2916 0 : mxMacroExpander.set( theMacroExpander::get(mxContext), UNO_QUERY_THROW );
2917 : }
2918 0 : io_url = mxMacroExpander->expandMacros( io_url );
2919 : }
2920 0 : catch( const Exception& )
2921 : {
2922 : DBG_UNHANDLED_EXCEPTION();
2923 0 : }
2924 : }
2925 :
2926 :
2927 0 : void SfxURLRelocator_Impl::makeRelocatableURL( OUString & rURL )
2928 : {
2929 0 : if ( !rURL.isEmpty() )
2930 : {
2931 0 : initOfficeInstDirs();
2932 0 : implExpandURL( rURL );
2933 0 : rURL = mxOfficeInstDirs->makeRelocatableURL( rURL );
2934 : }
2935 0 : }
2936 :
2937 :
2938 0 : void SfxURLRelocator_Impl::makeAbsoluteURL( OUString & rURL )
2939 : {
2940 0 : if ( !rURL.isEmpty() )
2941 : {
2942 0 : initOfficeInstDirs();
2943 0 : implExpandURL( rURL );
2944 0 : rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL );
2945 : }
2946 0 : }
2947 :
2948 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
2949 40 : com_sun_star_comp_sfx2_DocumentTemplates_get_implementation(
2950 : css::uno::XComponentContext *context,
2951 : css::uno::Sequence<css::uno::Any> const &)
2952 : {
2953 40 : return cppu::acquire(new SfxDocTplService(context));
2954 : }
2955 :
2956 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|