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