Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/doc/doctempl.cxx
Line
Count
Source
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
21
#include <limits.h>
22
#include <mutex>
23
#include <string_view>
24
25
#include <com/sun/star/uno/Any.h>
26
#include <sal/log.hxx>
27
28
#include <unotools/pathoptions.hxx>
29
#include <tools/urlobj.hxx>
30
#include <tools/debug.hxx>
31
#include <comphelper/diagnose_ex.hxx>
32
#include <comphelper/processfactory.hxx>
33
#include <comphelper/propertyvalue.hxx>
34
#include <ucbhelper/content.hxx>
35
#include <com/sun/star/beans/PropertyValue.hpp>
36
#include <com/sun/star/beans/XPropertySet.hpp>
37
#include <com/sun/star/beans/XPropertySetInfo.hpp>
38
#include <com/sun/star/document/XTypeDetection.hpp>
39
#include <com/sun/star/document/DocumentProperties.hpp>
40
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
41
#include <com/sun/star/frame/Desktop.hpp>
42
#include <com/sun/star/frame/DocumentTemplates.hpp>
43
#include <com/sun/star/frame/XDocumentTemplates.hpp>
44
#include <com/sun/star/io/IOException.hpp>
45
#include <com/sun/star/io/XPersist.hpp>
46
#include <com/sun/star/lang/XLocalizable.hpp>
47
#include <com/sun/star/sdbc/XResultSet.hpp>
48
#include <com/sun/star/sdbc/XRow.hpp>
49
#include <com/sun/star/ucb/ContentCreationException.hpp>
50
#include <com/sun/star/ucb/NameClash.hpp>
51
#include <com/sun/star/ucb/TransferInfo.hpp>
52
#include <com/sun/star/ucb/XContent.hpp>
53
#include <com/sun/star/ucb/XContentAccess.hpp>
54
#include <com/sun/star/ucb/AnyCompareFactory.hpp>
55
#include <com/sun/star/ucb/NumberedSortingInfo.hpp>
56
57
#include "doctemplateslocal.hxx"
58
#include <sfxurlrelocator.hxx>
59
60
#include <sfx2/doctempl.hxx>
61
#include <sfx2/objsh.hxx>
62
#include <sfx2/sfxresid.hxx>
63
#include <sfx2/strings.hrc>
64
#include <strings.hxx>
65
#include <svtools/templatefoldercache.hxx>
66
67
#include <memory>
68
#include <utility>
69
#include <vector>
70
71
72
using namespace ::com::sun::star;
73
using namespace ::com::sun::star::beans;
74
using namespace ::com::sun::star::frame;
75
using namespace ::com::sun::star::io;
76
using namespace ::com::sun::star::lang;
77
using namespace ::com::sun::star::sdbc;
78
using namespace ::com::sun::star::uno;
79
using namespace ::com::sun::star::ucb;
80
using namespace ::com::sun::star::document;
81
using namespace ::rtl;
82
using namespace ::ucbhelper;
83
84
constexpr OUString TITLE = u"Title"_ustr;
85
constexpr OUString TARGET_URL = u"TargetURL"_ustr;
86
87
constexpr OUStringLiteral COMMAND_TRANSFER = u"transfer";
88
89
namespace {
90
91
class RegionData_Impl;
92
93
}
94
95
namespace DocTempl {
96
97
namespace {
98
99
class DocTempl_EntryData_Impl
100
{
101
    // the following member must be SfxObjectShellLock since it controls that SfxObjectShell lifetime by design
102
    // and users of this class expect it to be so.
103
    SfxObjectShellLock  mxObjShell;
104
105
    OUString            maTitle;
106
    OUString            maOwnURL;
107
    OUString            maTargetURL;
108
109
public:
110
                        DocTempl_EntryData_Impl(const OUString& rTitle);
111
112
0
    const OUString&     GetTitle() const { return maTitle; }
113
    const OUString&     GetTargetURL(const INetURLObject& rRootURL);
114
    const OUString&     GetHierarchyURL(const INetURLObject& rRootURL);
115
116
0
    void                SetTitle( const OUString& rTitle ) { maTitle = rTitle; }
117
0
    void                SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; }
118
0
    void                SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; }
119
120
    int                 Compare( std::u16string_view rTitle ) const;
121
};
122
123
}
124
125
}
126
127
using namespace ::DocTempl;
128
129
namespace {
130
131
class RegionData_Impl
132
{
133
    std::vector<std::unique_ptr<DocTempl_EntryData_Impl>> maEntries;
134
    OUString                    maTitle;
135
    OUString                    maOwnURL;
136
137
private:
138
    size_t                      GetEntryPos( std::u16string_view rTitle,
139
                                             bool& rFound ) const;
140
141
public:
142
                        RegionData_Impl(OUString aTitle);
143
144
0
    void                SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; }
145
146
    DocTempl_EntryData_Impl*     GetEntry( size_t nIndex ) const;
147
    DocTempl_EntryData_Impl*     GetEntry( std::u16string_view rName ) const;
148
149
0
    const OUString&     GetTitle() const { return maTitle; }
150
    const OUString&     GetHierarchyURL(const INetURLObject& rRootURL);
151
152
    size_t              GetCount() const;
153
154
0
    void                SetTitle( const OUString& rTitle ) { maTitle = rTitle; }
155
156
    void                AddEntry(const INetURLObject& rRootURL,
157
                                 const OUString& rTitle,
158
                                 const OUString& rTargetURL,
159
                                 const size_t *pPos);
160
    void                DeleteEntry( size_t nIndex );
161
162
    int                 Compare( RegionData_Impl const * pCompareWith ) const;
163
};
164
165
}
166
167
class SfxDocTemplate_Impl : public SvRefBase
168
{
169
    uno::Reference< XPersist >               mxInfo;
170
    uno::Reference< XDocumentTemplates >     mxTemplates;
171
172
    mutable std::mutex  maMutex;
173
    OUString            maRootURL;
174
    OUString            maStandardGroup;
175
    std::vector<std::unique_ptr<RegionData_Impl>> maRegions;
176
    bool            mbConstructed;
177
178
    uno::Reference< XAnyCompareFactory > m_rCompareFactory;
179
180
    // the following member is intended to prevent clearing of the global data when it is in use
181
    // TODO/LATER: it still does not make the implementation complete thread-safe
182
    sal_Int32           mnLockCounter;
183
184
private:
185
    void                Clear();
186
187
public:
188
                        SfxDocTemplate_Impl();
189
                        virtual ~SfxDocTemplate_Impl() override;
190
191
    void                IncrementLock();
192
    void                DecrementLock();
193
194
    bool            Construct( );
195
    void                CreateFromHierarchy( std::unique_lock<std::mutex>& rGuard, Content &rTemplRoot );
196
    void                ReInitFromComponent();
197
    void                AddRegion( std::unique_lock<std::mutex>& rGuard,
198
                                   const OUString& rTitle,
199
                                   Content& rContent );
200
201
    void                Rescan();
202
203
    void                DeleteRegion( size_t nIndex );
204
205
    size_t              GetRegionCount() const
206
0
                            { return maRegions.size(); }
207
    RegionData_Impl*    GetRegion( std::u16string_view rName ) const;
208
    RegionData_Impl*    GetRegion( size_t nIndex ) const;
209
210
    bool            GetTitleFromURL( const OUString& rURL, OUString& aTitle );
211
    bool            InsertRegion( std::unique_ptr<RegionData_Impl> pData, size_t nPos );
212
213
    INetURLObject   GetRootURL() const
214
0
    {
215
0
        std::unique_lock aGuard(maMutex);
216
0
        return INetURLObject(maRootURL);
217
0
    }
218
219
    uno::Reference<XDocumentTemplates> getDocTemplates() const
220
0
    {
221
0
        std::unique_lock aGuard(maMutex);
222
0
        return mxTemplates;
223
0
    }
224
};
225
226
namespace {
227
228
class DocTemplLocker_Impl
229
{
230
    SfxDocTemplate_Impl& m_aDocTempl;
231
public:
232
    explicit DocTemplLocker_Impl( SfxDocTemplate_Impl& aDocTempl )
233
0
    : m_aDocTempl( aDocTempl )
234
0
    {
235
0
        m_aDocTempl.IncrementLock();
236
0
    }
237
238
    ~DocTemplLocker_Impl()
239
0
    {
240
0
        m_aDocTempl.DecrementLock();
241
0
    }
242
};
243
244
}
245
246
static SfxDocTemplate_Impl *gpTemplateData = nullptr;
247
248
249
static bool getTextProperty_Impl( Content& rContent,
250
                                      const OUString& rPropName,
251
                                      OUString& rPropValue );
