Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/ucb/source/ucp/hierarchy/hierarchydata.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
/**************************************************************************
22
                                TODO
23
 **************************************************************************
24
25
 - HierarchyEntry::move
26
   --> Rewrite to use XNamed ( once this is supported by config db api ).
27
28
 *************************************************************************/
29
#include "hierarchydata.hxx"
30
31
#include <comphelper/diagnose_ex.hxx>
32
#include <rtl/ustrbuf.hxx>
33
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
34
#include <com/sun/star/container/XNameContainer.hpp>
35
#include <com/sun/star/container/XNameReplace.hpp>
36
#include <com/sun/star/util/XChangesBatch.hpp>
37
#include <com/sun/star/util/XOfficeInstallationDirectories.hpp>
38
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
39
#include <comphelper/propertysequence.hxx>
40
#include <utility>
41
#include "hierarchyprovider.hxx"
42
#include "hierarchyuri.hxx"
43
44
using namespace com::sun::star;
45
46
namespace hierarchy_ucp
47
{
48
49
50
static void makeXMLName( std::u16string_view rIn, OUStringBuffer & rBuffer  )
51
0
{
52
0
    size_t nCount = rIn.size();
53
0
    for ( size_t n = 0; n < nCount; ++n )
54
0
    {
55
0
        const sal_Unicode c = rIn[ n ];
56
0
        switch ( c )
57
0
        {
58
0
            case '&':
59
0
                rBuffer.append( "&amp;" );
60
0
                break;
61
62
0
            case '"':
63
0
                rBuffer.append( "&quot;" );
64
0
                break;
65
66
0
            case '\'':
67
0
                rBuffer.append( "&apos;" );
68
0
                break;
69
70
0
            case '<':
71
0
                rBuffer.append( "&lt;" );
72
0
                break;
73
74
0
            case '>':
75
0
                rBuffer.append( "&gt;" );
76
0
                break;
77
78
0
            default:
79
0
                rBuffer.append( c );
80
0
                break;
81
0
        }
82
0
    }
83
0
}
84
85
86
// HierarchyEntry Implementation.
87
88
89
constexpr OUStringLiteral READ_SERVICE_NAME = u"com.sun.star.ucb.HierarchyDataReadAccess";
90
constexpr OUString READWRITE_SERVICE_NAME = u"com.sun.star.ucb.HierarchyDataReadWriteAccess"_ustr;
91
92
// describe path of cfg entry
93
constexpr OUString CFGPROPERTY_NODEPATH = u"nodepath"_ustr;
94
95
96
HierarchyEntry::HierarchyEntry(
97
                uno::Reference< uno::XComponentContext > xContext,
98
                HierarchyContentProvider* pProvider,
99
                const OUString& rURL )
100
0
: m_xContext(std::move( xContext )),
101
0
  m_xOfficeInstDirs( pProvider->getOfficeInstallationDirectories() ),
102
0
  m_bTriedToGetRootReadAccess( false )
103
0
{
104
0
    HierarchyUri aUri( rURL );
105
0
    m_aServiceSpecifier = aUri.getService();
106
107
0
    m_xConfigProvider
108
0
        = pProvider->getConfigProvider( m_aServiceSpecifier );
109
0
    m_xRootReadAccess
110
0
        = pProvider->getRootConfigReadNameAccess( m_aServiceSpecifier );
111
112
    // Note: do not init m_aPath in init list. createPathFromHierarchyURL
113
    //       needs m_xContext and m_aMutex.
114
0
    m_aPath = createPathFromHierarchyURL( aUri );
115
116
    // Extract language independent name from URL.
117
0
    sal_Int32 nPos = rURL.lastIndexOf( '/' );
118
0
    if ( nPos > HIERARCHY_URL_SCHEME_LENGTH )
119
0
        m_aName = rURL.copy( nPos + 1 );
120
0
    else
121
0
        OSL_FAIL( "HierarchyEntry - Invalid URL!" );
122
0
}
123
124
125
bool HierarchyEntry::hasData()
126
0
{
127
0
    uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
128
0
        = getRootReadAccess();
129
130
0
    OSL_ENSURE( xRootReadAccess.is(), "HierarchyEntry::hasData - No root!" );
131
132
0
    if ( xRootReadAccess.is() )
133
0
        return xRootReadAccess->hasByHierarchicalName( m_aPath );
134
135
0
    return false;
136
0
}
137
138
139
bool HierarchyEntry::getData( HierarchyEntryData& rData )
140
0
{
141
0
    try
142
0
    {
143
0
        uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
144
0
            = getRootReadAccess();
145
146
0
        OSL_ENSURE( xRootReadAccess.is(),
147
0
                    "HierarchyEntry::getData - No root!" );
148
149
0
        if ( xRootReadAccess.is() )
150
0
        {
151
0
            OUString aTitlePath = m_aPath + "/Title";
152
153
            // Note: Avoid NoSuchElementExceptions, because exceptions are
154
            //       relatively 'expensive'. Checking for availability of
155
            //       title value is sufficient here, because if it is
156
            //       there, the other values will be available too.
157
0
            if ( !xRootReadAccess->hasByHierarchicalName( aTitlePath ) )
158
0
                return false;
159
160
0
            OUString aValue;
161
162
            // Get Title value.
163
0
            if ( !( xRootReadAccess->getByHierarchicalName( aTitlePath )
164
0
                    >>= aValue ) )
165
0
            {
166
0
                OSL_FAIL( "HierarchyEntry::getData - "
167
0
                            "Got no Title value!" );
168
0
                return false;
169
0
            }
170
171
0
            rData.setTitle( aValue );
172
173
            // Get TargetURL value.
174
0
            OUString aTargetURLPath = m_aPath + "/TargetURL";
175
0
            if ( !( xRootReadAccess->getByHierarchicalName( aTargetURLPath )
176
0
                    >>= aValue ) )
177
0
            {
178
0
                OSL_FAIL( "HierarchyEntry::getData - "
179
0
                            "Got no TargetURL value!" );
180
0
                return false;
181
0
            }
182
183
            // TargetURL property may contain a reference to the Office
184
            // installation directory. To ensure a reloctable office
185
            // installation, the path to the office installation directory must
186
            // never be stored directly. A placeholder is used instead. Replace
187
            // it by actual installation directory.
188
0
            if ( m_xOfficeInstDirs.is() &&  !aValue.isEmpty()  )
189
0
                aValue = m_xOfficeInstDirs->makeAbsoluteURL( aValue );
190
0
            rData.setTargetURL( aValue );
191
192
0
            OUString aTypePath = m_aPath + "/Type";
193
0
            if ( xRootReadAccess->hasByHierarchicalName( aTypePath ) )
194
0
            {
195
                // Might not be present since it was introduced long after
196
                // Title and TargetURL (#82433#)... So not getting it is
197
                // not an error.
198
199
                // Get Type value.
200
0
                sal_Int32 nType = 0;
201
0
                if ( xRootReadAccess->getByHierarchicalName( aTypePath )
202
0
                     >>= nType )
203
0
                {
204
0
                    if ( nType == 0 )
205
0
                    {
206
0
                        rData.setType( HierarchyEntryData::LINK );
207
0
                    }
208
0
                    else if ( nType == 1 )
209
0
                    {
210
0
                        rData.setType( HierarchyEntryData::FOLDER );
211
0
                    }
212
0
                    else
213
0
                    {
214
0
                        OSL_FAIL( "HierarchyEntry::getData - "
215
0
                                    "Unknown Type value!" );
216
0
                        return false;
217
0
                    }
218
0
                }
219
0
            }
220
221
0
            rData.setName( m_aName );
222
0
            return true;
223
0
        }
224
0
    }
225
0
    catch ( uno::RuntimeException const & )
226
0
    {
227
0
        throw;
228
0
    }
229
0
    catch ( container::NoSuchElementException const & )
230
0
    {
231
        // getByHierarchicalName
232
233
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
234
0
    }
235
0
    return false;
236
0
}
237
238
239
bool HierarchyEntry::setData( const HierarchyEntryData& rData )
240
0
{
241
0
    try
242
0
    {
243
0
        std::unique_lock aGuard( m_aMutex );
244
245
0
        if ( !m_xConfigProvider.is() )
246
0
            m_xConfigProvider.set(
247
0
                m_xContext->getServiceManager()->createInstanceWithContext(m_aServiceSpecifier, m_xContext),
248
0
                uno::UNO_QUERY );
249
250
0
        if ( m_xConfigProvider.is() )
251
0
        {
252
            // Create parent's key. It must exist!
253
254
0
            OUString aParentPath;
255
0
            bool bRoot = true;
256
257
0
            sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
258
0
            if ( nPos != -1 )
259
0
            {
260
                // Skip "/Children" segment of the path, too.
261
0
                nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
262
263
0
                OSL_ENSURE( nPos != -1,
264
0
                            "HierarchyEntry::setData - Wrong path!" );
265
266
0
                aParentPath += m_aPath.subView( 0, nPos );
267
0
                bRoot = false;
268
0
            }
269
270
0
            uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
271
0
            {
272
0
                {CFGPROPERTY_NODEPATH, uno::Any(aParentPath)}
273
0
            }));
274
275
0
            uno::Reference< util::XChangesBatch > xBatch(
276
0
                    m_xConfigProvider->createInstanceWithArguments(
277
0
                        READWRITE_SERVICE_NAME,
278
0
                        aArguments ),
279
0
                    uno::UNO_QUERY );
280
281
0
            OSL_ENSURE( xBatch.is(),
282
0
                        "HierarchyEntry::setData - No batch!" );
283
284
0
            uno::Reference< container::XNameAccess > xParentNameAccess(
285
0
                xBatch, uno::UNO_QUERY );
286
287
0
            OSL_ENSURE( xParentNameAccess.is(),
288
0
                        "HierarchyEntry::setData - No name access!" );
289
290
0
            if ( xBatch.is() && xParentNameAccess.is() )
291
0
            {
292
                // Try to create own key. It must not exist!
293
294
0
                bool bExists = true;
295
0
                uno::Any aMyKey;
296
297
0
                try
298
0
                {
299
0
                    uno::Reference< container::XNameAccess > xNameAccess;
300
301
0
                    if ( bRoot )
302
0
                    {
303
0
                        xNameAccess = xParentNameAccess;
304
0
                    }
305
0
                    else
306
0
                    {
307
0
                        xParentNameAccess->getByName(u"Children"_ustr) >>= xNameAccess;
308
0
                    }
309
310
0
                    if ( xNameAccess->hasByName( m_aName ) )
311
0
                        aMyKey = xNameAccess->getByName( m_aName );
312
0
                    else
313
0
                        bExists = false;
314
0
                }
315
0
                catch ( container::NoSuchElementException const & )
316
0
                {
317
0
                    bExists = false;
318
0
                }
319
320
0
                uno::Reference< container::XNameReplace >   xNameReplace;
321
0
                uno::Reference< container::XNameContainer > xContainer;
322
323
0
                if ( bExists )
324
0
                {
325
                    // Key exists. Replace values.
326
327
0
                    aMyKey >>= xNameReplace;
328
329
0
                    OSL_ENSURE( xNameReplace.is(),
330
0
                                "HierarchyEntry::setData - No name replace!" );
331
0
                }
332
0
                else
333
0
                {
334
                    // Key does not exist. Create / fill / insert it.
335
336
0
                    uno::Reference< lang::XSingleServiceFactory > xFac;
337
338
0
                    if ( bRoot )
339
0
                    {
340
                        // Special handling for children of root,
341
                        // which is not an entry. It's only a set
342
                        // of entries.
343
0
                        xFac.set( xParentNameAccess, uno::UNO_QUERY );
344
0
                    }
345
0
                    else
346
0
                    {
347
                        // Append new entry to parents child list,
348
                        // which is a set of entries.
349
0
                        xParentNameAccess->getByName(u"Children"_ustr) >>= xFac;
350
0
                    }
351
352
0
                    OSL_ENSURE( xFac.is(),
353
0
                                "HierarchyEntry::setData - No factory!" );
354
355
0
                    if ( xFac.is() )
356
0
                    {
357
0
                        xNameReplace.set( xFac->createInstance(), uno::UNO_QUERY );
358
359
0
                        OSL_ENSURE( xNameReplace.is(),
360
0
                                "HierarchyEntry::setData - No name replace!" );
361
362
0
                        if ( xNameReplace.is() )
363
0
                        {
364
0
                            xContainer.set( xFac, uno::UNO_QUERY );
365
366
0
                            OSL_ENSURE( xContainer.is(),
367
0
                                "HierarchyEntry::setData - No container!" );
368
0
                        }
369
0
                    }
370
0
                }
371
372
0
                if ( xNameReplace.is() )
373
0
                {
374
                    // Set Title value.
375
0
                    xNameReplace->replaceByName(
376
0
                        u"Title"_ustr,
377
0
                        uno::Any( rData.getTitle() ) );
378
379
                    // Set TargetURL value.
380
381
                    // TargetURL property may contain a reference to the Office
382
                    // installation directory. To ensure a reloctable office
383
                    // installation, the path to the office installation
384
                    // directory must never be stored directly. Use a
385
                    // placeholder instead.
386
0
                    OUString aValue( rData.getTargetURL() );
387
0
                    if ( m_xOfficeInstDirs.is() &&  !aValue.isEmpty() )
388
0
                        aValue
389
0
                            = m_xOfficeInstDirs->makeRelocatableURL( aValue );
390
391
0
                    xNameReplace->replaceByName(
392
0
                        u"TargetURL"_ustr,
393
0
                        uno::Any( aValue ) );
394
395
                    // Set Type value.
396
0
                    sal_Int32 nType
397
0
                        = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
398
0
                    xNameReplace->replaceByName(
399
0
                        u"Type"_ustr,
400
0
                        uno::Any( nType ) );
401
402
0
                    if ( xContainer.is() )
403
0
                        xContainer->insertByName(
404
0
                            m_aName, uno::Any( xNameReplace ) );
405
406
                    // Commit changes.
407
0
                    xBatch->commitChanges();
408
0
                    return true;
409
0
                }
410
0
            }
411
0
        }
412
0
    }
