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