1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 
31 #include <stdio.h>
32 #include "layerexport.hxx"
33 #include "strings.hxx"
34 #include <xmloff/xmlexp.hxx>
35 #include <xmloff/nmspmap.hxx>
36 #include "xmloff/xmlnmspe.hxx"
37 #include <xmloff/xmluconv.hxx>
38 #include <xmloff/xmlprmap.hxx>
39 #include <xmloff/prhdlfac.hxx>
40 #include "elementexport.hxx"
41 #include <xmloff/families.hxx>
42 #include <xmloff/contextid.hxx>
43 #include <xmloff/controlpropertyhdl.hxx>
44 #include <tools/diagnose_ex.h>
45 #include "controlpropertymap.hxx"
46 #include <com/sun/star/container/XIndexAccess.hpp>
47 #include <com/sun/star/form/XFormsSupplier2.hpp>
48 #include <com/sun/star/xforms/XFormsSupplier.hpp>
49 #include <com/sun/star/form/FormComponentType.hpp>
50 #include <com/sun/star/lang/XServiceInfo.hpp>
51 #include <com/sun/star/container/XChild.hpp>
52 #include <com/sun/star/script/XEventAttacherManager.hpp>
53 #include "eventexport.hxx"
54 #include <xmloff/XMLEventExport.hxx>
55 #include "formevents.hxx"
56 #include <xmloff/xmlnumfe.hxx>
57 #include "xmloff/xformsexport.hxx"
58 
59 /** === begin UNO includes === **/
60 #include <com/sun/star/text/XText.hpp>
61 /** === end UNO includes === **/
62 
63 #include <numeric>
64 
65 //.........................................................................
66 namespace xmloff
67 {
68 //.........................................................................
69 
70 	using namespace ::com::sun::star::uno;
71 	using namespace ::com::sun::star::awt;
72 	using namespace ::com::sun::star::lang;
73 	using namespace ::com::sun::star::beans;
74 	using namespace ::com::sun::star::container;
75 	using namespace ::com::sun::star::drawing;
76 	using namespace ::com::sun::star::form;
77 	using namespace ::com::sun::star::script;
78 	using namespace ::com::sun::star::util;
79 	using namespace ::com::sun::star::text;
80 
81     typedef ::com::sun::star::xforms::XFormsSupplier XXFormsSupplier;
82 
83 	//=====================================================================
84 	//= OFormLayerXMLExport_Impl
85 	//=====================================================================
86 	//---------------------------------------------------------------------
87 	const ::rtl::OUString& OFormLayerXMLExport_Impl::getControlNumberStyleNamePrefix()
88 	{
89 		static const ::rtl::OUString s_sControlNumberStyleNamePrefix = ::rtl::OUString::createFromAscii("C");
90 		return s_sControlNumberStyleNamePrefix;
91 	}
92 
93 	//---------------------------------------------------------------------
94 	OFormLayerXMLExport_Impl::OFormLayerXMLExport_Impl(SvXMLExport& _rContext)
95 		:m_rContext(_rContext)
96 		,m_pControlNumberStyles(NULL)
97 	{
98 		initializePropertyMaps();
99 
100 		// add our style family to the export context's style pool
101 		m_xPropertyHandlerFactory = new OControlPropertyHandlerFactory();
102 		::vos::ORef< XMLPropertySetMapper > xStylePropertiesMapper = new XMLPropertySetMapper( getControlStylePropertyMap(), m_xPropertyHandlerFactory.getBodyPtr() );
103 		m_xStyleExportMapper = new OFormComponentStyleExportMapper( xStylePropertiesMapper.getBodyPtr() );
104 
105 		// our style family
106 		m_rContext.GetAutoStylePool()->AddFamily(
107 			XML_STYLE_FAMILY_CONTROL_ID, token::GetXMLToken(token::XML_PARAGRAPH),
108 			m_xStyleExportMapper.getBodyPtr(),
109 			::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( XML_STYLE_FAMILY_CONTROL_PREFIX) )
110 		);
111 
112 		// add our event translation table
113 		m_rContext.GetEventExport().AddTranslationTable(g_pFormsEventTranslation);
114 
115 		clear();
116 	}
117 
118 	OFormLayerXMLExport_Impl::~OFormLayerXMLExport_Impl()
119 	{
120 	}
121 
122 	//---------------------------------------------------------------------
123 	sal_Bool OFormLayerXMLExport_Impl::impl_isFormPageContainingForms(const Reference< XDrawPage >& _rxDrawPage, Reference< XIndexAccess >& _rxForms)
124 	{
125 		Reference< XFormsSupplier2 > xFormsSupp(_rxDrawPage, UNO_QUERY);
126 		OSL_ENSURE(xFormsSupp.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid draw page (no XFormsSupplier)! Doin' nothing!");
127 		if (!xFormsSupp.is())
128 			return sal_False;
129 
130         if ( !xFormsSupp->hasForms() )
131             // nothing to do at all
132             return sal_False;
133 
134 		_rxForms = Reference< XIndexAccess >(xFormsSupp->getForms(), UNO_QUERY);
135 		Reference< XServiceInfo > xSI(_rxForms, UNO_QUERY);	// order is important!
136 		OSL_ENSURE(xSI.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (must not be NULL and must have a ServiceInfo)!");
137 		if (!xSI.is())
138 			return sal_False;
139 
140 		if (!xSI->supportsService(SERVICE_FORMSCOLLECTION))
141 		{
142 			OSL_ENSURE(sal_False, "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (is no com.sun.star.form.Forms)!");
143 			// nothing to do
144 			return sal_False;
145 		}
146 		return sal_True;
147 	}
148 
149 	//---------------------------------------------------------------------
150 	void OFormLayerXMLExport_Impl::exportGridColumn(const Reference< XPropertySet >& _rxColumn,
151 		const Sequence< ScriptEventDescriptor >& _rEvents)
152 	{
153         // do the exporting
154 		OColumnExport aExportImpl(*this, _rxColumn, getControlId( _rxColumn ), _rEvents);
155 		aExportImpl.doExport();
156 	}
157 
158 	//---------------------------------------------------------------------
159 	void OFormLayerXMLExport_Impl::exportControl(const Reference< XPropertySet >& _rxControl,
160 		const Sequence< ScriptEventDescriptor >& _rEvents)
161 	{
162 		// the list of the referring controls
163 		::rtl::OUString sReferringControls;
164         MapPropertySet2String::const_iterator aReferring = m_aCurrentPageReferring->second.find(_rxControl);
165 		if (aReferring != m_aCurrentPageReferring->second.end())
166 			sReferringControls = aReferring->second;
167 
168 		// the control id (should already have been created in examineForms)
169 		::rtl::OUString sControlId( getControlId( _rxControl ) );
170 
171 		// do the exporting
172 		OControlExport aExportImpl(*this, _rxControl, sControlId, sReferringControls, _rEvents);
173 		aExportImpl.doExport();
174 	}
175 
176 	//---------------------------------------------------------------------
177 	void OFormLayerXMLExport_Impl::exportForm(const Reference< XPropertySet >& _rxProps,
178 		const Sequence< ScriptEventDescriptor >& _rEvents)
179 	{
180 		OSL_ENSURE(_rxProps.is(), "OFormLayerXMLExport_Impl::exportForm: invalid property set!");
181 		OFormExport aAttributeHandler(*this, _rxProps, _rEvents);
182 		aAttributeHandler.doExport();
183 	}
184 
185 	//---------------------------------------------------------------------
186 	::vos::ORef< SvXMLExportPropertyMapper > OFormLayerXMLExport_Impl::getStylePropertyMapper()
187 	{
188 		return m_xStyleExportMapper;
189 	}
190 
191 	//---------------------------------------------------------------------
192 	SvXMLExport& OFormLayerXMLExport_Impl::getGlobalContext()
193 	{
194 		return m_rContext;
195 	}
196 
197 	//---------------------------------------------------------------------
198 	void OFormLayerXMLExport_Impl::exportCollectionElements(const Reference< XIndexAccess >& _rxCollection)
199 	{
200 		// step through all the elements of the collection
201 		sal_Int32 nElements = _rxCollection->getCount();
202 
203 		Reference< XEventAttacherManager > xElementEventManager(_rxCollection, UNO_QUERY);
204 		Sequence< ScriptEventDescriptor > aElementEvents;
205 
206 		Reference< XPropertySetInfo > xPropsInfo;
207 		Reference< XIndexAccess > xCurrentContainer;
208 		for (sal_Int32 i=0; i<nElements; ++i)
209 		{
210 			try
211 			{
212 				// extract the current element
213 		        Reference< XPropertySet > xCurrentProps( _rxCollection->getByIndex(i), UNO_QUERY );
214 				OSL_ENSURE(xCurrentProps.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: invalid child element, skipping!");
215 				if (!xCurrentProps.is())
216 					continue;
217 
218 				// check if there is a ClassId property on the current element. If so, we assume it to be a control
219 				xPropsInfo = xCurrentProps->getPropertySetInfo();
220 				OSL_ENSURE(xPropsInfo.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: no property set info!");
221 				if (!xPropsInfo.is())
222 					// without this, a lot of stuff in the export routines may fail
223 					continue;
224 
225 				// if the element is part of a ignore list, we are not allowed to export it
226 				if ( m_aIgnoreList.end() != m_aIgnoreList.find( xCurrentProps ) )
227 					continue;
228 
229 				if (xElementEventManager.is())
230 					aElementEvents = xElementEventManager->getScriptEvents(i);
231 
232 				if (xPropsInfo->hasPropertyByName(PROPERTY_COLUMNSERVICENAME))
233 				{
234 					exportGridColumn(xCurrentProps, aElementEvents);
235 				}
236 				else if (xPropsInfo->hasPropertyByName(PROPERTY_CLASSID))
237 				{
238 					exportControl(xCurrentProps, aElementEvents);
239 				}
240 				else
241 				{
242 					exportForm(xCurrentProps, aElementEvents);
243 				}
244 			}
245 			catch(Exception&)
246 			{
247 				OSL_ENSURE(sal_False, "OFormLayerXMLExport_Impl::exportCollectionElements: caught an exception ... skipping the current element!");
248 				continue;
249 			}
250 		}
251 	}
252 
253 	//---------------------------------------------------------------------
254 	::rtl::OUString OFormLayerXMLExport_Impl::getObjectStyleName( const Reference< XPropertySet >& _rxObject )
255 	{
256 		::rtl::OUString aObjectStyle;
257 
258 		MapPropertySet2String::const_iterator aObjectStylePos = m_aGridColumnStyles.find( _rxObject );
259 		if ( m_aGridColumnStyles.end() != aObjectStylePos )
260 			aObjectStyle = aObjectStylePos->second;
261 		return aObjectStyle;
262 	}
263 
264 	//---------------------------------------------------------------------
265 	void OFormLayerXMLExport_Impl::clear()
266 	{
267 		m_aControlIds.clear();
268 		m_aReferringControls.clear();
269 		m_aCurrentPageIds = m_aControlIds.end();
270 		m_aCurrentPageReferring = m_aReferringControls.end();
271 
272 		m_aControlNumberFormats.clear();
273 		m_aGridColumnStyles.clear();
274 
275 		m_aIgnoreList.clear();
276 	}
277 
278 	//---------------------------------------------------------------------
279 	void OFormLayerXMLExport_Impl::exportControlNumberStyles()
280 	{
281 		if (m_pControlNumberStyles)
282 			m_pControlNumberStyles->Export(sal_False);
283 	}
284 
285 	//---------------------------------------------------------------------
286 	void OFormLayerXMLExport_Impl::exportAutoControlNumberStyles()
287 	{
288 		if ( m_pControlNumberStyles )
289 			m_pControlNumberStyles->Export( sal_True );
290 	}
291 
292 	//---------------------------------------------------------------------
293 	void OFormLayerXMLExport_Impl::exportAutoStyles()
294 	{
295 		m_rContext.GetAutoStylePool()->exportXML(
296 			XML_STYLE_FAMILY_CONTROL_ID,
297 			m_rContext.GetDocHandler(),
298 			m_rContext.GetMM100UnitConverter(),
299 			m_rContext.GetNamespaceMap()
300 		);
301 	}
302 
303 	//---------------------------------------------------------------------
304 	void OFormLayerXMLExport_Impl::exportForms(const Reference< XDrawPage >& _rxDrawPage)
305 	{
306 		// get the forms collection of the page
307 		Reference< XIndexAccess > xCollectionIndex;
308 		if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
309 			return;
310 
311 #if OSL_DEBUG_LEVEL > 0
312 		sal_Bool bPageIsKnown =
313 #endif
314 			implMoveIterators(_rxDrawPage, sal_False);
315 		OSL_ENSURE(bPageIsKnown, "OFormLayerXMLExport_Impl::exportForms: exporting a page which has not been examined!");
316 
317         // export forms collection
318 		exportCollectionElements(xCollectionIndex);
319 	}
320 
321 	//---------------------------------------------------------------------
322 	void OFormLayerXMLExport_Impl::exportXForms() const
323     {
324         // export XForms models
325         ::exportXForms( m_rContext );
326     }
327 
328 	//---------------------------------------------------------------------
329 	bool OFormLayerXMLExport_Impl::pageContainsForms( const Reference< XDrawPage >& _rxDrawPage ) const
330     {
331 		Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY );
332         DBG_ASSERT( xFormsSupp.is(), "OFormLayerXMLExport_Impl::pageContainsForms: no XFormsSupplier2!" );
333         return xFormsSupp.is() && xFormsSupp->hasForms();
334     }
335 
336 	//---------------------------------------------------------------------
337 	bool OFormLayerXMLExport_Impl::documentContainsXForms() const
338     {
339         Reference< XXFormsSupplier > xXFormSupp( m_rContext.GetModel(), UNO_QUERY );
340         Reference< XNameContainer > xForms;
341         if ( xXFormSupp.is() )
342             xForms = xXFormSupp->getXForms();
343         return xForms.is() && xForms->hasElements();
344     }
345 
346 	//---------------------------------------------------------------------
347 	sal_Bool OFormLayerXMLExport_Impl::implMoveIterators(const Reference< XDrawPage >& _rxDrawPage, sal_Bool _bClear)
348 	{
349 		sal_Bool bKnownPage = sal_False;
350 
351 		// the one for the ids
352 		m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage);
353 		if (m_aControlIds.end() == m_aCurrentPageIds)
354 		{
355 			m_aControlIds[_rxDrawPage] = MapPropertySet2String();
356 			m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage);
357 		}
358 		else
359 		{
360 			bKnownPage = sal_True;
361 			if (_bClear && !m_aCurrentPageIds->second.empty() )
362 				m_aCurrentPageIds->second.clear();
363 		}
364 
365 		// the one for the ids of the referring controls
366 		m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage);
367 		if (m_aReferringControls.end() == m_aCurrentPageReferring)
368 		{
369 			m_aReferringControls[_rxDrawPage] = MapPropertySet2String();
370 			m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage);
371 		}
372 		else
373 		{
374 			bKnownPage = sal_True;
375 			if (_bClear && !m_aCurrentPageReferring->second.empty() )
376 				m_aCurrentPageReferring->second.clear();
377 		}
378 		return bKnownPage;
379 	}
380 
381 	//---------------------------------------------------------------------
382 	sal_Bool OFormLayerXMLExport_Impl::seekPage(const Reference< XDrawPage >& _rxDrawPage)
383 	{
384         sal_Bool bKnownPage = implMoveIterators( _rxDrawPage, sal_False );
385         if ( bKnownPage )
386             return sal_True;
387 
388         // if the page is not yet known, this does not automatically mean that it has
389         // not been examined. Instead, examineForms returns silently and successfully
390         // if a page is a XFormsPageSupplier2, but does not have a forms collection
391         // (This behaviour of examineForms is a performance optimization, to not force
392         // the page to create a forms container just to see that it's empty.)
393 
394         // So, in such a case, seekPage is considered to be successfull, too, though the
395         // page was not yet known
396 		Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY );
397         if ( xFormsSupp.is() && !xFormsSupp->hasForms() )
398             return sal_True;
399 
400         // anything else means that the page has not been examined before, or it's no
401         // valid form page. Both cases are Bad (TM).
402         return sal_False;
403 	}
404 
405 	//---------------------------------------------------------------------
406 	::rtl::OUString OFormLayerXMLExport_Impl::getControlId(const Reference< XPropertySet >& _rxControl)
407 	{
408 		OSL_ENSURE(m_aCurrentPageIds != m_aControlIds.end(), "OFormLayerXMLExport_Impl::getControlId: invalid current page!");
409 		OSL_ENSURE(m_aCurrentPageIds->second.end() != m_aCurrentPageIds->second.find(_rxControl),
410 			"OFormLayerXMLExport_Impl::getControlId: can not find the control!");
411 		return m_aCurrentPageIds->second[_rxControl];
412 	}
413 
414 	//---------------------------------------------------------------------
415 	::rtl::OUString OFormLayerXMLExport_Impl::getImmediateNumberStyle( const Reference< XPropertySet >& _rxObject )
416 	{
417 		::rtl::OUString sNumberStyle;
418 
419 		sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxObject );
420 		if ( -1 != nOwnFormatKey )
421 			sNumberStyle = getControlNumberStyleExport()->GetStyleName( nOwnFormatKey );
422 
423 		return sNumberStyle;
424 	}
425 
426 	//---------------------------------------------------------------------
427 	::rtl::OUString OFormLayerXMLExport_Impl::getControlNumberStyle( const Reference< XPropertySet >& _rxControl )
428 	{
429 		::rtl::OUString sNumberStyle;
430 
431 		ConstMapPropertySet2IntIterator aControlFormatPos = m_aControlNumberFormats.find(_rxControl);
432 		if (m_aControlNumberFormats.end() != aControlFormatPos)
433 		{
434 			OSL_ENSURE(m_pControlNumberStyles, "OFormLayerXMLExport_Impl::getControlNumberStyle: have a control which has a format style, but no style exporter!");
435 			sNumberStyle = getControlNumberStyleExport()->GetStyleName(aControlFormatPos->second);
436 		}
437 		// it's allowed to ask for a control which does not have format information.
438 		// (This is for performance reasons)
439 
440 		return sNumberStyle;
441 	}
442 
443 	//---------------------------------------------------------------------
444 	void OFormLayerXMLExport_Impl::examineForms(const Reference< XDrawPage >& _rxDrawPage)
445 	{
446 		// get the forms collection of the page
447 		Reference< XIndexAccess > xCollectionIndex;
448 		if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
449 			return;
450 
451 		// move the iterator which specify the currently handled page
452 #if OSL_DEBUG_LEVEL > 0
453 		sal_Bool bPageIsKnown =
454 #endif
455 			implMoveIterators(_rxDrawPage, sal_True);
456 		OSL_ENSURE(!bPageIsKnown, "OFormLayerXMLExport_Impl::examineForms: examining a page twice!");
457 
458 		::std::stack< Reference< XIndexAccess > >	aContainerHistory;
459 		::std::stack< sal_Int32 >					aIndexHistory;
460 
461 		Reference< XIndexAccess > xLoop = xCollectionIndex;
462 		sal_Int32 nChildPos = 0;
463 		do
464 		{
465 			if (nChildPos < xLoop->getCount())
466 			{
467 		        Reference< XPropertySet	> xCurrent( xLoop->getByIndex( nChildPos ), UNO_QUERY );
468 				OSL_ENSURE(xCurrent.is(), "OFormLayerXMLExport_Impl::examineForms: invalid child object");
469 				if (!xCurrent.is())
470 					continue;
471 
472 				if (!checkExamineControl(xCurrent))
473 				{
474 					// step down
475 					Reference< XIndexAccess > xNextContainer(xCurrent, UNO_QUERY);
476 					OSL_ENSURE(xNextContainer.is(), "OFormLayerXMLExport_Impl::examineForms: what the heck is this ... no control, no container?");
477 					aContainerHistory.push(xLoop);
478 					aIndexHistory.push(nChildPos);
479 
480 					xLoop = xNextContainer;
481 					nChildPos = -1;	// will be incremented below
482 				}
483 				++nChildPos;
484 			}
485 			else
486 			{
487 				// step up
488 				while ((nChildPos >= xLoop->getCount()) && !aContainerHistory.empty() )
489 				{
490 					xLoop = aContainerHistory.top();
491 					aContainerHistory.pop();
492 					nChildPos = aIndexHistory.top();
493 					aIndexHistory.pop();
494 
495 					++nChildPos;
496 				}
497 				if (nChildPos >= xLoop->getCount())
498 					// exited the loop above because we have no history anymore (0 == aContainerHistory.size()),
499 					// and on the current level there are no more children
500 					// -> leave
501 					break;
502 			}
503 		}
504 		while (xLoop.is());
505 	}
506 
507 	//---------------------------------------------------------------------
508     namespace
509     {
510         struct AccumulateSize : public ::std::binary_function< size_t, MapPropertySet2Map::value_type, size_t >
511         {
512             size_t operator()( size_t _size, const MapPropertySet2Map::value_type& _map ) const
513             {
514                 return _size + _map.second.size();
515             }
516         };
517 
518         ::rtl::OUString lcl_findFreeControlId( const MapPropertySet2Map& _rAllPagesControlIds )
519         {
520 		    static const ::rtl::OUString sControlIdBase( RTL_CONSTASCII_USTRINGPARAM( "control" ) );
521 			::rtl::OUString sControlId = sControlIdBase;
522 
523             size_t nKnownControlCount = ::std::accumulate( _rAllPagesControlIds.begin(), _rAllPagesControlIds.end(), (size_t)0, AccumulateSize() );
524             sControlId += ::rtl::OUString::valueOf( (sal_Int32)nKnownControlCount + 1 );
525 
526         #ifdef DBG_UTIL
527 			// Check if the id is already used. It shouldn't, as we currently have no mechanism for removing entries
528 			// from the map, so the approach used above (take the accumulated map size) should be sufficient. But if
529             // somebody changes this (e.g. allows removing entries from the map), the assertion below probably will fail.
530             for (   MapPropertySet2Map::const_iterator outer = _rAllPagesControlIds.begin();
531                     outer != _rAllPagesControlIds.end();
532                     ++outer
533                 )
534                 for (   MapPropertySet2String::const_iterator inner = outer->second.begin();
535                         inner != outer->second.end();
536                         ++inner
537                     )
538                 {
539 				    OSL_ENSURE( inner->second != sControlId,
540 					    "lcl_findFreeControlId: auto-generated control ID is already used!" );
541                 }
542 		#endif
543             return sControlId;
544         }
545     }
546 
547 	//---------------------------------------------------------------------
548 	sal_Bool OFormLayerXMLExport_Impl::checkExamineControl(const Reference< XPropertySet >& _rxObject)
549 	{
550 		Reference< XPropertySetInfo > xCurrentInfo = _rxObject->getPropertySetInfo();
551 		OSL_ENSURE(xCurrentInfo.is(), "OFormLayerXMLExport_Impl::checkExamineControl: no property set info");
552 
553 		sal_Bool bIsControl = xCurrentInfo->hasPropertyByName( PROPERTY_CLASSID );
554 		if (bIsControl)
555 		{
556 			// ----------------------------------
557 			// generate a new control id
558 
559 			// find a free id
560 			::rtl::OUString sCurrentId = lcl_findFreeControlId( m_aControlIds );
561 			// add it to the map
562 			m_aCurrentPageIds->second[_rxObject] = sCurrentId;
563 
564 			// ----------------------------------
565 			// check if this control has a "LabelControl" property referring another control
566 			if ( xCurrentInfo->hasPropertyByName( PROPERTY_CONTROLLABEL ) )
567 			{
568 				Reference< XPropertySet > xCurrentReference( _rxObject->getPropertyValue( PROPERTY_CONTROLLABEL ), UNO_QUERY );
569 				if (xCurrentReference.is())
570 				{
571 					::rtl::OUString& sReferencedBy = m_aCurrentPageReferring->second[xCurrentReference];
572 					if (sReferencedBy.getLength())
573 						// it's not the first _rxObject referring to the xCurrentReference
574 						// -> separate the id
575 						sReferencedBy += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(","));
576 					sReferencedBy += sCurrentId;
577 				}
578 			}
579 
580 			// ----------------------------------
581 			// check if the control needs a number format style
582 			if ( xCurrentInfo->hasPropertyByName( PROPERTY_FORMATKEY ) )
583 			{
584 				examineControlNumberFormat(_rxObject);
585 			}
586 
587 			// ----------------------------------
588             // check if it's a control providing text
589             Reference< XText > xControlText( _rxObject, UNO_QUERY );
590             if ( xControlText.is() )
591             {
592 				m_rContext.GetTextParagraphExport()->collectTextAutoStyles( xControlText );
593             }
594 
595 			// ----------------------------------
596 			// check if it is a grid control - in this case, we need special handling for the columns
597 			sal_Int16 nControlType = FormComponentType::CONTROL;
598 			_rxObject->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType;
599 			if ( FormComponentType::GRIDCONTROL == nControlType )
600 			{
601 				collectGridColumnStylesAndIds( _rxObject );
602 			}
603 		}
604 
605 		return bIsControl;
606 	}
607 
608 	//---------------------------------------------------------------------
609 	void OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds( const Reference< XPropertySet >& _rxControl )
610 	{
611 		// loop through all columns of the grid
612 		try
613 		{
614 			Reference< XIndexAccess > xContainer( _rxControl, UNO_QUERY );
615 			OSL_ENSURE( xContainer.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: grid control not being a container?!" );
616             if ( !xContainer.is() )
617                 return;
618 
619 			Reference< XPropertySetInfo > xColumnPropertiesMeta;
620 
621 			sal_Int32 nCount = xContainer->getCount();
622 			for ( sal_Int32 i=0; i<nCount; ++i )
623 			{
624                 Reference< XPropertySet > xColumnProperties( xContainer->getByIndex( i ), UNO_QUERY );
625                 OSL_ENSURE( xColumnProperties.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: invalid grid column encountered!" );
626                 if ( !xColumnProperties.is() )
627                     continue;
628 
629 			    // ----------------------------------
630 			    // generate a new control id
631 
632 			    // find a free id
633 			    ::rtl::OUString sCurrentId = lcl_findFreeControlId( m_aControlIds );
634 			    // add it to the map
635 			    m_aCurrentPageIds->second[ xColumnProperties ] = sCurrentId;
636 
637 			    // ----------------------------------
638                 // determine a number style, if needed
639 				xColumnPropertiesMeta = xColumnProperties->getPropertySetInfo();
640 				// get the styles of the column
641 				::std::vector< XMLPropertyState > aPropertyStates = m_xStyleExportMapper->Filter( xColumnProperties );
642 
643 				// care for the number format, additionally
644 				::rtl::OUString sColumnNumberStyle;
645 				if ( xColumnPropertiesMeta.is() && xColumnPropertiesMeta->hasPropertyByName( PROPERTY_FORMATKEY ) )
646 					sColumnNumberStyle = getImmediateNumberStyle( xColumnProperties );
647 
648 				if ( sColumnNumberStyle.getLength() )
649 				{	// the column indeed has a formatting
650 					sal_Int32 nStyleMapIndex = m_xStyleExportMapper->getPropertySetMapper()->FindEntryIndex( CTF_FORMS_DATA_STYLE );
651 						// TODO: move this to the ctor
652 					OSL_ENSURE ( -1 != nStyleMapIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
653 
654 					XMLPropertyState aNumberStyleState( nStyleMapIndex, makeAny( sColumnNumberStyle ) );
655 					aPropertyStates.push_back( aNumberStyleState );
656 				}
657 
658 #if OSL_DEBUG_LEVEL > 0
659 				::std::vector< XMLPropertyState >::const_iterator aHaveALook = aPropertyStates.begin();
660 				for ( ; aHaveALook != aPropertyStates.end(); ++aHaveALook )
661 				{
662                     (void)aHaveALook;
663 				}
664 #endif
665 
666 			    // ----------------------------------
667                 // determine the column style
668 
669 				if ( !aPropertyStates.empty() )
670 				{	// add to the style pool
671 					::rtl::OUString sColumnStyleName = m_rContext.GetAutoStylePool()->Add( XML_STYLE_FAMILY_CONTROL_ID, aPropertyStates );
672 
673 					OSL_ENSURE( m_aGridColumnStyles.end() == m_aGridColumnStyles.find( xColumnProperties ),
674 						"OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: already have a style for this column!" );
675 
676 					m_aGridColumnStyles.insert( MapPropertySet2String::value_type( xColumnProperties, sColumnStyleName ) );
677 				}
678 			}
679 		}
680 		catch( const Exception&	)
681 		{
682             DBG_UNHANDLED_EXCEPTION();
683 		}
684 	}
685 
686 	//---------------------------------------------------------------------
687 	sal_Int32 OFormLayerXMLExport_Impl::implExamineControlNumberFormat( const Reference< XPropertySet >& _rxObject )
688 	{
689 		// get the format key relative to our own formats supplier
690 		sal_Int32 nOwnFormatKey = ensureTranslateFormat( _rxObject );
691 
692 		if ( -1 != nOwnFormatKey )
693 			// tell the exporter that we used this format
694 			getControlNumberStyleExport()->SetUsed( nOwnFormatKey );
695 
696 		return nOwnFormatKey;
697 	}
698 
699 	//---------------------------------------------------------------------
700 	void OFormLayerXMLExport_Impl::examineControlNumberFormat( const Reference< XPropertySet >& _rxControl )
701 	{
702 		sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxControl );
703 
704 		if ( -1 == nOwnFormatKey )
705 			// nothing to do, the number format of this control is void
706 			return;
707 
708 		// remember the format key for this control (we'll be asked in getControlNumberStyle for this)
709 		OSL_ENSURE(m_aControlNumberFormats.end() == m_aControlNumberFormats.find(_rxControl),
710 			"OFormLayerXMLExport_Impl::examineControlNumberFormat: already handled this control!");
711 		m_aControlNumberFormats[_rxControl] = nOwnFormatKey;
712 	}
713 
714 	//---------------------------------------------------------------------
715 	sal_Int32 OFormLayerXMLExport_Impl::ensureTranslateFormat(const Reference< XPropertySet >& _rxFormattedControl)
716 	{
717 		ensureControlNumberStyleExport();
718 		OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: no own formats supplier!");
719 			// (should have been created in ensureControlNumberStyleExport)
720 
721 		sal_Int32 nOwnFormatKey = -1;
722 
723 		// the format key (relative to the control's supplier)
724 		sal_Int32 nControlFormatKey = -1;
725 		Any aControlFormatKey = _rxFormattedControl->getPropertyValue(PROPERTY_FORMATKEY);
726 		if (aControlFormatKey >>= nControlFormatKey)
727 		{
728 			// the control's number format
729 			Reference< XNumberFormatsSupplier > xControlFormatsSupplier;
730 			_rxFormattedControl->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xControlFormatsSupplier;
731 			Reference< XNumberFormats > xControlFormats;
732 			if (xControlFormatsSupplier.is())
733 				xControlFormats = xControlFormatsSupplier->getNumberFormats();
734 			OSL_ENSURE(xControlFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: formatted control without supplier!");
735 
736 			// obtain the persistent (does not depend on the formats supplier) representation of the control's format
737 			Locale aFormatLocale;
738 			::rtl::OUString sFormatDescription;
739 			if (xControlFormats.is())
740 			{
741 				Reference< XPropertySet > xControlFormat = xControlFormats->getByKey(nControlFormatKey);
742 
743 				xControlFormat->getPropertyValue(PROPERTY_LOCALE)		>>= aFormatLocale;
744 				xControlFormat->getPropertyValue(PROPERTY_FORMATSTRING)	>>= sFormatDescription;
745 			}
746 
747 			// check if our own formats collection already knows the format
748 			nOwnFormatKey = m_xControlNumberFormats->queryKey(sFormatDescription, aFormatLocale, sal_False);
749 			if (-1 == nOwnFormatKey)
750 			{	// no, we don't
751 				// -> create a new format
752 				nOwnFormatKey = m_xControlNumberFormats->addNew(sFormatDescription, aFormatLocale);
753 			}
754 			OSL_ENSURE(-1 != nOwnFormatKey, "OFormLayerXMLExport_Impl::ensureTranslateFormat: could not translate the controls format key!");
755 		}
756 		else
757 			OSL_ENSURE(!aControlFormatKey.hasValue(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: invalid number format property value!");
758 
759 		return nOwnFormatKey;
760 	}
761 
762 	//---------------------------------------------------------------------
763 	void OFormLayerXMLExport_Impl::ensureControlNumberStyleExport()
764 	{
765 		if (!m_pControlNumberStyles)
766 		{
767 			// create our number formats supplier (if necessary)
768 			Reference< XNumberFormatsSupplier > xFormatsSupplier;
769 
770 			OSL_ENSURE(!m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: inconsistence!");
771 				// the m_xControlNumberFormats and m_pControlNumberStyles should be maintained together
772 
773 			try
774 			{
775 				// create it for en-US (does not really matter, as we will specify a locale for every
776 				// concrete language to use)
777 				Sequence< Any > aSupplierArgs(1);
778 				aSupplierArgs[0] <<= Locale	(	::rtl::OUString::createFromAscii("en"),
779 												::rtl::OUString::createFromAscii("US"),
780 												::rtl::OUString()
781 											);
782 				// #110680#
783 				//Reference< XInterface > xFormatsSupplierUntyped =
784 				//	::comphelper::getProcessServiceFactory()->createInstanceWithArguments(
785 				//		SERVICE_NUMBERFORMATSSUPPLIER,
786 				//		aSupplierArgs
787 				//	);
788 				Reference< XInterface > xFormatsSupplierUntyped =
789 					m_rContext.getServiceFactory()->createInstanceWithArguments(
790 						SERVICE_NUMBERFORMATSSUPPLIER,
791 						aSupplierArgs
792 					);
793 				OSL_ENSURE(xFormatsSupplierUntyped.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: could not instantiate a number formats supplier!");
794 
795 				xFormatsSupplier = Reference< XNumberFormatsSupplier >(xFormatsSupplierUntyped, UNO_QUERY);
796 				if (xFormatsSupplier.is())
797 					m_xControlNumberFormats = xFormatsSupplier->getNumberFormats();
798 			}
799 			catch(const Exception&)
800 			{
801 			}
802 
803 			OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: could not obtain my default number formats!");
804 
805 			// create the exporter
806 			m_pControlNumberStyles = new SvXMLNumFmtExport(m_rContext, xFormatsSupplier, getControlNumberStyleNamePrefix());
807 		}
808 	}
809 
810 	//---------------------------------------------------------------------
811 	SvXMLNumFmtExport* OFormLayerXMLExport_Impl::getControlNumberStyleExport()
812 	{
813 		ensureControlNumberStyleExport();
814 		return m_pControlNumberStyles;
815 	}
816 
817 	//---------------------------------------------------------------------
818 	void OFormLayerXMLExport_Impl::excludeFromExport( const Reference< XControlModel > _rxControl )
819 	{
820 		Reference< XPropertySet > xProps( _rxControl, UNO_QUERY );
821 		OSL_ENSURE( xProps.is(), "OFormLayerXMLExport_Impl::excludeFromExport: invalid control model!" );
822 #if OSL_DEBUG_LEVEL > 0
823 		::std::pair< PropertySetBag::iterator, bool > aPos =
824 #endif
825 		m_aIgnoreList.insert( xProps );
826 		OSL_ENSURE( aPos.second, "OFormLayerXMLExport_Impl::excludeFromExport: element already exists in the ignore list!" );
827 	}
828 
829 //.........................................................................
830 }	// namespace xmloff
831 //.........................................................................
832 
833 
834