252
253
254
OUString SfxDocumentTemplates::GetFullRegionName
255
(
256
    sal_uInt16 nIdx                     // Region Index
257
)   const
258
259
/*  [Description]
260
261
    Returns the logical name of a region and its path
262
263
    [Return value]                 Reference to the Region name
264
265
*/
266
267
0
{
268
    // First: find the RegionData for the index
269
270
0
    DocTemplLocker_Impl aLocker( *pImp );
271
272
0
    if ( pImp->Construct() )
273
0
    {
274
0
        RegionData_Impl *pData1 = pImp->GetRegion( nIdx );
275
276
0
        if ( pData1 )
277
0
            return pData1->GetTitle();
278
279
        // --**-- here was some code which appended the path to the
280
        //      group if there was more than one with the same name.
281
        //      this should not happen anymore
282
0
    }
283
284
0
    return OUString();
285
0
}
286
287
288
OUString SfxDocumentTemplates::GetRegionName
289
(
290
    sal_uInt16 nIdx                 // Region Index
291
)   const
292
293
/*  [Description]
294
295
    Returns the logical name of a region
296
297
    [Return value]
298
299
    const String&                   Reference to the Region name
300
301
*/
302
0
{
303
0
    DocTemplLocker_Impl aLocker( *pImp );
304
305
0
    if ( pImp->Construct() )
306
0
    {
307
0
        RegionData_Impl *pData = pImp->GetRegion( nIdx );
308
309
0
        if ( pData )
310
0
            return pData->GetTitle();
311
0
    }
312
313
0
    return OUString();
314
0
}
315
316
317
sal_uInt16 SfxDocumentTemplates::GetRegionCount() const
318
319
/*  [Description]
320
321
    Returns the number of Regions
322
323
    [Return value]
324
325
    sal_uInt16                  Number of Regions
326
*/
327
0
{
328
0
    DocTemplLocker_Impl aLocker( *pImp );
329
330
0
    if ( !pImp->Construct() )
331
0
        return 0;
332
333
0
    return pImp->GetRegionCount();
334
0
}
335
336
337
sal_uInt16 SfxDocumentTemplates::GetCount
338
(
339
    sal_uInt16 nRegion              /* Region index whose number is
340
                                   to be determined */
341
342
)   const
343
344
/*  [Description]
345
346
    Number of entries in Region
347
348
    [Return value]                 Number of entries
349
*/
350
351
0
{
352
0
    DocTemplLocker_Impl aLocker( *pImp );
353
354
0
    if ( !pImp->Construct() )
355
0
        return 0;
356
357
0
    RegionData_Impl *pData = pImp->GetRegion( nRegion );
358
359
0
    if ( !pData )
360
0
        return 0;
361
362
0
    return pData->GetCount();
363
0
}
364
365
366
OUString SfxDocumentTemplates::GetName
367
(
368
    sal_uInt16 nRegion,     //  Region Index, in which the entry lies
369
    sal_uInt16 nIdx         //  Index of the entry
370
)   const
371
372
/*  [Description]
373
374
    Returns the logical name of an entry in Region
375
376
    [Return value]
377
378
    const String&           Entry Name
379
*/
380
381
0
{
382
0
    DocTemplLocker_Impl aLocker( *pImp );
383
384
0
    if ( pImp->Construct() )
385
0
    {
386
0
        RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
387
388
0
        if ( pRegion )
389
0
        {
390
0
            DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
391
0
            if ( pEntry )
392
0
                return pEntry->GetTitle();
393
0
        }
394
0
    }
395
396
0
    return OUString();
397
0
}
398
399
400
OUString SfxDocumentTemplates::GetPath
401
(
402
    sal_uInt16  nRegion,    //  Region Index, in which the entry lies
403
    sal_uInt16  nIdx        //  Index of the entry
404
)   const
405
406
/*  [Description]
407
408
    Returns the file name with full path to the file assigned to an entry
409
410
    [Return value]
411
412
    String                  File name with full path
413
*/
414
0
{
415
0
    DocTemplLocker_Impl aLocker( *pImp );
416
417
0
    if ( !pImp->Construct() )
418
0
        return OUString();
419
420
0
    RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
421
422
0
    if ( pRegion )
423
0
    {
424
0
        DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
425
0
        if ( pEntry )
426
0
            return pEntry->GetTargetURL(pImp->GetRootURL());
427
0
    }
428
429
0
    return OUString();
430
0
}
431
432
OUString SfxDocumentTemplates::GetTemplateTargetURLFromComponent( std::u16string_view aGroupName,
433
                                                                    std::u16string_view aTitle )
