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