413
0
    catch ( lang::IllegalArgumentException const & )
414
0
    {
415
        // replaceByName, insertByName
416
417
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
418
0
    }
419
0
    catch ( uno::RuntimeException const & )
420
0
    {
421
0
        throw;
422
0
    }
423
0
    catch ( container::NoSuchElementException const & )
424
0
    {
425
        // replaceByName, getByName
426
427
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
428
0
    }
429
0
    catch ( container::ElementExistException const & )
430
0
    {
431
        // insertByName
432
433
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
434
0
    }
435
0
    catch ( lang::WrappedTargetException const & )
436
0
    {
437
        // replaceByName, insertByName, getByName, commitChanges
438
439
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
440
0
    }
441
0
    catch ( uno::Exception const & )
442
0
    {
443
        // createInstance, createInstanceWithArguments
444
445
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
446
0
    }
447
448
0
    return false;
449
0
}
450
451
452
bool HierarchyEntry::move(
453
    const OUString& rNewURL, const HierarchyEntryData& rData )
454
0
{
455
0
    OUString aNewPath = createPathFromHierarchyURL( HierarchyUri(rNewURL) );
456
457
0
    std::unique_lock aGuard( m_aMutex );
458
459
0
    if ( aNewPath == m_aPath )
460
0
        return true;
461
462
0
    bool bOldRoot = true;
463
0
    uno::Reference< util::XChangesBatch > xOldParentBatch;
464
465
0
    OUString aNewKey;
466
0
    sal_Int32 nURLPos = rNewURL.lastIndexOf( '/' );
467
0
    if ( nURLPos > HIERARCHY_URL_SCHEME_LENGTH )
468
0
        aNewKey = rNewURL.copy( nURLPos + 1 );
469
0
    else
470
0
    {
471
0
        OSL_FAIL( "HierarchyEntry::move - Invalid URL!" );
472
0
        return false;
473
0
    }
474
475
0
    bool bNewRoot = true;
476
0
    uno::Reference< util::XChangesBatch > xNewParentBatch;
477
478
0
    bool bDifferentParents = true;
479
480
0
    try
481
0
    {
482
0
        if ( !m_xConfigProvider.is() )
483
0
            m_xConfigProvider.set(
484
0
                m_xContext->getServiceManager()->createInstanceWithContext(m_aServiceSpecifier, m_xContext),
485
0
                uno::UNO_QUERY );
486
487
0
        if ( !m_xConfigProvider.is() )
488
0
            return false;
489
490
0
        OUString aOldParentPath;
491
0
        sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
492
0
        if ( nPos != -1 )
493
0
        {
494
            // Skip "/Children" segment of the path, too.
495
0
            nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
496
497
0
            OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
498
499
0
            aOldParentPath += m_aPath.subView( 0, nPos );
500
0
            bOldRoot = false;
501
0
        }
502
503
0
        OUString aNewParentPath;
504
0
        nPos = aNewPath.lastIndexOf( '/' );
505
0
        if ( nPos != -1 )
506
0
        {
507
            // Skip "/Children" segment of the path, too.
508
0
            nPos = aNewPath.lastIndexOf( '/', nPos - 1 );
509
510
0
            OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
511
512
0
            aNewParentPath += aNewPath.subView( 0, nPos );
513
0
            bNewRoot = false;
514
0
        }
515
516
0
        uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
517
0
        {
518
0
            {CFGPROPERTY_NODEPATH, uno::Any(aOldParentPath)}
519
0
        }));