434
0
{
435
0
    DocTemplLocker_Impl aLocker( *pImp );
436
437
0
    INetURLObject aTemplateObj( pImp->GetRootURL() );
438
439
0
    aTemplateObj.insertName( aGroupName, false,
440
0
                        INetURLObject::LAST_SEGMENT,
441
0
                        INetURLObject::EncodeMechanism::All );
442
443
0
    aTemplateObj.insertName( aTitle, false,
444
0
                        INetURLObject::LAST_SEGMENT,
445
0
                        INetURLObject::EncodeMechanism::All );
446
447
448
0
    Content aTemplate;
449
0
    uno::Reference< XCommandEnvironment > aCmdEnv;
450
0
    if ( Content::create( aTemplateObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext(), aTemplate ) )
451
0
    {
452
0
        OUString aResult;
453
0
        getTextProperty_Impl( aTemplate, TARGET_URL, aResult );
454
0
        return SvtPathOptions().SubstituteVariable( aResult );
455
0
    }
456
457
0
    return OUString();
458
0
}
459
460
461
/** Convert a template name to its localised pair if it exists.
462
    @param rString
463
        Name to be translated.
464
    @return
465
        The localised pair of rString or rString if the former does not exist.
466
*/
467
OUString SfxDocumentTemplates::ConvertResourceString(const OUString& rString)
468
0
{
469
0
    static constexpr OUString aTemplateNames[] =
470
0
    {
471
0
        STR_TEMPLATE_NAME1_DEF,
472
0
        STR_TEMPLATE_NAME2_DEF,
473
0
        STR_TEMPLATE_NAME3_DEF,
474
0
        STR_TEMPLATE_NAME4_DEF,
475
0
        STR_TEMPLATE_NAME5_DEF,
476
0
        STR_TEMPLATE_NAME6_DEF,
477
0
        STR_TEMPLATE_NAME7_DEF,
478
0
        STR_TEMPLATE_NAME8_DEF,
479
0
        STR_TEMPLATE_NAME9_DEF,
480
0
        STR_TEMPLATE_NAME10_DEF,
481
0
        STR_TEMPLATE_NAME11_DEF,
482
0
        STR_TEMPLATE_NAME12_DEF,
483
0
        STR_TEMPLATE_NAME13_DEF,
484
0
        STR_TEMPLATE_NAME14_DEF,
485
0
        STR_TEMPLATE_NAME15_DEF,
486
0
        STR_TEMPLATE_NAME16_DEF,
487
0
        STR_TEMPLATE_NAME17_DEF,
488
0
        STR_TEMPLATE_NAME18_DEF,
489
0
        STR_TEMPLATE_NAME19_DEF,
490
0
        STR_TEMPLATE_NAME20_DEF,
491
0
        STR_TEMPLATE_NAME21_DEF,
492
0
        STR_TEMPLATE_NAME22_DEF,
493
0
        STR_TEMPLATE_NAME23_DEF,
494
0
        STR_TEMPLATE_NAME24_DEF,
495
0
        STR_TEMPLATE_NAME25_DEF,
496
0
        STR_TEMPLATE_NAME26_DEF,
497
0
        STR_TEMPLATE_NAME27_DEF,
498
0
        STR_TEMPLATE_NAME28_DEF,
499
0
        STR_TEMPLATE_NAME29_DEF,
500
0
        STR_TEMPLATE_NAME30_DEF,
501
0
        STR_TEMPLATE_NAME31_DEF,
502
0
        STR_TEMPLATE_NAME32_DEF,
503
0
        STR_TEMPLATE_NAME33_DEF,
504
0
        STR_TEMPLATE_NAME34_DEF
505
0
    };
506
507
0
    TranslateId STR_TEMPLATE_NAME[] =
508
0
    {
509
0
        STR_TEMPLATE_NAME1,
510
0
        STR_TEMPLATE_NAME2,
511
0
        STR_TEMPLATE_NAME3,
512
0
        STR_TEMPLATE_NAME4,
513
0
        STR_TEMPLATE_NAME5,
514
0
        STR_TEMPLATE_NAME6,
515
0
        STR_TEMPLATE_NAME7,
516
0
        STR_TEMPLATE_NAME8,
517
0
        STR_TEMPLATE_NAME9,
518
0
        STR_TEMPLATE_NAME10,
519
0
        STR_TEMPLATE_NAME11,
520
0
        STR_TEMPLATE_NAME12,
521
0
        STR_TEMPLATE_NAME13,
522
0
        STR_TEMPLATE_NAME14,
523
0
        STR_TEMPLATE_NAME15,
524
0
        STR_TEMPLATE_NAME16,
525
0
        STR_TEMPLATE_NAME17,
526
0
        STR_TEMPLATE_NAME18,
527
0
        STR_TEMPLATE_NAME19,
528
0
        STR_TEMPLATE_NAME20,
529
0
        STR_TEMPLATE_NAME21,
530
0
        STR_TEMPLATE_NAME22,
531
0
        STR_TEMPLATE_NAME23,
532
0
        STR_TEMPLATE_NAME24,
533
0
        STR_TEMPLATE_NAME25,
534
0
        STR_TEMPLATE_NAME26,
535
0
        STR_TEMPLATE_NAME27,
536
0
        STR_TEMPLATE_NAME28,
537
0
        STR_TEMPLATE_NAME29,
538
0
        STR_TEMPLATE_NAME30,
539
0
        STR_TEMPLATE_NAME31,
540
0
        STR_TEMPLATE_NAME32,
541
0
        STR_TEMPLATE_NAME33,
542
0
        STR_TEMPLATE_NAME34
543
0
    };
544
545
0
    static_assert(SAL_N_ELEMENTS(aTemplateNames) == SAL_N_ELEMENTS(STR_TEMPLATE_NAME));
546
547
0
    for (size_t i = 0; i < SAL_N_ELEMENTS(STR_TEMPLATE_NAME); ++i)
548
0
    {
549
0
        if (rString == aTemplateNames[i])
550
0
            return SfxResId(STR_TEMPLATE_NAME[i]);
551
0
    }
552
0
    return rString;
553
0
}
554
555
556
bool SfxDocumentTemplates::CopyOrMove
557
(
558
    sal_uInt16  nTargetRegion,      //  Target Region Index
559
    sal_uInt16  nTargetIdx,         //  Target position Index
560
    sal_uInt16  nSourceRegion,      //  Source Region Index
561
    sal_uInt16  nSourceIdx,         /*  Index to be copied / to moved template */
562
    bool        bMove               //  Copy / Move
563
)
564
565
/*  [Description]
566
567
    Copy or move a document template
568
569
    [Return value]
570
571
    sal_Bool            sal_True,   Action could be performed
572
                        sal_False,  Action could not be performed
573
574
    [Cross-references]
575
576
    <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
577
    <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)>
578
*/
579
580
0
{
581
    /* to perform a copy or move, we need to send a transfer command to
582
       the destination folder with the URL of the source as parameter.
583
       ( If the destination content doesn't support the transfer command,
584
       we could try a copy ( and delete ) instead. )
585
       We need two transfers ( one for the real template and one for its
586
       representation in the hierarchy )
587
       ...
588
    */
589
590
0
    DocTemplLocker_Impl aLocker( *pImp );
591
592
0
    if ( !pImp->Construct() )
593
0
        return false;
594
595
    // Don't copy or move any folders
596
0
    if( nSourceIdx == USHRT_MAX )
597
0
        return false ;
598
599
0
    if ( nSourceRegion == nTargetRegion )
600
0
    {
601
0
        SAL_WARN( "sfx.doc", "Don't know, what to do!" );
602
0
        return false;
603
0
    }
604
605
0
    RegionData_Impl *pSourceRgn = pImp->GetRegion( nSourceRegion );
606
0
    if ( !pSourceRgn )
607
0
        return false;
608
609
0
    DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nSourceIdx );
610
0
    if ( !pSource )
611
0
        return false;
612
613
0
    RegionData_Impl *pTargetRgn = pImp->GetRegion( nTargetRegion );
614
0
    if ( !pTargetRgn )
615
0
        return false;
616
617
0
    const OUString aTitle = pSource->GetTitle();
618
619
0
    uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
620
621
0
    if ( xTemplates->addTemplate( pTargetRgn->GetTitle(),
622
0
                                  aTitle,
623
0
                                  pSource->GetTargetURL(pImp->GetRootURL()) ) )
624
0
    {
625
0
        const OUString aNewTargetURL = GetTemplateTargetURLFromComponent( pTargetRgn->GetTitle(), aTitle );
626
0
        if ( aNewTargetURL.isEmpty() )
627
0
            return false;
628
629
0
        if ( bMove )
630
0
        {
631
            // --**-- delete the original file
632
0
            bool bDeleted = xTemplates->removeTemplate( pSourceRgn->GetTitle(),
633
0
                                                            pSource->GetTitle() );
634
0
            if ( bDeleted )
635
0
                pSourceRgn->DeleteEntry( nSourceIdx );
636
0
            else
637
0
            {
638
0
                if ( xTemplates->removeTemplate( pTargetRgn->GetTitle(), aTitle ) )
639
0
                    return false; // will trigger retry with copy instead of move
640
641
                // if it is not possible to remove just created template ( must be possible! )
642
                // it is better to report success here, since at least the copy has succeeded
643
                // TODO/LATER: solve it more gracefully in future
644
0
            }
645
0
        }
646
647
        // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
648
0
        size_t temp_nTargetIdx = nTargetIdx;
649
0
        pTargetRgn->AddEntry(pImp->GetRootURL(), aTitle, aNewTargetURL, &temp_nTargetIdx);
650
651
0
        return true;
652
0
    }
