merge the formfield patch from ooo-build
[ooovba.git] / configmgr / source / xml / valueformatter.cxx
blob6ff1a3b10fbcb37a4941175604c6b8f9ecdec501
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: valueformatter.cxx,v $
10 * $Revision: 1.6 $
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 "valueformatter.hxx"
35 #include "elementformatter.hxx"
36 #include "xmlstrings.hxx"
37 #include "typeconverter.hxx"
38 #include "simpletypehelper.hxx"
39 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/uno/Sequence.hxx>
42 #ifndef INCLUDED_ALGORITHM
43 #include <algorithm>
44 #define INCLUDED_ALGORITHM
45 #endif
47 namespace configmgr
49 namespace uno = com::sun::star::uno;
51 namespace xml
54 //==========================================================================
55 //= Helper
56 //==========================================================================
58 // -----------------------------------------------------------------------------
59 namespace
61 // -----------------------------------------------------------------------------
63 static
64 inline
65 bool isWhitespaceCharacter( sal_Unicode ch )
67 return ch <= 0x20 && ch;
69 // -----------------------------------------------------------------------------
71 static
72 inline
73 bool isWhitespaceString(rtl::OUString const & aStr)
75 sal_Unicode const * const pBegin = aStr.getStr();
76 sal_Unicode const * const pEnd = pBegin + aStr.getLength();
78 // BACK: true, if any whitespace in string or string is empty
79 if (pBegin == pEnd)
80 return true;
82 sal_Unicode const * const pSpace = std::find_if(pBegin,pEnd,isWhitespaceCharacter);
84 return pSpace != pEnd;
86 // -----------------------------------------------------------------------------
88 static
89 bool hasWhitespaceString( uno::Sequence< rtl::OUString > const & aSeq)
91 // BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
92 rtl::OUString const * const pBegin = aSeq.getConstArray();
93 rtl::OUString const * const pEnd = pBegin + aSeq.getLength();
95 rtl::OUString const * const pSpace = std::find_if(pBegin,pEnd,isWhitespaceString);
97 return pSpace != pEnd;
99 // -----------------------------------------------------------------------------
101 struct HasSubString
103 HasSubString(rtl::OUString const & _aSubStr)
104 : m_aSubStr(_aSubStr)
107 bool operator()(rtl::OUString const & _aStr)
108 { return _aStr.indexOf(m_aSubStr) >= 0; }
110 rtl::OUString const m_aSubStr;
112 // -----------------------------------------------------------------------------
114 static
115 bool hasStringWithSubstring(const uno::Sequence< rtl::OUString > &aSeq, rtl::OUString const & _aSubStr)
117 rtl::OUString const * const pBegin = aSeq.getConstArray();
118 rtl::OUString const * const pEnd = pBegin + aSeq.getLength();
120 rtl::OUString const * const pSpace = std::find_if(pBegin,pEnd,HasSubString(_aSubStr));
122 return pSpace != pEnd;
124 // -----------------------------------------------------------------------------
127 template <class Element_>
128 struct IsEmptySequence
130 bool operator()(uno::Sequence<Element_> const & aSeq) const
132 return aSeq.getLength() == 0;
135 // -----------------------------------------------------------------------------
137 template <class Element_>
138 bool hasEmptySequence(uno::Sequence< uno::Sequence<Element_> > const & aSeqSeq)
140 // BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
141 uno::Sequence<Element_> const * const pBegin = aSeqSeq.getConstArray();
142 uno::Sequence<Element_> const * const pEnd = pBegin + aSeqSeq.getLength();
144 uno::Sequence<Element_> const * const pEmpty = std::find_if(pBegin, pEnd, IsEmptySequence<Element_>() );
146 return pEmpty != pEnd;
148 // -----------------------------------------------------------------------------
150 inline
151 bool canUseSeparator(uno::Sequence< rtl::OUString > const & aSeq, rtl::OUString const & aSeparator)
153 return ! hasStringWithSubstring(aSeq,aSeparator);
155 // -----------------------------------------------------------------------------
157 inline
158 bool canUseWhitespaceSeparator(uno::Sequence< rtl::OUString > const & aSeq)
160 return ! hasWhitespaceString(aSeq);
162 // -----------------------------------------------------------------------------
164 template <class Element_>
165 inline
166 bool canUseWhitespaceSeparator(const uno::Sequence< uno::Sequence<Element_> > &aSeq)
168 return ! hasEmptySequence(aSeq);
170 // -----------------------------------------------------------------------------
172 class Separator
174 rtl::OUString m_sValue;
175 public:
176 // -----------------------------------------------------------------------------
177 Separator() : m_sValue() {}
178 // -----------------------------------------------------------------------------
179 bool isDefault() const { return m_sValue.getLength() == 0; }
180 // -----------------------------------------------------------------------------
181 rtl::OUString value() const { return isDefault() ? static_cast<rtl::OUString>(SEPARATOR_WHITESPACE) : m_sValue; }
182 // -----------------------------------------------------------------------------
184 bool check(const uno::Sequence<rtl::OUString> &aSeq) const
186 return isDefault() ? canUseWhitespaceSeparator(aSeq) : canUseSeparator(aSeq, m_sValue);
189 // -----------------------------------------------------------------------------
190 bool trySeparator(rtl::OUString const& sSep, const uno::Sequence<rtl::OUString> & aSeq)
192 OSL_ENSURE( ! isWhitespaceString(sSep), "There should be no spaces in non-default separators");
193 // BACK: true, if Separator is ok, not in Strings
194 if (!canUseSeparator(aSeq, sSep))
195 return false;
196 this->setSeparator(sSep);
197 return true;
199 // -----------------------------------------------------------------------------
200 void setSeparator(rtl::OUString const& sSep)
202 m_sValue = sSep;
204 // -----------------------------------------------------------------------------
206 // -----------------------------------------------------------------------------
207 #define ASCII( STRING_LIT_ ) ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( STRING_LIT_ ) ) )
208 // -----------------------------------------------------------------------------
209 static
210 Separator createSeparator(const uno::Any& aAny)
212 Separator aResult;
214 // create a Separator which isn't in any value
215 if (aAny.getValueTypeClass() == uno::TypeClass_SEQUENCE)
217 uno::Type aElementType = configmgr::getSequenceElementType(aAny.getValueType());
218 if (aElementType.getTypeClass() == uno::TypeClass_STRING)
220 // only in strings we need to search a separator
221 uno::Sequence<rtl::OUString> aSeq;
223 OSL_VERIFY (aAny >>= aSeq);
225 bool bValidSeparator =
226 canUseWhitespaceSeparator(aSeq) ||
227 aResult.trySeparator(ASCII(","), aSeq) ||
228 aResult.trySeparator(ASCII(";"), aSeq) ||
229 aResult.trySeparator(ASCII(":"), aSeq) ||
230 aResult.trySeparator(ASCII("|"), aSeq) ||
231 aResult.trySeparator(ASCII("#"), aSeq) ||
232 aResult.trySeparator(ASCII("-#*=+#-"), aSeq);
234 if (!bValidSeparator)
236 OSL_TRACE("ERROR: configuration formatter: Could not create Separator for string list");
237 OSL_ENSURE(false, "ERROR: Could not create Separator for string list");
239 else
241 // maybe the whitespace test was invalid ?
242 OSL_ENSURE(aResult.check(aSeq), "Found Separator does not pass check ?!");
245 else if (aElementType == SimpleTypeHelper::getBinaryType())
247 // only in strings we need to search a separator
248 uno::Sequence< uno::Sequence<sal_Int8> > aSeq;
249 OSL_VERIFY(aAny >>= aSeq);
251 if (!canUseWhitespaceSeparator(aSeq))
253 aResult.setSeparator( ASCII(":") );
258 // DefaultSeparator
259 return aResult;
261 #undef ASCII
262 // -----------------------------------------------------------------------------
263 static
264 inline
265 sal_Unicode hexNibble(sal_uInt8 _nNibble)
267 OSL_ASSERT(_nNibble <= 0x0F);
269 const sal_uInt8 cDecOffset = sal_uInt8('0');
270 const sal_uInt8 cHexOffset = sal_uInt8('a') - 10;
272 return _nNibble + (_nNibble<10 ? cDecOffset : cHexOffset);
275 // -----------------------------------------------------------------------------
276 static
277 inline
278 void appendHex(rtl::OUStringBuffer& rBuff, sal_uInt8 _nByte)
280 rBuff.append( hexNibble(_nByte >> 4) );
281 rBuff.append( hexNibble(_nByte & 0x0f) );
284 // -----------------------------------------------------------------------------
285 static
286 rtl::OUString binaryToHex(const uno::Sequence<sal_Int8>& _aBinarySeq)
288 sal_Int32 const nLength = _aBinarySeq.getLength();
290 rtl::OUStringBuffer sHex(2*nLength);
292 for (sal_Int32 nPos = 0;nPos < nLength; ++nPos)
294 appendHex( sHex, _aBinarySeq[nPos] );
297 OSL_ASSERT(sHex.getLength() == 2*nLength);
298 return sHex.makeStringAndClear();;
300 // -----------------------------------------------------------------------------
301 rtl::OUString formatSimpleValue(uno::Any const & _aValue, uno::Reference< script::XTypeConverter > const & _xTCV)
303 rtl::OUString sResult;
305 if (_aValue.hasValue())
307 if (_aValue .getValueType() == SimpleTypeHelper::getBinaryType())
309 uno::Sequence<sal_Int8> aBinarySeq;
311 OSL_VERIFY(_aValue >>= aBinarySeq);
313 sResult = binaryToHex(aBinarySeq);
315 else
317 // cannot have nested any
318 OSL_ASSERT(_aValue.getValueTypeClass() != uno::TypeClass_ANY);
320 sResult = toString(_xTCV, _aValue);
323 return sResult;
326 // -----------------------------------------------------------------------------
327 template <class Element_>
328 rtl::OUString formatSequence(uno::Sequence< Element_ > const& aSequence, rtl::OUString const& sSeparator, uno::Reference< script::XTypeConverter > const & _xTCV)
330 rtl::OUStringBuffer aResult;
332 if (sal_Int32 const nLength = aSequence.getLength())
334 Element_ const * pSeq = aSequence.getConstArray();
336 aResult = formatSimpleValue( uno::makeAny(pSeq[0]),_xTCV);
338 for(sal_Int32 i=1; i<nLength; ++i)
340 aResult.append( sSeparator );
341 aResult.append( formatSimpleValue(uno::makeAny(pSeq[i]),_xTCV) );
345 return aResult.makeStringAndClear();
347 // -----------------------------------------------------------------------------
348 // template <> // optimized overload for String
349 rtl::OUString formatSequence(uno::Sequence< rtl::OUString > const& aSequence, rtl::OUString const& sSeparator, uno::Reference< script::XTypeConverter > const & )
351 rtl::OUStringBuffer aResult;
353 if (sal_Int32 const nLength = aSequence.getLength())
355 rtl::OUString const * pSeq = aSequence.getConstArray();
357 aResult = pSeq[0];
359 for(sal_Int32 i=1; i<nLength; ++i)
361 aResult.append( sSeparator ).append( pSeq[i] );
365 return aResult.makeStringAndClear();
368 // -----------------------------------------------------------------------------
370 #define CASE_WRITE_SEQUENCE(TYPE_CLASS, DATA_TYPE) \
371 case TYPE_CLASS: \
373 uno::Sequence< DATA_TYPE > aData; \
374 OSL_ENSURE( ::getCppuType(static_cast< DATA_TYPE const*>(0)).getTypeClass() == (TYPE_CLASS), \
375 "Usage Error for CASE_WRITE_SEQUENCE: Type extracted does not match type class"); \
376 OSL_VERIFY( _aValue >>= aData ); \
377 aResult = formatSequence(aData,sSeparator,xTCV); \
378 } break \
380 rtl::OUString formatSequenceValue(uno::Any const& _aValue, rtl::OUString const& sSeparator, uno::Reference< script::XTypeConverter > const & xTCV)
382 rtl::OUString aResult;
384 uno::Type aElementType = getSequenceElementType( _aValue.getValueType() );
386 switch(aElementType.getTypeClass())
388 CASE_WRITE_SEQUENCE( uno::TypeClass_BOOLEAN, sal_Bool );
390 CASE_WRITE_SEQUENCE( uno::TypeClass_SHORT, sal_Int16 );
392 CASE_WRITE_SEQUENCE( uno::TypeClass_LONG, sal_Int32 );
394 CASE_WRITE_SEQUENCE( uno::TypeClass_HYPER, sal_Int64 );
396 CASE_WRITE_SEQUENCE( uno::TypeClass_DOUBLE, double );
398 CASE_WRITE_SEQUENCE( uno::TypeClass_STRING, rtl::OUString );
400 CASE_WRITE_SEQUENCE( uno::TypeClass_SEQUENCE, uno::Sequence<sal_Int8> );
402 default:
403 OSL_ENSURE(false, "Unexpected typeclass for sequence elements");
404 break;
407 return aResult;
410 #undef CASE_WRITE_SEQUENCE
411 // -----------------------------------------------------------------------------
412 } // anonymous namspace
413 // -----------------------------------------------------------------------------
414 // -----------------------------------------------------------------------------
416 static inline bool isListVal(uno::Any const & _aValue)
418 bool bList = false;
419 if (_aValue.hasValue())
421 getBasicType(_aValue.getValueType(),bList);
423 return bList;
425 // -----------------------------------------------------------------------------
426 void ValueFormatter::makeSeparator()
428 if (isListVal(m_aValue))
430 Separator aSeparator = createSeparator(m_aValue);
432 m_sSeparator = aSeparator.value();
433 m_bUseSeparator = !aSeparator.isDefault();
435 OSL_POSTCOND( this->isList() , "ValueFormatter: Could not mark as list");
437 else
439 m_sSeparator = rtl::OUString();
440 m_bUseSeparator = false;
442 OSL_POSTCOND( !this->isList(), "ValueFormatter: Could not mark as non-list");
445 // -----------------------------------------------------------------------------
447 rtl::OUString ValueFormatter::getContent(uno::Reference< script::XTypeConverter > const & _xTCV) const
449 rtl::OUString aResult;
452 if (this->isList())
454 aResult = formatSequenceValue(m_aValue, m_sSeparator, _xTCV);
456 else
458 aResult = formatSimpleValue(m_aValue, _xTCV);
461 catch (script::CannotConvertException& cce)
463 rtl::OUString const sMessage(RTL_CONSTASCII_USTRINGPARAM("Configuration: Could not convert value to XML representation: "));
464 throw uno::RuntimeException(sMessage + cce.Message, cce.Context);
467 return aResult;
469 // -----------------------------------------------------------------------------
471 bool ValueFormatter::addValueAttributes(ElementFormatter & _rFormatter) const
473 // do we have a NULL value
474 if (!m_aValue.hasValue())
476 _rFormatter.addIsNull();
477 return false;
480 // create a sequence separator
481 if (m_bUseSeparator)
483 OSL_ASSERT(this->isList());
484 _rFormatter.addSeparator(m_sSeparator);
487 return true;
489 // -----------------------------------------------------------------------------
491 // -----------------------------------------------------------------------------
492 // -----------------------------------------------------------------------------
493 } // namespace xml
495 // -----------------------------------------------------------------------------
496 } // namespace configmgr