520
521
0
        xOldParentBatch.set(
522
0
            m_xConfigProvider->createInstanceWithArguments(
523
0
                READWRITE_SERVICE_NAME,
524
0
                aArguments ),
525
0
            uno::UNO_QUERY );
526
527
0
        OSL_ENSURE( xOldParentBatch.is(), "HierarchyEntry::move - No batch!" );
528
529
0
        if ( !xOldParentBatch.is() )
530
0
            return false;
531
532
0
        if ( aOldParentPath == aNewParentPath )
533
0
        {
534
0
            bDifferentParents = false;
535
0
            xNewParentBatch = xOldParentBatch;
536
0
        }
537
0
        else
538
0
        {
539
0
            uno::Sequence<uno::Any> aArguments2(comphelper::InitAnyPropertySequence(
540
0
            {
541
0
                {CFGPROPERTY_NODEPATH, uno::Any(aNewParentPath)}
542
0
            }));
543
544
0
            xNewParentBatch.set(
545
0
                m_xConfigProvider->createInstanceWithArguments(
546
0
                    READWRITE_SERVICE_NAME,
547
0
                    aArguments2 ),
548
0
                uno::UNO_QUERY );
549
550
0
            OSL_ENSURE(
551
0
                xNewParentBatch.is(), "HierarchyEntry::move - No batch!" );
552
553
0
            if ( !xNewParentBatch.is() )
554
0
                return false;
555
0
        }
