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