653
654
    // --**-- if the current file is opened,
655
    // it must be re-opened afterwards.
656
657
0
    return false;
658
0
}
659
660
bool SfxDocumentTemplates::Move
661
(
662
    sal_uInt16 nTargetRegion,       //  Target Region Index
663
    sal_uInt16 nTargetIdx,          //  Target position Index
664
    sal_uInt16 nSourceRegion,       //  Source Region Index
665
    sal_uInt16 nSourceIdx           /*  Index to be copied / to moved template */
666
)
667
668
/*  [Description]
669
670
    Moving a template
671
672
    [Return value]
673
674
    sal_Bool            sal_True,   Action could be performed
675
                        sal_False,  Action could not be performed
676
677
    [Cross-references]
678
679
    <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
680
*/
681
0
{
682
0
    DocTemplLocker_Impl aLocker( *pImp );
683
684
0
    return CopyOrMove( nTargetRegion, nTargetIdx,
685
0
                       nSourceRegion, nSourceIdx, true );
686
0
}
687
688
689
bool SfxDocumentTemplates::Copy
690
(
691
    sal_uInt16 nTargetRegion,       //  Target Region Index
692
    sal_uInt16 nTargetIdx,          //  Target position Index
693
    sal_uInt16 nSourceRegion,       //  Source Region Index
694
    sal_uInt16 nSourceIdx           /*  Index to be copied / to moved template */
695
)
696
697
/*  [Description]
698
699
    Copying a template
700
701
    [Return value]
702
703
    sal_Bool            sal_True,   Action could be performed
704
                        sal_False,  Action could not be performed
705
706
    [Cross-references]
707
708
    <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)>
709
*/
710
711
0
{
712
0
    DocTemplLocker_Impl aLocker( *pImp );
713
714
0
    return CopyOrMove( nTargetRegion, nTargetIdx,
715
0
                       nSourceRegion, nSourceIdx, false );
716
0
}
717
718
719
bool SfxDocumentTemplates::CopyTo
720
(
721
    sal_uInt16          nRegion,    //  Region of the template to be exported
722
    sal_uInt16          nIdx,       //  Index of the template to be exported
723
    std::u16string_view rName       /*  File name under which the template is to
724
                                    be created */
725
)   const
726
727
/*  [Description]
728
729
    Exporting a template into the file system
730
731
    [Return value]
732
733
    sal_Bool            sal_True,   Action could be performed
734
                        sal_False,  Action could not be performed
735
736
    [Cross-references]
737
738
    <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)>
739
*/
740
741
0
{
742
0
    DocTemplLocker_Impl aLocker( *pImp );
743
744
0
    if ( ! pImp->Construct() )
745
0
        return false;
746
747
0
    RegionData_Impl *pSourceRgn = pImp->GetRegion( nRegion );
748
0
    if ( !pSourceRgn )
749
0
        return false;
750
751
0
    DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nIdx );
752
0
    if ( !pSource )
753
0
        return false;
754
755
0
    INetURLObject aTargetURL( rName );
756
757
0
    const OUString aTitle( aTargetURL.getName( INetURLObject::LAST_SEGMENT, true,
758
0
                                         INetURLObject::DecodeMechanism::WithCharset ) );
759
0
    aTargetURL.removeSegment();
760
761
0
    const OUString aParentURL = aTargetURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
762
763
0
    uno::Reference< XCommandEnvironment > aCmdEnv;
764
0
    Content aTarget;
765
766
0
    try
767
0
    {
768
0
        aTarget = Content( aParentURL, aCmdEnv, comphelper::getProcessComponentContext() );
769
770
0
        TransferInfo aTransferInfo;
771
0
        aTransferInfo.MoveData = false;
772
0
        aTransferInfo.SourceURL = pSource->GetTargetURL(pImp->GetRootURL());
773
0
        aTransferInfo.NewTitle = aTitle;
774
0
        aTransferInfo.NameClash = NameClash::RENAME;
775
776
0
        Any aArg( aTransferInfo );
777
0
        aTarget.executeCommand( COMMAND_TRANSFER, aArg );
778
0
    }
779
0
    catch ( ContentCreationException& )
780
0
    { return false; }
781
0
    catch ( Exception& )
782
0
    { return false; }
783
784
0
    return true;
785
0
}
786
787
788
bool SfxDocumentTemplates::CopyFrom
789
(
790
    sal_uInt16      nRegion,        /*  Region in which the template is to be
791
                                    imported */
792
    sal_uInt16      nIdx,           //  Index of the new template in this Region
793
    OUString&       rName           /*  File name of the template to be imported
794
                                    as an out parameter of the (automatically
795
                                    generated from the file name) logical name
796
                                    of the template */
797
)
798
799
/*  [Description]
800
801
    Import a template from the file system
802
803
    [Return value]                 Success (sal_True) or serfpTargetDirectory->GetContent());
804
805
    sal_Bool            sal_True,   Action could be performed
806
                        sal_False,  Action could not be performed
807
808
    [Cross-references]
809
810
    <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)>
811
*/
812
813
0
{
814
0
    DocTemplLocker_Impl aLocker( *pImp );
815
816
0
    if ( ! pImp->Construct() )
817
0
        return false;
818
819
0
    RegionData_Impl *pTargetRgn = pImp->GetRegion( nRegion );
820
821
0
    if ( !pTargetRgn )
822
0
        return false;
823
824
0
    uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
825
0
    if ( !xTemplates.is() )
826
0
        return false;
827
828
0
    OUString aTitle;
829
0
    bool bTemplateAdded = false;
830
831
0
    if( pImp->GetTitleFromURL( rName, aTitle ) )
832
0
    {
833
0
        bTemplateAdded = xTemplates->addTemplate( pTargetRgn->GetTitle(), aTitle, rName );
834
0
    }
835
0
    else
836
0
    {
837
0
        uno::Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
838
839
0
        Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(u"Hidden"_ustr, true) };
840
841
0
        INetURLObject   aTemplURL( rName );
842
0
        uno::Reference< XDocumentPropertiesSupplier > xDocPropsSupplier;
843
0
        uno::Reference< XStorable > xStorable;
844
0
        try
845
0
        {
846
0
            xStorable.set(
847
0
                xDesktop->loadComponentFromURL( aTemplURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
848
0
                                                u"_blank"_ustr,
849
0
                                                0,
850
0
                                                aArgs ),
851
0
                UNO_QUERY );
852
853
0
            xDocPropsSupplier.set( xStorable, UNO_QUERY );
854
0
        }
855
0
        catch( Exception& )
856
0
        {
857
0
        }
858
859
0
        if( xStorable.is() )
860
0
        {
861
            // get Title from XDocumentPropertiesSupplier
862
0
            if( xDocPropsSupplier.is() )
863
0
            {
864
0
                uno::Reference< XDocumentProperties > xDocProps
865
0
                    = xDocPropsSupplier->getDocumentProperties();
866
0
                if (xDocProps.is() ) {
867
0
                    aTitle = xDocProps->getTitle();
868
0
                }
869
0
            }
870
871
0
            if( aTitle.isEmpty() )
872
0
            {
873
0
                INetURLObject aURL(std::move(aTemplURL));
874
0
                aURL.CutExtension();
875
0
                aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
876
0
                                        INetURLObject::DecodeMechanism::WithCharset );
877
0
            }
878
879
            // write a template using XStorable interface
880
0
            bTemplateAdded = xTemplates->storeTemplate( pTargetRgn->GetTitle(), aTitle, xStorable );
881
0
        }