556
0
    }
557
0
    catch ( uno::RuntimeException const & )
558
0
    {
559
0
        throw;
560
0
    }
561
0
    catch ( uno::Exception const & )
562
0
    {
563
        // createInstance, createInstanceWithArguments
564
565
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
566
0
        return false;
567
0
    }
568
569
570
    // (1) Get entry...
571
572
573
0
    uno::Any aEntry;
574
0
    uno::Reference< container::XNameAccess >    xOldParentNameAccess;
575
0
    uno::Reference< container::XNameContainer > xOldNameContainer;
576
577
0
    try
578
0
    {
579
0
        xOldParentNameAccess.set( xOldParentBatch, uno::UNO_QUERY );
580
581
0
        OSL_ENSURE( xOldParentNameAccess.is(),
582
0
                    "HierarchyEntry::move - No name access!" );
583
584
0
        if ( !xOldParentNameAccess.is() )
585
0
            return false;
586
587
0
        if ( bOldRoot )
588
0
        {
589
0
            xOldNameContainer.set( xOldParentNameAccess, uno::UNO_QUERY );
590
0
        }
591
0
        else
592
0
        {
593
0
            xOldParentNameAccess->getByName(u"Children"_ustr) >>= xOldNameContainer;
594
0
        }
595
596
0
        aEntry = xOldNameContainer->getByName( m_aName );
597
0
    }
