merge the formfield patch from ooo-build
[ooovba.git] / configmgr / source / treemgr / configgroup.cxx
blob5420a61394343789672793e3b79a91c4deddf464
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
40 #include "tree.hxx"
41 #include "groupnodeimpl.hxx"
42 #include "valuenodeimpl.hxx"
43 #include "typeconverter.hxx"
44 #include "tracer.hxx"
45 #include <com/sun/star/script/XTypeConverter.hpp>
47 namespace configmgr
49 namespace configuration
52 //-----------------------------------------------------------------------------
53 // class GroupUpdateHelper
54 //-----------------------------------------------------------------------------
56 GroupUpdateHelper::GroupUpdateHelper(rtl::Reference< Tree > const& aParentTree, NodeRef const& aGroupNode)
57 : m_aTree(aParentTree)
58 , m_aNode(aGroupNode)
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
86 if (!aNode.isValid())
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
96 if (!aNode.isValid())
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:
140 return true;
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:
153 return true;
155 case uno::TypeClass_SEQUENCE:
157 uno::Sequence< uno::Sequence< sal_Int8 > > const * const forBinaryList = 0;
158 return !!(aValueType == ::getCppuType(forBinaryList));
161 default:
162 return false;
165 default:
166 return false;
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;
178 return true;
181 if (xTypeConverter.is())
182 try
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 ?!
192 return false;
194 catch(css::script::CannotConvertException&)
196 // try to do more conversion here ?!
197 return false;
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 ?!
203 return false;
206 return true;
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)
247 aRet = aValue;
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");
255 // OK - any type
256 aRet = aValue;
259 else
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()) );
268 return aRet;
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);
282 pChange->setTarget(
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 //-----------------------------------------------------------------------------
296 namespace
298 struct NodeDefaulter : NodeVisitor
300 GroupDefaulter& updater;
301 NodeChanges result;
303 explicit
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) );
322 return CONTINUE;
325 NodeVisitor::Result NodeDefaulter::handle(rtl::Reference< Tree > const& , ValueRef const& aValue)
327 addResult( updater.validateSetToDefaultValue(aValue) );
328 return CONTINUE;
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);
367 pChange->setTarget(
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);
380 NodeChange aResult;
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();
390 return aResult;
392 //-----------------------------------------------------------------------------
394 NodeChanges GroupDefaulter::validateSetAllToDefault()
396 NodeDefaulter aDefaulter(*this);
398 m_aHelper.tree()->dispatchToChildren(m_aHelper.node(),aDefaulter);
400 return aDefaulter.result;
402 //-----------------------------------------------------------------------------
404 //-----------------------------------------------------------------------------