882
0
    }
883
884
885
0
    if( bTemplateAdded )
886
0
    {
887
0
        INetURLObject aTemplObj(pTargetRgn->GetHierarchyURL(pImp->GetRootURL()));
888
0
        aTemplObj.insertName( aTitle, false,
889
0
                              INetURLObject::LAST_SEGMENT,
890
0
                              INetURLObject::EncodeMechanism::All );
891
0
        const OUString aTemplURL = aTemplObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
892
893
0
        uno::Reference< XCommandEnvironment > aCmdEnv;
894
0
        Content aTemplCont;
895
896
0
        if( Content::create( aTemplURL, aCmdEnv, comphelper::getProcessComponentContext(), aTemplCont ) )
897
0
        {
898
0
            OUString aTemplName;
899
0
            if( getTextProperty_Impl( aTemplCont, TARGET_URL, aTemplName ) )
900
0
            {
901
0
                if ( nIdx == USHRT_MAX )
902
0
                    nIdx = 0;
903
0
                else
904
0
                    ++nIdx;
905
906
                // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16
907
0
                size_t temp_nIdx = nIdx;
908
0
                pTargetRgn->AddEntry(pImp->GetRootURL(), aTitle, aTemplName, &temp_nIdx);
909
0
                rName = aTitle;
910
0
                return true;
911
0
            }
912
0
            else
913
0
            {
914
0
                SAL_WARN( "sfx.doc", "CopyFrom(): The content should contain target URL!" );
915
0
            }
916
0
        }
917
0
        else
918
0
        {
919
0
            SAL_WARN( "sfx.doc", "CopyFrom(): The content just was created!" );
920
0
        }
921
0
    }
922
923
0
    return false;
924
0
}
925
926
927
bool SfxDocumentTemplates::Delete
928
(
929
    sal_uInt16 nRegion,             //  Region Index
930
    sal_uInt16 nIdx                 /*  Index of the entry or USHRT_MAX,
931
                                    if a directory is meant. */
932
)
933
934
/*  [Description]
935
936
    Deleting an entry or a directory
937
938
    [Return value]
939
940
    sal_Bool            sal_True,   Action could be performed
941
                        sal_False,  Action could not be performed
942
943
    [Cross-references]
944
945
    <SfxDocumentTemplates::InsertDir(const String&,sal_uInt16)>
946
    <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
947
*/
948
949
0
{
950
0
    DocTemplLocker_Impl aLocker( *pImp );
951
952
    /* delete the template or folder in the hierarchy and in the
953
       template folder by sending a delete command to the content.
954
       Then remove the data from the lists
955
    */
956
0
    if ( ! pImp->Construct() )
957
0
        return false;
958
959
0
    RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
960
961
0
    if ( !pRegion )
962
0
        return false;
963
964
0
    bool bRet;
965
0
    uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
966
967
0
    if ( nIdx == USHRT_MAX )
968
0
    {
969
0
        bRet = xTemplates->removeGroup( pRegion->GetTitle() );
970
0
        if ( bRet )
971
0
            pImp->DeleteRegion( nRegion );
972
0
    }
973
0
    else
974
0
    {
975
0
        DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
976
977
0
        if ( !pEntry )
978
0
            return false;
979
980
0
        bRet = xTemplates->removeTemplate( pRegion->GetTitle(),
981
0
                                           pEntry->GetTitle() );
982
0
        if( bRet )
983
0
            pRegion->DeleteEntry( nIdx );
984
0
    }
985
986
0
    return bRet;
987
0
}
988
989
990
bool SfxDocumentTemplates::InsertDir
991
(
992
    const OUString&     rText,      //  the logical name of the new Region
993
    sal_uInt16          nRegion     //  Region Index
994
)
995
996
/*  [Description]
997
998
    Insert an index
999
1000
    [Return value]
1001
1002
    sal_Bool            sal_True,   Action could be performed
1003
                        sal_False,  Action could not be performed
1004
1005
    [Cross-references]
1006
1007
    <SfxDocumentTemplates::KillDir(SfxTemplateDir&)>
1008
*/
1009
0
{
1010
0
    DocTemplLocker_Impl aLocker( *pImp );
1011
1012
0
    if ( ! pImp->Construct() )
1013
0
        return false;
1014
1015
0
    RegionData_Impl *pRegion = pImp->GetRegion( rText );
1016
1017
0
    if ( pRegion )
1018
0
        return false;
1019
1020
0
    uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
1021
1022
0
    if (xTemplates->addGroup(rText))
1023
0
        return pImp->InsertRegion(std::make_unique<RegionData_Impl>(rText), nRegion);
1024
1025
0
    return false;
1026
0
}
1027
1028
bool SfxDocumentTemplates::InsertTemplate(sal_uInt16 nSourceRegion, sal_uInt16 nIdx, const OUString &rName, const OUString &rPath)
1029
0
{
1030
0
    DocTemplLocker_Impl aLocker( *pImp );
1031
1032
0
    if ( ! pImp->Construct() )
1033
0
        return false;
1034
1035
0
    RegionData_Impl *pRegion = pImp->GetRegion( nSourceRegion );
1036
1037
0
    if ( !pRegion )
1038
0
        return false;
1039
1040
0
    size_t pos = nIdx;
1041
0
    pRegion->AddEntry(pImp->GetRootURL(), rName, rPath, &pos);
1042
1043
0
    return true;
1044
0
}
1045
1046
bool SfxDocumentTemplates::SetName( const OUString& rName, sal_uInt16 nRegion, sal_uInt16 nIdx )
1047
1048
0
{
1049
0
    DocTemplLocker_Impl aLocker( *pImp );
1050
1051
0
    if ( ! pImp->Construct() )
1052
0
        return false;
1053
1054
0
    RegionData_Impl *pRegion = pImp->GetRegion( nRegion );
1055
1056
0
    if ( !pRegion )
1057
0
        return false;
1058
1059
0
    uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates();
1060
1061
0
    if ( nIdx == USHRT_MAX )
1062
0
    {
1063
0
        if ( pRegion->GetTitle() == rName )
1064
0
            return true;
1065
1066
        // we have to rename a region
1067
0
        if ( xTemplates->renameGroup( pRegion->GetTitle(), rName ) )
1068
0
        {
1069
0
            pRegion->SetTitle( rName );
1070
0
            pRegion->SetHierarchyURL( u""_ustr );
1071
0
            return true;
1072
0
        }
1073
0
    }
1074
0
    else
1075
0
    {
1076
0
        DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx );
1077
1078
0
        if ( !pEntry )
1079
0
            return false;
1080
1081
0
        if ( pEntry->GetTitle() == rName )
1082
0
            return true;
1083
1084
0
        if ( xTemplates->renameTemplate( pRegion->GetTitle(),
1085
0
                                         pEntry->GetTitle(),
1086
0
                                         rName ) )
1087
0
        {
1088
0
            pEntry->SetTitle( rName );
1089
0
            pEntry->SetTargetURL( u""_ustr );
1090
0
            pEntry->SetHierarchyURL( u""_ustr );
1091
0
            return true;
1092
0
        }
1093
0
    }
1094
1095
0
    return false;