598
0
    catch ( container::NoSuchElementException const & )
599
0
    {
600
        // getByName
601
602
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
603
0
        return false;
604
0
    }
605
0
    catch ( lang::WrappedTargetException const & )
606
0
    {
607
        // getByName
608
609
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
610
0
        return false;
611
0
    }
612
613
614
    // (2) Remove entry... Note: Insert BEFORE remove does not work!
615
616
617
0
    try
618
0
    {
619
0
        xOldNameContainer->removeByName( m_aName );
620
0
        xOldParentBatch->commitChanges();
621
0
    }
622
0
    catch ( container::NoSuchElementException const & )
623
0
    {
624
        // getByName, removeByName
625
626
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
627
0
        return false;
628
0
    }
629
630
631
    // (3) Insert entry at new parent...
632
633
634
0
    try
635
0
    {
636
0
        uno::Reference< container::XNameReplace > xNewNameReplace;
637
0
        aEntry >>= xNewNameReplace;
638
639
0
        OSL_ENSURE( xNewNameReplace.is(),
640
0
                    "HierarchyEntry::move - No name replace!" );
641
642
0
        if ( !xNewNameReplace.is() )
643
0
            return false;
644
645
0
        uno::Reference< container::XNameAccess > xNewParentNameAccess;
646
0
        if ( bDifferentParents )
647
0
            xNewParentNameAccess.set( xNewParentBatch, uno::UNO_QUERY );
648
0
        else
649
0
            xNewParentNameAccess = std::move(xOldParentNameAccess);
650
651
0
        OSL_ENSURE( xNewParentNameAccess.is(),
652
0
                    "HierarchyEntry::move - No name access!" );
653
654
0
        if ( !xNewParentNameAccess.is() )
655
0
            return false;
656
657
0
        uno::Reference< container::XNameContainer > xNewNameContainer;
658
0
        if ( bDifferentParents )
659
0
        {
660
0
            if ( bNewRoot )
661
0
            {
662
0
                xNewNameContainer.set( xNewParentNameAccess, uno::UNO_QUERY );
663
0
            }
664
0
            else
665
0
            {
666
0
                xNewParentNameAccess->getByName(u"Children"_ustr) >>= xNewNameContainer;
667
0
            }
668
0
        }
669
0
        else
670
0
            xNewNameContainer = std::move(xOldNameContainer);
671
672
0
        if ( !xNewNameContainer.is() )
673
0
            return false;
674
675
0
        xNewNameReplace->replaceByName(
676
0
            u"Title"_ustr,
677
0
            uno::Any( rData.getTitle() ) );
678
679
        // TargetURL property may contain a reference to the Office
680
        // installation directory. To ensure a reloctable office
681
        // installation, the path to the office installation
682
        // directory must never be stored directly. Use a placeholder
683
        // instead.
684
0
        OUString aValue( rData.getTargetURL() );
685
0
        if ( m_xOfficeInstDirs.is() &&  !aValue.isEmpty() )
686
0
            aValue = m_xOfficeInstDirs->makeRelocatableURL( aValue );
687
0
        xNewNameReplace->replaceByName(
688
0
            u"TargetURL"_ustr,
689
0
            uno::Any( aValue ) );
690
0
        sal_Int32 nType = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
691
0
        xNewNameReplace->replaceByName(
692
0
            u"Type"_ustr,
693
0
            uno::Any( nType ) );
694
695
0
        xNewNameContainer->insertByName( aNewKey, aEntry );
696
0
        xNewParentBatch->commitChanges();
697
0
    }
