/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// add our style family to the export context's style pool
m_xPropertyHandlerFactory = new OControlPropertyHandlerFactory();
::rtl::Reference< XMLPropertySetMapper > xStylePropertiesMapper = new XMLPropertySetMapper( getControlStylePropertyMap(), m_xPropertyHandlerFactory, true );
m_xStyleExportMapper = new OFormComponentStyleExportMapper( xStylePropertiesMapper );
// our style family
m_rContext.GetAutoStylePool()->AddFamily(
XmlStyleFamily::CONTROL_ID, token::GetXMLToken(token::XML_PARAGRAPH),
m_xStyleExportMapper.get(),
XML_STYLE_FAMILY_CONTROL_PREFIX
);
if ( !xFormsSupp->hasForms() ) // nothing to do at all returnfalse;
_rxForms.set(xFormsSupp->getForms(), UNO_QUERY);
Reference< XServiceInfo > xSI(_rxForms, UNO_QUERY); // order is important!
OSL_ENSURE(xSI.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (must not be NULL and must have a ServiceInfo)!"); if (!xSI.is()) returnfalse;
if (!xSI->supportsService(u"com.sun.star.form.Forms"_ustr))
{
OSL_FAIL("OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (is no com.sun.star.form.Forms)!"); // nothing to do returnfalse;
} returntrue;
}
void OFormLayerXMLExport_Impl::exportCollectionElements(const Reference< XIndexAccess >& _rxCollection)
{ // step through all the elements of the collection
sal_Int32 nElements = _rxCollection->getCount();
Reference< XPropertySetInfo > xPropsInfo; for (sal_Int32 i=0; i<nElements; ++i)
{ try
{ // extract the current element
Reference< XPropertySet > xCurrentProps( _rxCollection->getByIndex(i), UNO_QUERY );
OSL_ENSURE(xCurrentProps.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: invalid child element, skipping!"); if (!xCurrentProps.is()) continue;
// check if there is a ClassId property on the current element. If so, we assume it to be a control
xPropsInfo = xCurrentProps->getPropertySetInfo();
OSL_ENSURE(xPropsInfo.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: no property set info!"); if (!xPropsInfo.is()) // without this, a lot of stuff in the export routines may fail continue;
// if the element is part of an ignore list, we are not allowed to export it if ( m_aIgnoreList.end() != m_aIgnoreList.find( xCurrentProps ) ) continue;
if (xElementEventManager.is())
aElementEvents = xElementEventManager->getScriptEvents(i);
if (xPropsInfo->hasPropertyByName(PROPERTY_COLUMNSERVICENAME))
{
exportGridColumn(xCurrentProps, aElementEvents);
} elseif (xPropsInfo->hasPropertyByName(PROPERTY_CLASSID))
{
exportControl(xCurrentProps, aElementEvents);
} else
{
exportForm(xCurrentProps, aElementEvents);
}
} catch(Exception&)
{
TOOLS_WARN_EXCEPTION("xmloff.forms", "caught an exception ... skipping the current element!"); continue;
}
}
}
void OFormLayerXMLExport_Impl::exportForms(const Reference< XDrawPage >& _rxDrawPage)
{ // get the forms collection of the page
Reference< XIndexAccess > xCollectionIndex; if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
{ return;
}
bool bPageIsKnown = implMoveIterators(_rxDrawPage, false);
OSL_ENSURE(bPageIsKnown, "OFormLayerXMLExport_Impl::exportForms: exporting a page which has not been examined!");
// export forms collection
exportCollectionElements(xCollectionIndex);
}
// the one for the ids
m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage); if (m_aControlIds.end() == m_aCurrentPageIds)
{
m_aControlIds[_rxDrawPage] = MapPropertySet2String();
m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage);
} else
{
bKnownPage = true; if (_bClear && !m_aCurrentPageIds->second.empty() )
m_aCurrentPageIds->second.clear();
}
// the one for the ids of the referring controls
m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage); if (m_aReferringControls.end() == m_aCurrentPageReferring)
{
m_aReferringControls[_rxDrawPage] = MapPropertySet2String();
m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage);
} else
{
bKnownPage = true; if (_bClear && !m_aCurrentPageReferring->second.empty() )
m_aCurrentPageReferring->second.clear();
} return bKnownPage;
}
// if the page is not yet known, this does not automatically mean that it has // not been examined. Instead, examineForms returns silently and successfully // if a page is a XFormsPageSupplier2, but does not have a forms collection // (This behaviour of examineForms is a performance optimization, to not force // the page to create a forms container just to see that it's empty.)
// So, in such a case, seekPage is considered to be successful, too, though the // page was not yet known
Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY ); if ( xFormsSupp.is() && !xFormsSupp->hasForms() ) returntrue;
// anything else means that the page has not been examined before, or it's no // valid form page. Both cases are Bad (TM). returnfalse;
}
OSL_ENSURE(m_aCurrentPageIds->second.end() != m_aCurrentPageIds->second.find(_rxControl), "OFormLayerXMLExport_Impl::getControlId: can not find the control!"); return m_aCurrentPageIds->second[_rxControl];
}
MapPropertySet2Int::const_iterator aControlFormatPos = m_aControlNumberFormats.find(_rxControl); if (m_aControlNumberFormats.end() != aControlFormatPos)
{
OSL_ENSURE(m_pControlNumberStyles, "OFormLayerXMLExport_Impl::getControlNumberStyle: have a control which has a format style, but no style exporter!");
sNumberStyle = getControlNumberStyleExport()->GetStyleName(aControlFormatPos->second);
} // it's allowed to ask for a control which does not have format information. // (This is for performance reasons)
return sNumberStyle;
}
void OFormLayerXMLExport_Impl::examineForms(const Reference< XDrawPage >& _rxDrawPage)
{ // get the forms collection of the page
Reference< XIndexAccess > xCollectionIndex; if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex))
{ return;
}
// move the iterator which specify the currently handled page bool bPageIsKnown = implMoveIterators(_rxDrawPage, true);
OSL_ENSURE(!bPageIsKnown, "OFormLayerXMLExport_Impl::examineForms: examining a page twice!");
if (!checkExamineControl(xCurrent))
{ // step down
Reference< XIndexAccess > xNextContainer(xCurrent, UNO_QUERY);
OSL_ENSURE(xNextContainer.is(), "OFormLayerXMLExport_Impl::examineForms: what the heck is this ... no control, no container?");
aContainerHistory.push(xLoop);
aIndexHistory.push(nChildPos);
xLoop = std::move(xNextContainer);
nChildPos = -1; // will be incremented below
}
++nChildPos;
} else
{ // step up while ((nChildPos >= xLoop->getCount()) && !aContainerHistory.empty() )
{
xLoop = aContainerHistory.top();
aContainerHistory.pop();
nChildPos = aIndexHistory.top();
aIndexHistory.pop();
++nChildPos;
} if (nChildPos >= xLoop->getCount()) // exited the loop above because we have no history anymore (0 == aContainerHistory.size()), // and on the current level there are no more children // -> leave break;
}
} while (xLoop.is());
}
#ifdef DBG_UTIL // Check if the id is already used. It shouldn't, as we currently have no mechanism for removing entries // from the map, so the approach used above (take the accumulated map size) should be sufficient. But if // somebody changes this (e.g. allows removing entries from the map), the assertion below probably will fail. for ( constauto& outer : _rAllPagesControlIds ) for ( constauto& inner : outer.second )
{
OSL_ENSURE( inner.second != sControlId, "lcl_findFreeControlId: auto-generated control ID is already used!" );
} #endif return sControlId;
}
}
bool OFormLayerXMLExport_Impl::checkExamineControl(const Reference< XPropertySet >& _rxObject)
{
Reference< XPropertySetInfo > xCurrentInfo = _rxObject->getPropertySetInfo();
OSL_ENSURE(xCurrentInfo.is(), "OFormLayerXMLExport_Impl::checkExamineControl: no property set info");
bool bIsControl = xCurrentInfo->hasPropertyByName( PROPERTY_CLASSID ); if (bIsControl)
{ // generate a new control id
// find a free id
OUString sCurrentId = lcl_findFreeControlId( m_aControlIds ); // add it to the map
m_aCurrentPageIds->second[_rxObject] = sCurrentId;
// check if this control has a "LabelControl" property referring another control if ( xCurrentInfo->hasPropertyByName( PROPERTY_CONTROLLABEL ) )
{
Reference< XPropertySet > xCurrentReference( _rxObject->getPropertyValue( PROPERTY_CONTROLLABEL ), UNO_QUERY ); if (xCurrentReference.is())
{
OUString& sReferencedBy = m_aCurrentPageReferring->second[xCurrentReference]; if (!sReferencedBy.isEmpty()) // it's not the first _rxObject referring to the xCurrentReference // -> separate the id
sReferencedBy += ",";
sReferencedBy += sCurrentId;
}
}
// check if the control needs a number format style if ( xCurrentInfo->hasPropertyByName( PROPERTY_FORMATKEY ) )
{
examineControlNumberFormat(_rxObject);
}
// check if it's a control providing text
Reference< XText > xControlText( _rxObject, UNO_QUERY ); if ( xControlText.is() )
{ try
{ // tdf#120397: similar to the fix of tdf#153161 where // XTextRange::getText() --> ::GetSelection() flushes the changes // for some Shape objects we also need to set the end cursor pos // to the end of the form text objects, otherwise fail to get // exported correctly. Maybe at some point it would make sense // to find a better place for more targeted flush.
xControlText = xControlText->getText();
} catch (css::uno::RuntimeException const&)
{ // just in case if we would hit something here
}
m_rContext.GetTextParagraphExport()->collectTextAutoStyles( xControlText );
}
// check if it is a grid control - in this case, we need special handling for the columns
sal_Int16 nControlType = FormComponentType::CONTROL;
_rxObject->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType; if ( FormComponentType::GRIDCONTROL == nControlType )
{
collectGridColumnStylesAndIds( _rxObject );
}
}
return bIsControl;
}
void OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds( const Reference< XPropertySet >& _rxControl )
{ // loop through all columns of the grid try
{
Reference< XIndexAccess > xContainer( _rxControl, UNO_QUERY );
OSL_ENSURE( xContainer.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: grid control not being a container?!" ); if ( !xContainer.is() ) return;
// find a free id and add it to the map
m_aCurrentPageIds->second[xColumnProperties] = lcl_findFreeControlId(m_aControlIds);
// determine a number style, if needed
xColumnPropertiesMeta = xColumnProperties->getPropertySetInfo(); // get the styles of the column
::std::vector<XMLPropertyState> aPropertyStates = m_xStyleExportMapper->Filter(m_rContext, xColumnProperties);
// care for the number format, additionally
OUString sColumnNumberStyle; if ( xColumnPropertiesMeta.is() && xColumnPropertiesMeta->hasPropertyByName( PROPERTY_FORMATKEY ) )
sColumnNumberStyle = getImmediateNumberStyle( xColumnProperties );
if ( !sColumnNumberStyle.isEmpty() )
{ // the column indeed has a formatting
sal_Int32 nStyleMapIndex = m_xStyleExportMapper->getPropertySetMapper()->FindEntryIndex( CTF_FORMS_DATA_STYLE ); // TODO: move this to the ctor
OSL_ENSURE ( -1 != nStyleMapIndex, "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: could not obtain the index for our context id!");
if ( !aPropertyStates.empty() )
{ // add to the style pool
OUString sColumnStyleName = m_rContext.GetAutoStylePool()->Add( XmlStyleFamily::CONTROL_ID, std::move(aPropertyStates) );
OSL_ENSURE( m_aGridColumnStyles.end() == m_aGridColumnStyles.find( xColumnProperties ), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: already have a style for this column!" );
if ( -1 == nOwnFormatKey ) // nothing to do, the number format of this control is void return;
// remember the format key for this control (we'll be asked in getControlNumberStyle for this)
OSL_ENSURE(m_aControlNumberFormats.end() == m_aControlNumberFormats.find(_rxControl), "OFormLayerXMLExport_Impl::examineControlNumberFormat: already handled this control!");
m_aControlNumberFormats[_rxControl] = nOwnFormatKey;
}
sal_Int32 OFormLayerXMLExport_Impl::ensureTranslateFormat(const Reference< XPropertySet >& _rxFormattedControl)
{
ensureControlNumberStyleExport();
OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: no own formats supplier!"); // (should have been created in ensureControlNumberStyleExport)
sal_Int32 nOwnFormatKey = -1;
// the format key (relative to the control's supplier)
sal_Int32 nControlFormatKey = -1;
Any aControlFormatKey = _rxFormattedControl->getPropertyValue(PROPERTY_FORMATKEY); if (aControlFormatKey >>= nControlFormatKey)
{ // the control's number format
Reference< XNumberFormatsSupplier > xControlFormatsSupplier;
_rxFormattedControl->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xControlFormatsSupplier;
Reference< XNumberFormats > xControlFormats; if (xControlFormatsSupplier.is())
xControlFormats = xControlFormatsSupplier->getNumberFormats();
OSL_ENSURE(xControlFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: formatted control without supplier!");
// obtain the persistent (does not depend on the formats supplier) representation of the control's format
Locale aFormatLocale;
OUString sFormatDescription; if (xControlFormats.is())
{
Reference< XPropertySet > xControlFormat = xControlFormats->getByKey(nControlFormatKey);
// check if our own formats collection already knows the format
nOwnFormatKey = m_xControlNumberFormats->queryKey(sFormatDescription, aFormatLocale, false); if (-1 == nOwnFormatKey)
{ // no, we don't // -> create a new format
nOwnFormatKey = m_xControlNumberFormats->addNew(sFormatDescription, aFormatLocale);
}
OSL_ENSURE(-1 != nOwnFormatKey, "OFormLayerXMLExport_Impl::ensureTranslateFormat: could not translate the controls format key!");
} else
OSL_ENSURE(!aControlFormatKey.hasValue(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: invalid number format property value!");
return nOwnFormatKey;
}
void OFormLayerXMLExport_Impl::ensureControlNumberStyleExport()
{ if (m_pControlNumberStyles) return;
OSL_ENSURE(!m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: inconsistence!"); // the m_xControlNumberFormats and m_pControlNumberStyles should be maintained together
try
{ // create it for en-US (does not really matter, as we will specify a locale for every // concrete language to use)
Locale aLocale ( u"en"_ustr, u"US"_ustr, OUString() );
xFormatsSupplier = NumberFormatsSupplier::createWithLocale( m_rContext.getComponentContext(), aLocale );
m_xControlNumberFormats = xFormatsSupplier->getNumberFormats();
} catch(const Exception&)
{
}
OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: could not obtain my default number formats!");
// create the exporter
m_pControlNumberStyles = std::make_unique<SvXMLNumFmtExport>(m_rContext, xFormatsSupplier, getControlNumberStyleNamePrefix());
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.