1096
0
}
1097
1098
1099
bool SfxDocumentTemplates::GetFull
1100
(
1101
    std::u16string_view rRegion,      // Region Name
1102
    std::u16string_view rName,    // Template Name
1103
    OUString &rPath               // Out: Path + File name
1104
)
1105
1106
/*  [Description]
1107
1108
    Returns Path + File name of the template specified by rRegion and rName.
1109
1110
    [Return value]
1111
1112
    sal_Bool            sal_True,   Action could be performed
1113
                        sal_False,  Action could not be performed
1114
1115
    [Cross-references]
1116
1117
    <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)>
1118
*/
1119
1120
0
{
1121
0
    DocTemplLocker_Impl aLocker( *pImp );
1122
1123
    // We don't search for empty names!
1124
0
    if ( rName.empty() )
1125
0
        return false;
1126
1127
0
    if ( ! pImp->Construct() )
1128
0
        return false;
1129
1130
0
    DocTempl_EntryData_Impl* pEntry = nullptr;
1131
0
    const sal_uInt16 nCount = GetRegionCount();
1132
1133
0
    for ( sal_uInt16 i = 0; i < nCount; ++i )
1134
0
    {
1135
0
        RegionData_Impl *pRegion = pImp->GetRegion( i );
1136
1137
0
        if( pRegion &&
1138
0
            ( rRegion.empty() || ( rRegion == pRegion->GetTitle() ) ) )
1139
0
        {
1140
0
            pEntry = pRegion->GetEntry( rName );
1141
1142
0
            if ( pEntry )
1143
0
            {
1144
0
                rPath = pEntry->GetTargetURL(pImp->GetRootURL());
1145
0
                break;
1146
0
            }
1147
0
        }
1148
0
    }
1149
1150
0
    return ( pEntry != nullptr );
1151
0
}
1152
1153
1154
bool SfxDocumentTemplates::GetLogicNames
1155
(
1156
    std::u16string_view rPath,        // Full Path to the template
1157
    OUString &rRegion,                // Out: Region name
1158
    OUString &rName                   // Out: Template name
1159
) const
1160
1161
/*  [Description]
1162
1163
    Returns and logical path name to the template specified by rPath
1164
1165
    [Return value]
1166
1167
    sal_Bool            sal_True,   Action could be performed
1168
                        sal_False,  Action could not be performed
1169
1170
    [Cross-references]
1171
1172
    <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)>
1173
*/
1174
1175
0
{
1176
0
    DocTemplLocker_Impl aLocker( *pImp );
1177
1178
0
    if ( ! pImp->Construct() )
1179
0
        return false;
1180
1181
0
    INetURLObject aFullPath;
1182
1183
0
    aFullPath.SetSmartProtocol( INetProtocol::File );
1184
0
    aFullPath.SetURL( rPath );
1185
0
    const OUString aPath( aFullPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1186
1187
0
    const sal_uInt16 nCount = GetRegionCount();
1188
1189
0
    for ( sal_uInt16 i=0; i<nCount; ++i )
1190
0
    {
1191
0
        RegionData_Impl *pData = pImp->GetRegion( i );
1192
0
        if ( pData )
1193
0
        {
1194
0
            const sal_uInt16 nChildCount = pData->GetCount();
1195
1196
0
            for ( sal_uInt16 j=0; j<nChildCount; ++j )
1197
0
            {
1198
0
                DocTempl_EntryData_Impl *pEntry = pData->GetEntry( j );
1199
0
                if ( pEntry && pEntry->GetTargetURL(pImp->GetRootURL()) == aPath )
1200
0
                {
1201
0
                    rRegion = pData->GetTitle();
1202
0
                    rName = pEntry->GetTitle();
1203
0
                    return true;
1204
0
                }
1205
0
            }
1206
0
        }
1207
0
    }
1208
1209
0
    return false;
1210
0
}
1211
1212
1213
SfxDocumentTemplates::SfxDocumentTemplates()
1214
1215
/*  [Description]
1216
1217
    Constructor
1218
*/
1219
0
{
1220
0
    if ( !gpTemplateData )
1221
0
        gpTemplateData = new SfxDocTemplate_Impl;
1222
1223
0
    pImp = gpTemplateData;
1224
0
}
1225
1226
1227
SfxDocumentTemplates::~SfxDocumentTemplates()
1228
1229
/*  [Description]
1230
1231
    Destructor
1232
    Release of administrative data
1233
*/
1234
1235
0
{
1236
0
    pImp = nullptr;
1237
0
}
1238
1239
void SfxDocumentTemplates::Update( )
1240
0
{
1241
0
    if ( ::svt::TemplateFolderCache( true ).needsUpdate() )   // update is really necessary
1242
0
    {
1243
0
        if ( pImp->Construct() )
1244
0
            pImp->Rescan();
1245
0
    }
1246
0
}
1247
1248
void SfxDocumentTemplates::ReInitFromComponent()
1249
0
{
1250
0
    pImp->ReInitFromComponent();
1251
0
}
1252
1253
DocTempl_EntryData_Impl::DocTempl_EntryData_Impl(const OUString& rTitle)
1254
0
    : maTitle(SfxDocumentTemplates::ConvertResourceString(rTitle))
1255
0
{
1256
0
}
1257
1258
int DocTempl_EntryData_Impl::Compare( std::u16string_view rTitle ) const
1259
0
{
1260
0
    return maTitle.compareTo( rTitle );
1261
0
}
1262
1263
const OUString& DocTempl_EntryData_Impl::GetHierarchyURL(const INetURLObject& rRootURL)
1264
0
{
1265
0
    if ( maOwnURL.isEmpty() )
1266
0
    {
1267
0
        INetURLObject aTemplateObj(rRootURL);
1268
1269
0
        aTemplateObj.insertName( GetTitle(), false,
1270
0
                     INetURLObject::LAST_SEGMENT,
1271
0
                     INetURLObject::EncodeMechanism::All );
1272
1273
0
        maOwnURL = aTemplateObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1274
0
        DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1275
0
    }
1276
1277
0
    return maOwnURL;
1278
0
}
1279
1280
const OUString& DocTempl_EntryData_Impl::GetTargetURL(const INetURLObject& rRootURL)
1281
0
{
1282
0
    if ( maTargetURL.isEmpty() )
1283
0
    {
1284
0
        uno::Reference< XCommandEnvironment > aCmdEnv;
1285
0
        Content aRegion;
1286
1287
0
        if ( Content::create( GetHierarchyURL(rRootURL), aCmdEnv, comphelper::getProcessComponentContext(), aRegion ) )
1288
0
        {
1289
0
            getTextProperty_Impl( aRegion, TARGET_URL, maTargetURL );
1290
0
        }
1291
0
        else
1292
0
        {
1293
0
            SAL_WARN( "sfx.doc", "GetTargetURL(): Could not create hierarchy content!" );
1294
0
        }
1295
0
    }
1296
1297
0
    return maTargetURL;
1298
0
}
1299
1300
RegionData_Impl::RegionData_Impl(OUString aTitle)
1301
0
    : maTitle(std::move(aTitle))
1302
0
{
1303
0
}
1304
1305
1306
size_t RegionData_Impl::GetEntryPos( std::u16string_view rTitle, bool& rFound ) const
1307
0
{
1308
0
    const size_t nCount = maEntries.size();
1309
1310
0
    for ( size_t i=0; i<nCount; ++i )
1311
0
    {
1312
0
        auto &pData = maEntries[ i ];
1313
1314
0
        if ( pData->Compare( rTitle ) == 0 )
1315
0
        {
1316
0
            rFound = true;
1317
0
            return i;
1318
0
        }
1319
0
    }
1320
1321
0
    rFound = false;
1322
0
    return nCount;
1323
0
}
1324
1325
void RegionData_Impl::AddEntry(const INetURLObject& rRootURL,
1326
                               const OUString& rTitle,
1327
                               const OUString& rTargetURL,
1328
                               const size_t *pPos)
1329
0
{
1330
0
    INetURLObject aLinkObj( GetHierarchyURL(rRootURL) );
1331
0
    aLinkObj.insertName( rTitle, false,
1332
0
                      INetURLObject::LAST_SEGMENT,
1333
0
                      INetURLObject::EncodeMechanism::All );
1334
0
    const OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1335
1336
0
    bool        bFound = false;
1337
0
    size_t          nPos = GetEntryPos( rTitle, bFound );
1338
1339
0
    if ( bFound )
1340
0
        return;
1341
1342
0
    if ( pPos )
1343
0
        nPos = *pPos;
1344
1345
0
    auto pEntry = std::make_unique<DocTempl_EntryData_Impl>(rTitle);
1346
0
    pEntry->SetTargetURL( rTargetURL );
1347
0
    pEntry->SetHierarchyURL( aLinkURL );
1348
0
    if ( nPos < maEntries.size() ) {
1349
0
        auto it = maEntries.begin();
1350
0
        std::advance( it, nPos );
1351
0
        maEntries.insert( it, std::move(pEntry) );
1352
0
    }
1353
0
    else
1354
0
        maEntries.push_back( std::move(pEntry) );
1355
0
}
1356
1357
size_t RegionData_Impl::GetCount() const
1358
0
{
1359
0
    return maEntries.size();
1360
0
}
1361
1362
const OUString& RegionData_Impl::GetHierarchyURL(const INetURLObject& rRootURL)
1363
0
{
1364
0
    if ( maOwnURL.isEmpty() )
1365
0
    {
1366
0
        INetURLObject aRegionObj(rRootURL);
1367
1368
0
        aRegionObj.insertName( GetTitle(), false,
1369
0
                     INetURLObject::LAST_SEGMENT,
1370
0
                     INetURLObject::EncodeMechanism::All );
1371
1372
0
        maOwnURL = aRegionObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1373
0
        DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
1374
0
    }
1375
1376
0
    return maOwnURL;
1377
0
}
1378
1379
DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( std::u16string_view rName ) const
1380
0
{
1381
0
    bool    bFound = false;
1382
0
    tools::Long        nPos = GetEntryPos( rName, bFound );
1383
1384
0
    if ( bFound )
1385
0
        return maEntries[ nPos ].get();
1386
0
    return nullptr;
1387
0
}
1388
1389
1390
DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( size_t nIndex ) const
1391
0
{
1392
0
    if ( nIndex < maEntries.size() )
1393
0
        return maEntries[ nIndex ].get();
1394
0
    return nullptr;
1395
0
}
1396
1397
void RegionData_Impl::DeleteEntry( size_t nIndex )
1398
0
{
1399
0
    if ( nIndex < maEntries.size() )
1400
0
    {
1401
0
        auto it = maEntries.begin();
1402
0
        std::advance( it, nIndex );
1403
0
        maEntries.erase( it );
1404
0
    }
1405
0
}
1406
1407
int RegionData_Impl::Compare( RegionData_Impl const * pCompare ) const
1408
0
{
1409
0
    return maTitle.compareTo( pCompare->maTitle );
1410
0
}
1411
1412
SfxDocTemplate_Impl::SfxDocTemplate_Impl()
1413
0
    : maStandardGroup(DocTemplLocaleHelper::GetStandardGroupString())
1414
0
    , mbConstructed(false)
1415
0
    , mnLockCounter(0)
1416
0
{
1417
0
}
1418
1419
SfxDocTemplate_Impl::~SfxDocTemplate_Impl()
1420
0
{
1421
0
    gpTemplateData = nullptr;
1422
0
}
1423
1424
void SfxDocTemplate_Impl::IncrementLock()
1425
0
{
1426
0
    std::unique_lock aGuard( maMutex );
1427
0
    mnLockCounter++;
1428
0
}
1429
1430
void SfxDocTemplate_Impl::DecrementLock()
1431
0
{
1432
0
    std::unique_lock aGuard( maMutex );
1433
0
    if ( mnLockCounter )
1434
0
        mnLockCounter--;
1435
0
}
1436
1437
RegionData_Impl* SfxDocTemplate_Impl::GetRegion( size_t nIndex ) const
1438
0
{
1439
0
    if ( nIndex < maRegions.size() )
1440
0
        return maRegions[ nIndex ].get();
1441
0
    return nullptr;
1442
0
}
1443
1444
RegionData_Impl* SfxDocTemplate_Impl::GetRegion( std::u16string_view rName )
1445
    const
1446
0
{
1447
0
    for (auto& pData : maRegions)
1448
0
    {
1449
0
        if( pData->GetTitle() == rName )
1450
0
            return pData.get();
1451
0
    }
1452
0
    return nullptr;
1453
0
}
1454
1455
1456
void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex )
1457
0
{
1458
0
    if ( nIndex < maRegions.size() )
1459
0
    {
1460
0
        auto it = maRegions.begin();
1461
0
        std::advance( it, nIndex );
1462
0
        maRegions.erase( it );
1463
0
    }
1464
0
}
1465
1466
1467
/*  AddRegion adds a Region to the RegionList
1468
*/
1469
void SfxDocTemplate_Impl::AddRegion( std::unique_lock<std::mutex>& /*rGuard*/,
1470
                                     const OUString& rTitle,
1471
                                     Content& rContent )
