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