698
0
    catch ( container::NoSuchElementException const & )
699
0
    {
700
        // replaceByName, insertByName, getByName
701
702
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
703
0
        return false;
704
0
    }
705
0
    catch ( lang::IllegalArgumentException const & )
706
0
    {
707
        // replaceByName, insertByName
708
709
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
710
0
        return false;
711
0
    }
712
0
    catch ( container::ElementExistException const & )
713
0
    {
714
        // insertByName
715
716
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
717
0
        return false;
718
0
    }
719
0
    catch ( lang::WrappedTargetException const & )
720
0
    {
721
        // replaceByName, insertByName, getByName
722
723
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
724
0
        return false;
725
0
    }
726
727
0
    return true;
728
0
}
729
730
731
bool HierarchyEntry::remove()
732
0
{
733
0
    try
734
0
    {
735
0
        std::unique_lock aGuard( m_aMutex );
736
737
0
        if ( !m_xConfigProvider.is() )
738
0
            m_xConfigProvider.set(
739
0
                m_xContext->getServiceManager()->createInstanceWithContext(m_aServiceSpecifier, m_xContext),
740
0
                uno::UNO_QUERY );
741
742
0
        if ( m_xConfigProvider.is() )
743
0
        {
744
            // Create parent's key. It must exist!
745
746
0
            OUString aParentPath;
747
0
            bool bRoot = true;
748
749
0
            sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
750
0
            if ( nPos != -1 )
751
0
            {
752
                // Skip "/Children" segment of the path, too.
753
0
                nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
754
755
0
                OSL_ENSURE( nPos != -1,
756
0
                            "HierarchyEntry::remove - Wrong path!" );
757
758
0
                aParentPath += m_aPath.subView( 0, nPos );
759
0
                bRoot = false;
760
0
            }
761
762
0
            uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
763
0
            {
764
0
                {CFGPROPERTY_NODEPATH, uno::Any(aParentPath)}
765
0
            }));
766
767
0
            uno::Reference< util::XChangesBatch > xBatch(
768
0
                m_xConfigProvider->createInstanceWithArguments(
769
0
                    READWRITE_SERVICE_NAME,
770
0
                    aArguments ),
771
0
                uno::UNO_QUERY );
772
773
0
            OSL_ENSURE( xBatch.is(),
774
0
                        "HierarchyEntry::remove - No batch!" );
775
776
0
            uno::Reference< container::XNameAccess > xParentNameAccess(
777
0
                xBatch, uno::UNO_QUERY );
778
779
0
            OSL_ENSURE( xParentNameAccess.is(),
780
0
                        "HierarchyEntry::remove - No name access!" );
781
782
0
            if ( xBatch.is() && xParentNameAccess.is() )
783
0
            {
784
0
                uno::Reference< container::XNameContainer > xContainer;
785
786
0
                if ( bRoot )
787
0
                {
788
                    // Special handling for children of root,
789
                    // which is not an entry. It's only a set
790
                    // of entries.
791
0
                    xContainer.set( xParentNameAccess, uno::UNO_QUERY );
792
0
                }
793
0
                else
794
0
                {
795
                    // Append new entry to parents child list,
796
                    // which is a set of entries.
797
0
                     xParentNameAccess->getByName(u"Children"_ustr) >>= xContainer;
798
0
                }
799
800
0
                OSL_ENSURE( xContainer.is(),
801
0
                            "HierarchyEntry::remove - No container!" );
802
803
0
                if ( xContainer.is() )
804
0
                {
805
0
                    xContainer->removeByName( m_aName );
806
0
                    xBatch->commitChanges();
807
0
                    return true;
808
0
                }
809
0
            }
810
0
        }
811
0
    }
812
0
    catch ( uno::RuntimeException const & )
813
0
    {
814
0
        throw;
815
0
    }
816
0
    catch ( container::NoSuchElementException const & )
817
0
    {
818
        // getByName, removeByName
819
820
0
        OSL_FAIL(
821
0
            "HierarchyEntry::remove - caught NoSuchElementException!" );
822
0
    }
823
0
    catch ( lang::WrappedTargetException const & )