1472
0
{
1473
0
    auto pRegion = std::make_unique<RegionData_Impl>(rTitle);
1474
0
    auto pRegionTmp = pRegion.get();
1475
1476
0
    if ( ! InsertRegion( std::move(pRegion), size_t(-1) ) )
1477
0
    {
1478
0
        return;
1479
0
    }
1480
1481
    // now get the content of the region
1482
0
    uno::Reference< XResultSet > xResultSet;
1483
1484
0
    try
1485
0
    {
1486
0
        xResultSet = rContent.createSortedCursor( { TITLE, TARGET_URL }, { { 1, true } }, m_rCompareFactory, INCLUDE_DOCUMENTS_ONLY );
1487
0
    }
1488
0
    catch ( Exception& ) {}
1489
1490
0
    if ( !xResultSet.is() )
1491
0
        return;
1492
1493
0
    uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
1494
1495
0
    try
1496
0
    {
1497
0
        while ( xResultSet->next() )
1498
0
        {
1499
0
            pRegionTmp->AddEntry(INetURLObject(maRootURL), xRow->getString( 1 ), xRow->getString( 2 ), nullptr);
1500
0
        }
1501
0
    }
1502
0
    catch ( Exception& ) {}
1503
0
}
1504
1505
void SfxDocTemplate_Impl::CreateFromHierarchy( std::unique_lock<std::mutex>& rGuard, Content &rTemplRoot )
1506
0
{
1507
0
    uno::Reference< XResultSet > xResultSet;
1508
0
    Sequence< OUString > aProps { TITLE };
1509
1510
0
    try
1511
0
    {
1512
0
        xResultSet = rTemplRoot.createSortedCursor(
1513
0
                         aProps,
1514
0
                         { // Sequence
1515
0
                              { // NumberedSortingInfo
1516
0
                                  /* ColumnIndex */ 1, /* Ascending */ true
1517
0
                              }
1518
0
                         },
1519
0
                         m_rCompareFactory,
1520
0
                         INCLUDE_FOLDERS_ONLY
1521
0
                     );
1522
0
    }
1523
0
    catch ( Exception& ) {}
1524
1525
0
    if ( !xResultSet.is() )
1526
0
        return;
1527
1528
0
    uno::Reference< XCommandEnvironment > aCmdEnv;
1529
0
    uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
1530
0
    uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
1531
1532
0
    try
1533
0
    {
1534
0
        while ( xResultSet->next() )
1535
0
        {
1536
0
            const OUString aId = xContentAccess->queryContentIdentifierString();
1537
0
            Content  aContent( aId, aCmdEnv, comphelper::getProcessComponentContext() );
1538
1539
0
            AddRegion( rGuard, xRow->getString( 1 ), aContent );
1540
0
        }
1541
0
    }
1542
0
    catch ( Exception& ) {}
1543
0
}
1544
1545
1546
bool SfxDocTemplate_Impl::Construct( )
1547
0
{
1548
0
    std::unique_lock aGuard( maMutex );
1549
1550
0
    if ( mbConstructed )
1551
0
        return true;
1552
1553
0
    const uno::Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
1554
1555
0
    mxInfo.set(document::DocumentProperties::create(xContext), UNO_QUERY);
1556
1557
0
    mxTemplates = frame::DocumentTemplates::create(xContext);
1558
1559
0
    uno::Reference< XLocalizable > xLocalizable( mxTemplates, UNO_QUERY );
1560
1561
0
    m_rCompareFactory = AnyCompareFactory::createWithLocale(xContext, xLocalizable->getLocale());
1562
1563
0
    uno::Reference < XContent > aRootContent = mxTemplates->getContent();
1564
0
    uno::Reference < XCommandEnvironment > aCmdEnv;
1565
1566
0
    if ( ! aRootContent.is() )
1567
0
        return false;
1568
1569
0
    mbConstructed = true;
1570
0
    maRootURL = aRootContent->getIdentifier()->getContentIdentifier();
1571
1572
0
    Content aTemplRoot( aRootContent, aCmdEnv, xContext );
1573
0
    CreateFromHierarchy( aGuard, aTemplRoot );
1574
1575
0
    return true;
1576
0
}
1577
1578
1579
void SfxDocTemplate_Impl::ReInitFromComponent()
1580
0
{
1581
0
    uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates();
1582
0
    if ( xTemplates.is() )
1583
0
    {
1584
0
        uno::Reference < XContent > aRootContent = xTemplates->getContent();
1585
0
        uno::Reference < XCommandEnvironment > aCmdEnv;
1586
0
        Content aTemplRoot( aRootContent, aCmdEnv, comphelper::getProcessComponentContext() );
1587
0
        Clear();
1588
0
        std::unique_lock aGuard(maMutex);
1589
0
        CreateFromHierarchy( aGuard, aTemplRoot );
1590
0
    }
1591
0
}
1592
1593
1594
bool SfxDocTemplate_Impl::InsertRegion( std::unique_ptr<RegionData_Impl> pNew, size_t nPos )
1595
0
{
1596
    // return false (not inserted) if the entry already exists
1597
0
    for (auto const& pRegion : maRegions)
1598
0
        if ( pRegion->Compare( pNew.get() ) == 0 )
1599
0
            return false;
1600
1601
0
    size_t newPos = nPos;
1602
0
    if ( pNew->GetTitle() == maStandardGroup )
1603
0
        newPos = 0;
1604
1605
0
    if ( newPos < maRegions.size() )
1606
0
    {
1607
0
        auto it = maRegions.begin();
1608
0
        std::advance( it, newPos );
1609
0
        maRegions.emplace( it, std::move(pNew) );
1610
0
    }
1611
0
    else
1612
0
        maRegions.emplace_back( std::move(pNew) );
1613
1614
0
    return true;
1615
0
}
1616
1617
1618
void SfxDocTemplate_Impl::Rescan()
1619
0
{
1620
0
    Clear();
1621
1622
0
    try
1623
0
    {
1624
0
        uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates();
1625
0
        DBG_ASSERT( xTemplates.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" );
1626
0
        if ( xTemplates.is() )
1627
0
        {
1628
0
            xTemplates->update();
1629
1630
0
            uno::Reference < XContent > aRootContent = xTemplates->getContent();
1631
0
            uno::Reference < XCommandEnvironment > aCmdEnv;
1632
1633
0
            Content aTemplRoot( aRootContent, aCmdEnv, comphelper::getProcessComponentContext() );
1634
0
            std::unique_lock aGuard(maMutex);
1635
0
            CreateFromHierarchy( aGuard, aTemplRoot );
1636
0
        }
1637
0
    }
1638
0
    catch( const Exception& )
1639
0
    {
1640
0
        TOOLS_WARN_EXCEPTION( "sfx.doc", "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update" );
1641
0
    }
1642
0
}
1643
1644
1645
bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString& rURL,
1646
                                           OUString& aTitle )
1647
0
{
1648
0
    if ( mxInfo.is() )
1649
0
    {
1650
0
        try
1651
0
        {
1652
0
            mxInfo->read( rURL );
1653
0
        }
1654
0
        catch ( Exception& )
1655
0
        {
1656
            // the document is not a StarOffice document
1657
0
            return false;
1658
0
        }
1659
1660
1661
0
        try
1662
0
        {
1663
0
            uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY );
1664
0
            if ( aPropSet.is() )
1665
0
            {
1666
0
                Any aValue = aPropSet->getPropertyValue( TITLE );
1667
0
                aValue >>= aTitle;
1668
0
            }
1669
0
        }
1670
0
        catch ( IOException& ) {}
1671
0
        catch ( UnknownPropertyException& ) {}
1672
0
        catch ( Exception& ) {}
1673
0
    }
1674
1675
0
    if ( aTitle.isEmpty() )
1676
0
    {
1677
0
        INetURLObject aURL( rURL );
1678
0
        aURL.CutExtension();
1679
0
        aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true,
1680
0
                               INetURLObject::DecodeMechanism::WithCharset );
1681
0
    }
1682
1683
0
    return true;
1684
0
}
1685
1686
1687
void SfxDocTemplate_Impl::Clear()
1688
0
{
1689
0
    std::unique_lock aGuard( maMutex );
1690
0
    if ( mnLockCounter )
1691
0
        return;
1692
0
    maRegions.clear();
1693
0
}
1694
1695
1696
bool getTextProperty_Impl( Content& rContent,
1697
                               const OUString& rPropName,
1698
                               OUString& rPropValue )
1699
0
{
1700
0
    bool bGotProperty = false;
1701
1702
    // Get the property
1703
0
    try
1704
0
    {
1705
0
        uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties();
1706
1707
        // check, whether or not the property exists
1708
0
        if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) )
1709
0
        {
1710
0
            return false;
1711
0
        }
1712
1713
        // now get the property
1714
0
        Any aAnyValue = rContent.getPropertyValue( rPropName );
1715
0
        aAnyValue >>= rPropValue;
1716
1717
0
        if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) )
1718
0
        {
1719
0
            SfxURLRelocator_Impl aRelocImpl( ::comphelper::getProcessComponentContext() );
1720
0
            aRelocImpl.makeAbsoluteURL( rPropValue );
1721
0
        }
1722
1723
0
        bGotProperty = true;
1724
0
    }
1725
0
    catch ( RuntimeException& ) {}
1726
0
    catch ( Exception& ) {}
1727
1728
0
    return bGotProperty;
1729
0
}
1730
1731
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */