1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #ifndef _UNOTOOLS_CONFIGNODE_HXX_
24 #define _UNOTOOLS_CONFIGNODE_HXX_
25 
26 #include "unotools/unotoolsdllapi.h"
27 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/container/XNameContainer.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <com/sun/star/util/XChangesBatch.hpp>
32 #include <unotools/eventlisteneradapter.hxx>
33 
34 namespace comphelper
35 {
36     class ComponentContext;
37 }
38 
39 //........................................................................
40 namespace utl
41 {
42 //........................................................................
43 
44 	//========================================================================
45 	//= OConfigurationNode
46 	//========================================================================
47 	class OConfigurationTreeRoot;
48 	/** a small wrapper around a configuration node.<p/>
49 		Nodes in the terminology used herein are <em>inner</em> nodes of a configuration
50 		tree, which means <em>no leafs</em>.
51 	*/
52 	class UNOTOOLS_DLLPUBLIC OConfigurationNode : public ::utl::OEventListenerAdapter
53 	{
54 	private:
55 		::com::sun::star::uno::Reference< ::com::sun::star::container::XHierarchicalNameAccess >
56 					m_xHierarchyAccess;		/// accessing children grandchildren (mandatory interface of our UNO object)
57 		::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >
58 					m_xDirectAccess;		/// accessing children  (mandatory interface of our UNO object)
59 		::com::sun::star::uno::Reference< ::com::sun::star::container::XNameReplace >
60 					m_xReplaceAccess;		/// replacing child values
61 		::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
62 					m_xContainerAccess;		/// modifying set nodes  (optional interface of our UNO object)
63 		::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
64 					m_xDummy;
65 		sal_Bool	m_bEscapeNames;			/// escape names before accessing children ?
66 
67 		::rtl::OUString
68 					m_sCompletePath;
69 
70 		OConfigurationNode  insertNode(const ::rtl::OUString& _rName,const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xNode) const throw();
71 
72     protected:
73 		/// constructs a node object with an interface representing a node
74 		OConfigurationNode(
75 			const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxNode
76         );
77 
78         const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >&
getUNONode() const79             getUNONode() const { return m_xDirectAccess; }
80 
81 	public:
82 		/// constructs an empty and invalid node object
OConfigurationNode()83 		OConfigurationNode() :m_bEscapeNames(sal_False) { }
84 		/// copy ctor
85 		OConfigurationNode(const OConfigurationNode& _rSource);
86 
87 		/// assigment
88 		const OConfigurationNode& operator=(const OConfigurationNode& _rSource);
89 
90 		/// dtor
~OConfigurationNode()91 		~OConfigurationNode() {}
92 
93         /// returns the local name of the node
94         ::rtl::OUString     getLocalName() const;
95 
96         /// returns the fully qualified path of the node
97         ::rtl::OUString     getNodePath() const;
98 
99 		/** open a sub node
100 			@param		_rPath		access path of the to-be-opened sub node. May be a hierarchical path.
101 		*/
102 		OConfigurationNode	openNode(const ::rtl::OUString& _rPath) const throw();
103 
openNode(const sal_Char * _pAsciiPath) const104         OConfigurationNode	openNode( const sal_Char* _pAsciiPath ) const
105         {
106             return openNode( ::rtl::OUString::createFromAscii( _pAsciiPath ) );
107         }
108 
109 		/** create a new child node
110 
111 			If the object represents a set node, this method may be used to create a new child. For non-set-nodes, the
112 			method will fail.<br/>
113 			Unless the respective operations on the pure configuration API, the to-be-created node immediately
114 			becomes a part of it's hierarchy, no explicit insertion is necessary.
115 			@param		_rName		name for the new child. Must be level-1-depth.
116 		*/
117 		OConfigurationNode	createNode(const ::rtl::OUString& _rName) const throw();
118 
createNode(const sal_Char * _pAsciiName) const119 		OConfigurationNode	createNode( const sal_Char* _pAsciiName ) const
120         {
121             return createNode( ::rtl::OUString::createFromAscii( _pAsciiName ) );
122         }
123 
124         /** appends a node under a new name
125 
126 			If the object represents a set node, this method may be used to create a new child. For non-set-nodes, the
127 			method will fail.<br/>
128 			Unless the respective operations on the pure configuration API, the to-be-created node immediately
129 			becomes a part of it's hierarchy, no explicit insertion is necessary.
130 			@param		_rName		name for the new child. Must be level-1-depth.
131 			@param		_aNewNode	the node which should be appended
132 		*/
133 		OConfigurationNode  appendNode(const ::rtl::OUString& _rName,const OConfigurationNode& _aNewNode) const throw();
134 
appendNode(const sal_Char * _pAsciiName,const OConfigurationNode & _aNewNode) const135 		OConfigurationNode  appendNode( const sal_Char* _pAsciiName, const OConfigurationNode& _aNewNode ) const
136         {
137             return appendNode( ::rtl::OUString::createFromAscii( _pAsciiName ), _aNewNode );
138         }
139 
140 		/** remove an existent child nod
141 
142             If the object represents a set node, this method may be used to delete an existent child. For non-set-nodes,
143 			the method will fail.
144 		*/
145 		sal_Bool			removeNode(const ::rtl::OUString& _rName) const throw();
146 
removeNode(const sal_Char * _pAsciiName) const147 		sal_Bool			removeNode( const sal_Char* _pAsciiName ) const
148         {
149             return removeNode( ::rtl::OUString::createFromAscii( _pAsciiName ) );
150         }
151 
152 		/** retrieves the content of a descendant
153 
154             the returned value may contain anything from an interface (if <arg>_rPath</arg> refers to inner node of
155 			the configuration tree) to any explicit value (e.g. string, integer) or even void.<br/>
156 			Unfortunately, this implies that if a void value is returned, you won't have a clue if this means
157 			"the path does not exist" (besides the assertion made :), or if the value is really void.
158 		*/
159 		::com::sun::star::uno::Any
160 							getNodeValue(const ::rtl::OUString& _rPath) const throw();
161 
162         ::com::sun::star::uno::Any
getNodeValue(const sal_Char * _pAsciiPath) const163                             getNodeValue( const sal_Char* _pAsciiPath ) const
164         {
165             return getNodeValue( ::rtl::OUString::createFromAscii( _pAsciiPath ) );
166         }
167 
168 		/** write a node value<p/>
169 			The value given is written into the node specified by the given relative path.<br/>
170 			In opposite to <method>getNodeValue</method>, _rName must refer to a leaf in the configuration tree, not an inner
171 			node.
172 			@return		sal_True if and only if the write was successfull.
173 		*/
174 		sal_Bool			setNodeValue(const ::rtl::OUString& _rPath, const ::com::sun::star::uno::Any& _rValue) const throw();
175 
setNodeValue(const sal_Char * _pAsciiPath,const::com::sun::star::uno::Any & _rValue) const176 		sal_Bool			setNodeValue( const sal_Char* _pAsciiPath, const ::com::sun::star::uno::Any& _rValue ) const
177         {
178             return setNodeValue( ::rtl::OUString::createFromAscii( _pAsciiPath ), _rValue );
179         }
180 
181 		/// return the names of the existing children
182 		::com::sun::star::uno::Sequence< ::rtl::OUString >
183 							getNodeNames() const throw();
184 
185 		/** enables or disables name escaping when accessing direct children<p/>
186 			Escaping is disabled by default, usually you enable it for set nodes (e.g. with calling setEscape(isSetNode)).
187 			Once escaping is enabled, you should not access indirect children (e.g. openNode("child/grandchild"), 'cause
188 			escaping for such names may not be supported by the underlying API objects.
189 			@see getEscape
190 		*/
191 		void		setEscape(sal_Bool _bEnable = sal_True);
192 		/** get the flag specifying the current escape behaviour
193 			@see setEscape
194 		*/
getEscape() const195 		sal_Bool	getEscape() const { return m_bEscapeNames; }
196 
197 		/// invalidate the object
198 		virtual void clear() throw();
199 
200 	    // -----------------------
201 	    // meta informations about the node
202 
203         /// checks whether or not the object represents a set node.
204 		sal_Bool isSetNode() const;
205 
206         /// checks whether or not a direct child with a given name exists
207 		sal_Bool hasByName(const ::rtl::OUString& _rName) const throw();
hasByName(const sal_Char * _pAsciiName) const208         sal_Bool hasByName( const sal_Char* _pAsciiName ) const { return hasByName( ::rtl::OUString::createFromAscii( _pAsciiName ) ); }
209 
210         /// checks whether or not a descendent (no matter if direct or indirect) with the given name exists
211 		sal_Bool hasByHierarchicalName( const ::rtl::OUString& _rName ) const throw();
hasByHierarchicalName(const sal_Char * _pAsciiName) const212         sal_Bool hasByHierarchicalName( const sal_Char* _pAsciiName ) const { return hasByHierarchicalName( ::rtl::OUString::createFromAscii( _pAsciiName ) ); }
213 
214         /// check if the objects represents a valid configuration node
isValid() const215 		sal_Bool isValid() const { return m_xHierarchyAccess.is(); }
216 
217         /// check whether the object is read-only of updatable
isReadonly() const218 		sal_Bool isReadonly() const { return !m_xReplaceAccess.is(); }
219 
220 	protected:
221 		// OEventListenerAdapter
222 		virtual void _disposing( const ::com::sun::star::lang::EventObject& _rSource );
223 
224 	protected:
225 		enum NAMEORIGIN
226 		{
227 			NO_CONFIGURATION,		/// the name came from a configuration node
228 			NO_CALLER				/// the name came from a client of this class
229 		};
230 		::rtl::OUString normalizeName(const ::rtl::OUString& _rName, NAMEORIGIN _eOrigin) const;
231 	};
232 
233 	//========================================================================
234 	//= OConfigurationTreeRoot
235 	//========================================================================
236 	/** a specialized version of a OConfigurationNode, representing the root
237 		of a configuration sub tree<p/>
238 		Only this class is able to commit any changes made any any OConfigurationNode
239 		objects.
240 	*/
241 	class UNOTOOLS_DLLPUBLIC OConfigurationTreeRoot : public OConfigurationNode
242 	{
243 		::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesBatch >
244 								m_xCommitter;
245 	protected:
246 		/** ctor<p/>
247 		*/
248 		OConfigurationTreeRoot(
249 			const ::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesBatch >& _rxRootNode
250         );
251 
252 		/** ctor for a readonly node
253 		*/
254 		OConfigurationTreeRoot(
255 			const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxRootNode
256         );
257 
258 	public:
259 		/// modes to use when creating a top-level node object
260 		enum CREATION_MODE
261 		{
262             /// open the node (i.e. sub tree) for read access only
263             CM_READONLY,
264             /// open the node (i.e. sub tree) for read and write access, fall back to read-only if write access is not possible
265             CM_UPDATABLE
266 		};
267 
268 	public:
269 		/** default ctor<p/>
270 			The object constructed here is invalid (i.e. <method>isValid</method> will return sal_False).
271 		*/
OConfigurationTreeRoot()272 		OConfigurationTreeRoot() :OConfigurationNode() { }
273 
274         /** creates a configuration tree for the given path in the given mode
275         */
276         OConfigurationTreeRoot(
277             const ::comphelper::ComponentContext& i_rContext,
278             const sal_Char* i_pAsciiNodePath,
279             const bool i_bUpdatable
280         );
281 
282         /** creates a configuration tree for the given path in the given mode
283         */
284         OConfigurationTreeRoot(
285             const ::comphelper::ComponentContext& i_rContext,
286             const ::rtl::OUString& i_rNodePath,
287             const bool i_bUpdatable
288         );
289 
290 		/// copy ctor
OConfigurationTreeRoot(const OConfigurationTreeRoot & _rSource)291 		OConfigurationTreeRoot(const OConfigurationTreeRoot& _rSource)
292 			:OConfigurationNode(_rSource), m_xCommitter(_rSource.m_xCommitter) { }
293 
294 		/** open a new top-level configuration node
295 
296 			opens a new node which is the root if an own configuration sub tree. This is what "top level" means: The
297 			node does not have a parent. It does not mean that the node represents a module tree (like org.openoffice.Office.Writer
298 			or such).<br/>
299 			In opposite to <method>createWithServiceFactory</method>, createWithProvider expects a configuration provider
300 			to work with.
301 
302             @param		_rxConfProvider	configuration provider to use when retrieving the node.
303 			@param		_rPath			path to the node the object should represent
304 			@param		_nDepth			depth for node retrieval
305 			@param		_eMode			specifies which privileges should be applied when retrieving the node
306 
307             @see	createWithServiceFactory
308 		*/
309 		static OConfigurationTreeRoot createWithProvider(
310                 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxConfProvider,
311 			    const ::rtl::OUString& _rPath,
312                 sal_Int32 _nDepth = -1,
313                 CREATION_MODE _eMode = CM_UPDATABLE,
314                 sal_Bool _bLazyWrite = sal_True
315             );
316 
317 		/** open a new top-level configuration node<p/>
318 			opens a new node which is the root if an own configuration sub tree. This is what "top level" means: The
319 			node does not have a parent. It does not mean that the node represents a module tree (like org.openoffice.Office.Writer
320 			or such).<br/>
321 			In opposite to <method>createWithProvider</method>, createWithProvider expects a service factory. This factory
322 			is used to create a configuration provider, and this provider is used to retrieve the node
323 			@see	createWithProvider
324 			@param		_rxORB			service factory to use to create the configuration provider.
325 			@param		_rPath			path to the node the object should represent
326 			@param		_nDepth			depth for node retrieval
327 			@param		_eMode			specifies which privileges should be applied when retrieving the node
328 		*/
329 		static OConfigurationTreeRoot createWithServiceFactory(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB,
330 			const ::rtl::OUString& _rPath, sal_Int32 _nDepth = -1, CREATION_MODE _eMode = CM_UPDATABLE, sal_Bool _bLazyWrite = sal_True);
331 
332 		/** tolerant version of the <member>createWithServiceFactory</member>
333 
334 			<p>No assertions are thrown in case of an failure to initialize the configuration service, but once
335 			the configuration could be initialized, errors in the creation of the specific node (e.g. because the
336 			given node path does not exist) are still asserted.</p>
337 		*/
338 		static OConfigurationTreeRoot tryCreateWithServiceFactory( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB,
339 			const ::rtl::OUString& _rPath, sal_Int32 _nDepth = -1, CREATION_MODE _eMode = CM_UPDATABLE, sal_Bool _bLazyWrite = sal_True );
340 
341 		/** commit all changes made on the subtree the object is the root for<p/>
342 			All changes made on any <type>OConfigurationNode</type> object retrieved (maybe indirect) from this root
343 			object are committed when calling this method.
344 			@return		sal_True if and only if the commit was successfull
345 		*/
346 		sal_Bool commit() const throw();
347 
348 		/// invalidate the object
349 		virtual void clear() throw();
350 	};
351 
352 //........................................................................
353 }	// namespace utl
354 //........................................................................
355 
356 #endif // _UNOTOOLS_CONFIGNODE_HXX_
357 
358