824
0
    {
825
        // getByName, commitChanges
826
827
0
        OSL_FAIL(
828
0
            "HierarchyEntry::remove - caught WrappedTargetException!" );
829
0
    }
830
0
    catch ( uno::Exception const & )
831
0
    {
832
        // createInstance, createInstanceWithArguments
833
834
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
835
0
    }
836
837
0
    return false;
838
0
}
839
840
841
bool HierarchyEntry::first( iterator & it )
842
0
{
843
0
    if ( it.pos == -1 )
844
0
    {
845
        // Init...
846
847
0
        try
848
0
        {
849
0
            uno::Reference< container::XHierarchicalNameAccess >
850
0
                xRootHierNameAccess = getRootReadAccess();
851
852
0
            if ( xRootHierNameAccess.is() )
853
0
            {
854
0
                uno::Reference< container::XNameAccess > xNameAccess;
855
856
0
                if ( !m_aPath.isEmpty() )
857
0
                {
858
0
                    OUString aPath = m_aPath + "/Children";
859
860
0
                    xRootHierNameAccess->getByHierarchicalName( aPath )
861
0
                        >>= xNameAccess;
862
0
                }
863
0
                else
864
0
                    xNameAccess.set( xRootHierNameAccess, uno::UNO_QUERY );
865
866
0
                OSL_ENSURE( xNameAccess.is(),
867
0
                            "HierarchyEntry::first - No name access!" );
868
869
0
                if ( xNameAccess.is() )
870
0
                    it.names = xNameAccess->getElementNames();
871
872
0
                uno::Reference< container::XHierarchicalNameAccess >
873
0
                    xHierNameAccess( xNameAccess, uno::UNO_QUERY );
874
875
0
                OSL_ENSURE( xHierNameAccess.is(),
876
0
                            "HierarchyEntry::first - No hier. name access!" );
877
878
0
                it.dir = std::move(xHierNameAccess);
879
880
0
                it.officeDirs = m_xOfficeInstDirs;
881
0
            }
882
0
        }
883
0
        catch ( uno::RuntimeException const & )
884
0
        {
885
0
            throw;
886
0
        }
887
0
        catch ( container::NoSuchElementException const& )
888
0
        {
889
            // getByHierarchicalName
890
891
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
892
0
        }
893
0
        catch ( uno::Exception const & )
894
0
        {
895
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
896
0
        }
897
0
    }
898
899
0
    if ( !it.names.hasElements() )
900
0
        return false;
901
902
0
    it.pos = 0;
903
0
    return true;
904
0
}
905
906
907
bool HierarchyEntry::next( iterator& it )
908
0
{
909
0
    if ( it.pos == -1 )
910
0
        return first( it );
911
912
0
    ++it.pos;
913
914
0
    return ( it.pos < it.names.getLength() );
915
0
}
916
917
918
OUString HierarchyEntry::createPathFromHierarchyURL(
919
    const HierarchyUri& rURI )
920
0
{
921
    // Transform path...
922
    // folder/subfolder/subsubfolder
923
    //      --> ['folder']/Children/['subfolder']/Children/['subsubfolder']
924
925
0
    const OUString aPath = rURI.getPath().copy( 1 ); // skip leading slash.
926
0
    sal_Int32 nLen = aPath.getLength();
927
928
0
    if ( nLen )
929
0
    {
930
0
        OUStringBuffer aNewPath( "['" );
931
932
0
        sal_Int32 nStart = 0;
933
0
        sal_Int32 nEnd   = aPath.indexOf( '/' );
934
935
0
        do
936
0
        {
937
0
            if ( nEnd == -1 )
938
0
                nEnd = nLen;
939
940
0
            OUString aToken = aPath.copy( nStart, nEnd - nStart );
941
0
            makeXMLName( aToken, aNewPath );
942
943
0
            if ( nEnd != nLen )
944
0
            {
945
0
                aNewPath.append( "']/Children/['" );
946
0
                nStart = nEnd + 1;
947
0
                nEnd   = aPath.indexOf( '/', nStart );
948
0
            }
949
0
            else
950
0
                aNewPath.append( "']" );
951
0
        }
952
0
        while ( nEnd != nLen );
953
954
0
        return aNewPath.makeStringAndClear();
955
0
    }
956
957
0
    return aPath;
958
0
}
959
960
961
uno::Reference< container::XHierarchicalNameAccess >
962
HierarchyEntry::getRootReadAccess()
963
0
{
964
0
    if ( !m_xRootReadAccess.is() )
965
0
    {
966
0
        std::unique_lock aGuard( m_aMutex );
967
0
        if ( !m_xRootReadAccess.is() )
968
0
        {
969
0
            if ( m_bTriedToGetRootReadAccess )
970
0
            {
971
0
                OSL_FAIL( "HierarchyEntry::getRootReadAccess - "
972
0
                            "Unable to read any config data! -> #82494#" );
973
0
                return uno::Reference< container::XHierarchicalNameAccess >();
974
0
            }
975
976
0
            try
977
0
            {
978
0
                if ( !m_xConfigProvider.is() )
979
0
                    m_xConfigProvider.set(
980
0
                            m_xContext->getServiceManager()->createInstanceWithContext(m_aServiceSpecifier, m_xContext),
981
0
                            uno::UNO_QUERY );
982
983
0
                if ( m_xConfigProvider.is() )
984
0
                {
985
                    // Create Root object.
986
987
0
                    uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
988
0
                    {
989
0
                        {CFGPROPERTY_NODEPATH, uno::Any(OUString())} // root path
990
0
                    }));
991
992
0
                    m_bTriedToGetRootReadAccess = true;
993
994
0
                    m_xRootReadAccess.set(
995
0
                            m_xConfigProvider->createInstanceWithArguments(
996
0
                                READ_SERVICE_NAME,
997
0
                                aArguments ),
998
0
                            uno::UNO_QUERY );
999
0
                }
1000
0
            }
1001
0
            catch ( uno::RuntimeException const & )
1002
0
            {
1003
0
                throw;
1004
0
            }
1005
0
            catch ( uno::Exception const & )
1006
0
            {
1007
                // createInstance, createInstanceWithArguments
1008
1009
0
                TOOLS_WARN_EXCEPTION("ucb.ucp", "");
1010
0
            }
1011
0
        }
1012
0
    }
1013
0
    return m_xRootReadAccess;
1014
0
}
1015
1016
1017
// HierarchyEntry::iterator Implementation.
1018
1019
1020
const HierarchyEntryData& HierarchyEntry::iterator::operator*()
1021
0
{
1022
0
    if ( ( pos != -1 )
1023
0
         && ( dir.is() )
1024
0
         && ( pos < names.getLength() ) )
1025
0
    {
1026
0
        try
1027
0
        {
1028
0
            OUStringBuffer aKey( "['" );
1029
0
            makeXMLName( names.getConstArray()[ pos ], aKey );
1030
0
            aKey.append( "']" );
1031
1032
0
            OUString aTitle     = aKey.makeStringAndClear();
1033
0
            OUString aTargetURL = aTitle;
1034
0
            OUString aType      = aTitle;
1035
1036
0
            aTitle     += "/Title";
1037
0
            aTargetURL += "/TargetURL";
1038
0
            aType      += "/Type";
1039
1040
0
            OUString aValue;
1041
0
            dir->getByHierarchicalName( aTitle ) >>= aValue;
1042
0
            entry.setTitle( aValue );
1043
1044
0
            dir->getByHierarchicalName( aTargetURL ) >>= aValue;
1045
1046
            // TargetURL property may contain a reference to the Office
1047
            // installation directory. To ensure a reloctable office
1048
            // installation, the path to the office installation directory must
1049
            // never be stored directly. A placeholder is used instead. Replace
1050
            // it by actual installation directory.
1051
0
            if ( officeDirs.is() && !aValue.isEmpty() )
1052
0
                aValue = officeDirs->makeAbsoluteURL( aValue );
1053
0
            entry.setTargetURL( aValue );
1054
1055
0
            if ( dir->hasByHierarchicalName( aType ) )
1056
0
            {
1057
                // Might not be present since it was introduced long
1058
                // after Title and TargetURL (#82433#)... So not getting
1059
                // it is not an error.
1060
1061
                // Get Type value.
1062
0
                sal_Int32 nType = 0;
1063
0
                if ( dir->getByHierarchicalName( aType ) >>= nType )
1064
0
                {
1065
0
                    if ( nType == 0 )
1066
0
                    {
1067
0
                        entry.setType( HierarchyEntryData::LINK );
1068
0
                    }
1069
0
                    else if ( nType == 1 )
1070
0
                    {
1071
0
                        entry.setType( HierarchyEntryData::FOLDER );
1072
0
                    }
1073
0
                    else
1074
0
                    {
1075
0
                        OSL_FAIL( "HierarchyEntry::getData - "
1076
0
                                    "Unknown Type value!" );
1077
0
                    }
1078
0
                }
1079
0
            }
1080
1081
0
            entry.setName(
1082
0
                names.getConstArray()[ pos ] );
1083
0
        }
1084
0
        catch ( container::NoSuchElementException const & )
1085
0
        {
1086
0
            entry = HierarchyEntryData();
1087
0
        }
1088
0
    }
1089
1090
0
    return entry;
1091
0
}
1092
1093
} // namespace hierarchy_ucp
1094
1095
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */