1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: configgroup.cxx,v $
10 * $Revision: 1.14.14.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "configgroup.hxx"
35 #include "configset.hxx"
36 #include "valueref.hxx"
37 #include "anynoderef.hxx"
38 #include "nodechange.hxx"
39 #include "nodechangeimpl.hxx"
41 #include "groupnodeimpl.hxx"
42 #include "valuenodeimpl.hxx"
43 #include "typeconverter.hxx"
45 #include <com/sun/star/script/XTypeConverter.hpp>
49 namespace configuration
52 //-----------------------------------------------------------------------------
53 // class GroupUpdateHelper
54 //-----------------------------------------------------------------------------
56 GroupUpdateHelper::GroupUpdateHelper(rtl::Reference
< Tree
> const& aParentTree
, NodeRef
const& aGroupNode
)
57 : m_aTree(aParentTree
)
60 implValidateTree(m_aTree
);
61 implValidateNode(m_aTree
,m_aNode
);
63 if (! view::ViewTreeAccess(m_aTree
.get()).isGroupNode(m_aNode
) )
64 throw Exception("INTERNAL ERROR: Group Member Update: node is not a group");
66 //-----------------------------------------------------------------------------
68 void GroupUpdateHelper::implValidateTree(rtl::Reference
< Tree
> const& aTree
) const
70 if (isEmpty(aTree
.get()))
71 throw Exception("INTERNAL ERROR: Group Member Update: Unexpected NULL tree");
73 // check for proper nesting
74 for(rtl::Reference
<Tree
> aTestTree
= aTree
;
75 aTestTree
!= m_aTree
; // search this as ancestor tree
76 aTestTree
= aTestTree
->getContextTree() )
78 if (!aTestTree
.is()) // no more trees to look for
79 throw Exception("INTERNAL ERROR: Group Member Update: improper tree relationship");
82 //-----------------------------------------------------------------------------
84 void GroupUpdateHelper::implValidateNode(rtl::Reference
< Tree
> const& aTree
, NodeRef
const& aNode
) const
87 throw Exception("INTERNAL ERROR: Group Member Update: Unexpected NULL node");
89 if (!aTree
->isValidNode(aNode
.getOffset()))
90 throw Exception("INTERNAL ERROR: Group Member Update: node does not match tree");
92 //-----------------------------------------------------------------------------
94 void GroupUpdateHelper::implValidateNode(rtl::Reference
< Tree
> const& aTree
, ValueRef
const& aNode
) const
97 throw Exception("INTERNAL ERROR: Group Member Update: Unexpected NULL node");
99 if (!aTree
->isValidValueNode(aNode
))
100 throw Exception("INTERNAL ERROR: Group Member Update: changed node does not match tree");
102 if (aTree
->getAttributes(aNode
).isReadonly())
103 throw ConstraintViolation( "Group Member Update: Node is read-only !" );
106 //-----------------------------------------------------------------------------
108 void GroupUpdateHelper::validateNode(ValueRef
const& aNode
) const
110 implValidateNode(m_aTree
,aNode
);
112 //-----------------------------------------------------------------------------
114 void GroupUpdateHelper::validateNode(NodeRef
const& aNode
) const
116 implValidateNode(m_aTree
,aNode
);
118 //-----------------------------------------------------------------------------
120 /** a helper that gets the UNO <type scope='com::sun::star::uno'>Type</type>
121 for a UNO <type scope='com::sun::star::uno'>Any</type>.
123 static inline com::sun::star::uno::Type
getUnoAnyType()
125 com::sun::star::uno::Any
const * const selectAny
= 0;
126 return ::getCppuType(selectAny
);
128 //-----------------------------------------------------------------------------
130 bool isPossibleValueType(com::sun::star::uno::Type
const& aValueType
)
132 switch(aValueType
.getTypeClass())
134 case uno::TypeClass_BOOLEAN
:
135 case uno::TypeClass_SHORT
:
136 case uno::TypeClass_LONG
:
137 case uno::TypeClass_HYPER
:
138 case uno::TypeClass_DOUBLE
:
139 case uno::TypeClass_STRING
:
142 case uno::TypeClass_SEQUENCE
:
143 switch(getSequenceElementType(aValueType
).getTypeClass())
145 case uno::TypeClass_BYTE
: // scalar binary
147 case uno::TypeClass_BOOLEAN
:
148 case uno::TypeClass_SHORT
:
149 case uno::TypeClass_LONG
:
150 case uno::TypeClass_HYPER
:
151 case uno::TypeClass_DOUBLE
:
152 case uno::TypeClass_STRING
:
155 case uno::TypeClass_SEQUENCE
:
157 uno::Sequence
< uno::Sequence
< sal_Int8
> > const * const forBinaryList
= 0;
158 return !!(aValueType
== ::getCppuType(forBinaryList
));
170 //-----------------------------------------------------------------------------
171 bool convertCompatibleValue(com::sun::star::uno::Reference
<com::sun::star::script::XTypeConverter
> const& xTypeConverter
, uno::Any
& rConverted
, com::sun::star::uno::Any
const& rNewValue
, com::sun::star::uno::Type
const& rTargetType
)
173 OSL_ASSERT( isPossibleValueType(rTargetType
) );
175 if (rTargetType
== rNewValue
.getValueType())
177 rConverted
= rNewValue
;
181 if (xTypeConverter
.is())
184 rConverted
= xTypeConverter
->convertTo(rNewValue
,rTargetType
);
186 OSL_ASSERT( rConverted
.getValueType() == rTargetType
);
188 catch(uno::RuntimeException
&) { throw; }
189 catch(css::lang::IllegalArgumentException
&)
191 // try to do more conversion here ?!
194 catch(css::script::CannotConvertException
&)
196 // try to do more conversion here ?!
199 catch(uno::Exception
&)
201 OSL_ENSURE(sal_False
, "ValueUpdater::convertValue : generic exception ... thought we caught all allowed exceptions !");
202 // try to do more conversion here ?!
208 //-----------------------------------------------------------------------------
210 //-----------------------------------------------------------------------------
211 // class GroupUpdater
212 //-----------------------------------------------------------------------------
214 GroupUpdater::GroupUpdater(rtl::Reference
< Tree
> const& aParentTree
, NodeRef
const& aGroupNode
, com::sun::star::uno::Reference
<com::sun::star::script::XTypeConverter
> const& xConverter
)
215 : m_aHelper(aParentTree
,aGroupNode
)
216 , m_xTypeConverter(xConverter
)
219 //-----------------------------------------------------------------------------
221 com::sun::star::uno::Any
GroupUpdater::implValidateValue(rtl::Reference
< Tree
> const& aTree
, ValueRef
const& aNode
, com::sun::star::uno::Any
const& aValue
) const
223 com::sun::star::uno::Type aValueType
= aValue
.getValueType();
224 com::sun::star::uno::Type aTargetType
= aTree
->getUnoType(aNode
);
226 OSL_ENSURE( aTargetType
.getTypeClass() == uno::TypeClass_ANY
|| isPossibleValueType(aTargetType
),
227 "Invalid value type found on existing property" );
229 OSL_ASSERT( aValueType
.getTypeClass() != uno::TypeClass_ANY
);
231 com::sun::star::uno::Any aRet
;
233 if (!aValue
.hasValue())
235 if (!aTree
->getAttributes(aNode
).isNullable())
237 rtl::OString
sError("Group Member Update: Node (");
238 sError
+= OUSTRING2ASCII(aNode
.m_sNodeName
);
239 sError
+= ") is not nullable !";
240 throw ConstraintViolation( sError
);
242 OSL_ASSERT( !aRet
.hasValue() );
245 else if (aValueType
== aTargetType
)
250 else if (aTargetType
== getUnoAnyType())
252 if ( ! isPossibleValueType(aValueType
) )
253 throw TypeMismatch(aValueType
.getTypeName(), aTargetType
.getTypeName(), " - new property value has no legal configuration data type");
261 if (!convertCompatibleValue(m_xTypeConverter
, aRet
, aValue
,aTargetType
))
262 throw TypeMismatch(aValueType
.getTypeName(), aTargetType
.getTypeName(), " cannot set incompatible value");
266 OSL_ASSERT( !aRet
.hasValue() || isPossibleValueType(aRet
.getValueType()) );
270 //-----------------------------------------------------------------------------
272 NodeChange
GroupUpdater::validateSetValue(ValueRef
const& aValueNode
, com::sun::star::uno::Any
const& newValue
)
274 m_aHelper
.validateNode(aValueNode
);
276 com::sun::star::uno::Any aNewValue
= implValidateValue(m_aHelper
.tree(), aValueNode
, newValue
);
278 // now build the specific change
279 std::auto_ptr
<ValueChangeImpl
> pChange( new ValueReplaceImpl(aNewValue
) );
281 NodeRef aParent
= m_aHelper
.tree()->getParent(aValueNode
);
283 view::ViewTreeAccess(m_aHelper
.tree().get()).toGroupNode(aParent
),
284 aValueNode
.m_sNodeName
287 return NodeChange(pChange
.release());
290 //-----------------------------------------------------------------------------
292 //-----------------------------------------------------------------------------
293 // helper class NodeDefaulter
294 //-----------------------------------------------------------------------------
298 struct NodeDefaulter
: NodeVisitor
300 GroupDefaulter
& updater
;
304 NodeDefaulter(GroupDefaulter
& _rUpdater
) : updater(_rUpdater
), result() {}
306 /// do the operation on <var>aNode</var>. needs to be implemented by concrete visitor classes
307 Result
handle(rtl::Reference
< Tree
> const& aTree
, NodeRef
const& aNode
);
309 /// do the operation on <var>aValue</var>. needs to be implemented by concrete visitor classes
310 Result
handle(rtl::Reference
< Tree
> const& aTree
, ValueRef
const& aValue
);
312 inline void addResult(NodeChange
const& aChange
)
314 if (aChange
.maybeChange())
315 this->result
.add(aChange
);
319 NodeVisitor::Result
NodeDefaulter::handle(rtl::Reference
< Tree
> const& , NodeRef
const& aNode
)
321 addResult( updater
.validateSetToDefaultState(aNode
) );
325 NodeVisitor::Result
NodeDefaulter::handle(rtl::Reference
< Tree
> const& , ValueRef
const& aValue
)
327 addResult( updater
.validateSetToDefaultValue(aValue
) );
331 //-----------------------------------------------------------------------------
333 //-----------------------------------------------------------------------------
334 // class GroupDefaulter
335 //-----------------------------------------------------------------------------
337 GroupDefaulter::GroupDefaulter(rtl::Reference
< Tree
> const& _aParentTree
, NodeRef
const& _aGroupNode
, DefaultProvider
const& _aProvider
)
338 : m_aHelper(_aParentTree
,_aGroupNode
)
339 , m_aDefaultProvider(_aProvider
)
340 , m_bHasDoneSet(false)
343 //-----------------------------------------------------------------------------
344 bool GroupDefaulter::isDataAvailable(rtl::Reference
< Tree
> const& _aParentTree
, NodeRef
const& _aGroupNode
)
346 return _aParentTree
->areValueDefaultsAvailable(_aGroupNode
);
348 //-----------------------------------------------------------------------------
349 bool GroupDefaulter::ensureDataAvailable(rtl::Reference
< Tree
> const& _aParentTree
, NodeRef
const& _aGroupNode
, DefaultProvider
const& _aDataSource
)
351 return isDataAvailable(_aParentTree
, _aGroupNode
) ||
352 _aDataSource
.fetchDefaultData( _aParentTree
);
354 //-----------------------------------------------------------------------------
356 NodeChange
GroupDefaulter::validateSetToDefaultValue(ValueRef
const& aValueNode
)
358 m_aHelper
.validateNode(aValueNode
);
360 if (!m_aHelper
.tree()->hasNodeDefault(aValueNode
))
361 throw Exception("INTERNAL ERROR: Group Member Update: Node has no default value" );
363 // now build the specific change
364 std::auto_ptr
<ValueChangeImpl
> pChange( new ValueResetImpl() );
366 NodeRef aParent
= m_aHelper
.tree()->getParent(aValueNode
);
368 view::ViewTreeAccess(m_aHelper
.tree().get()).toGroupNode(aParent
),
369 aValueNode
.m_sNodeName
372 return NodeChange(pChange
.release());
374 //-----------------------------------------------------------------------------
376 NodeChange
GroupDefaulter::validateSetToDefaultState(NodeRef
const& aNode
)
378 m_aHelper
.validateNode(aNode
);
382 // only works for set nodes - groups are left alone
383 if ( view::ViewTreeAccess(m_aHelper
.tree().get()).isSetNode(aNode
) )
385 aResult
= SetDefaulter( m_aHelper
.tree(), aNode
, m_aDefaultProvider
).validateSetToDefaultState();
388 m_bHasDoneSet
= aResult
.maybeChange();
392 //-----------------------------------------------------------------------------
394 NodeChanges
GroupDefaulter::validateSetAllToDefault()
396 NodeDefaulter
aDefaulter(*this);
398 m_aHelper
.tree()->dispatchToChildren(m_aHelper
.node(),aDefaulter
);
400 return aDefaulter
.result
;
402 //-----------------------------------------------------------------------------
404 //-----------------------------------------------------------------------------