LibreOffice Module reportdesign (master)  1
xmlExportDocumentHandler.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
21 #include <officecfg/Office/Common.hxx>
22 #include <com/sun/star/sdb/CommandType.hpp>
23 #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
24 #include <com/sun/star/chart/XComplexDescriptionAccess.hpp>
25 #include <com/sun/star/reflection/ProxyFactory.hpp>
29 #include <xmloff/attrlist.hxx>
30 #include <xmloff/xmltoken.hxx>
31 #include <xmloff/xmlement.hxx>
32 #include <xmloff/xmluconv.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <connectivity/dbtools.hxx>
35 
36 namespace rptxml
37 {
38 using namespace ::com::sun::star;
39 using namespace ::xmloff::token;
40 
41 static void lcl_exportPrettyPrinting(const uno::Reference< xml::sax::XDocumentHandler >& _xDelegatee)
42 {
43  if ( officecfg::Office::Common::Save::Document::PrettyPrinting::get() )
44  {
45  _xDelegatee->ignorableWhitespace(" ");
46  }
47 }
48 
49 OUString lcl_createAttribute(const xmloff::token::XMLTokenEnum& _eNamespace,const xmloff::token::XMLTokenEnum& _eAttribute)
50 {
51  return
52  // ...if it's in our map, make the prefix
53  xmloff::token::GetXMLToken(_eNamespace) +
54  ":" +
55  xmloff::token::GetXMLToken(_eAttribute);
56 }
57 
58 static void lcl_correctCellAddress(const OUString & _sName, const uno::Reference< xml::sax::XAttributeList > & xAttribs)
59 {
60  SvXMLAttributeList* pList = comphelper::getFromUnoTunnel<SvXMLAttributeList>(xAttribs);
61  OUString sCellAddress = pList->getValueByName(_sName);
62  const sal_Int32 nPos = sCellAddress.lastIndexOf('$');
63  if ( nPos != -1 )
64  {
65  sCellAddress = OUString::Concat(sCellAddress.subView(0,nPos)) + "$65535";
66  pList->RemoveAttribute(_sName);
67  pList->AddAttribute(_sName,sCellAddress);
68  }
69 }
70 
71 ExportDocumentHandler::ExportDocumentHandler(uno::Reference< uno::XComponentContext > const & context) :
72  m_xContext(context)
73  ,m_nColumnCount(0)
74  ,m_bTableRowsStarted(false)
75  ,m_bFirstRowExported(false)
76  ,m_bCountColumnHeader(false)
77 {
78 }
79 
80 ExportDocumentHandler::~ExportDocumentHandler()
81 {
82  if ( m_xProxy.is() )
83  {
84  m_xProxy->setDelegator( nullptr );
85  m_xProxy.clear();
86  }
87 }
89 
90 OUString SAL_CALL ExportDocumentHandler::getImplementationName( )
91 {
92  return "com.sun.star.comp.report.ExportDocumentHandler";
93 }
94 
95 sal_Bool SAL_CALL ExportDocumentHandler::supportsService( const OUString& ServiceName )
96 {
97  return cppu::supportsService(this, ServiceName);
98 }
99 
100 uno::Sequence< OUString > SAL_CALL ExportDocumentHandler::getSupportedServiceNames( )
101 {
102  uno::Sequence< OUString > aSupported;
103  if ( m_xServiceInfo.is() )
104  aSupported = m_xServiceInfo->getSupportedServiceNames();
105  return ::comphelper::concatSequences(uno::Sequence< OUString > { "com.sun.star.report.ExportDocumentHandler" },aSupported);
106 }
107 
108 // xml::sax::XDocumentHandler:
109 void SAL_CALL ExportDocumentHandler::startDocument()
110 {
111  m_xDelegatee->startDocument();
112 }
113 
114 void SAL_CALL ExportDocumentHandler::endDocument()
115 {
116  m_xDelegatee->endDocument();
117 }
118 
119 void SAL_CALL ExportDocumentHandler::startElement(const OUString & _sName, const uno::Reference< xml::sax::XAttributeList > & xAttribs)
120 {
121  bool bExport = true;
122  if ( _sName == "office:chart" )
123  {
125  OUStringBuffer sValue;
126  static const SvXMLEnumMapEntry<sal_uInt16> aXML_CommandTypeEnumMap[] =
127  {
128  { XML_TABLE, sdb::CommandType::TABLE },
129  { XML_QUERY, sdb::CommandType::QUERY },
130  { XML_TOKEN_INVALID, 0 }
131  };
132  if ( SvXMLUnitConverter::convertEnum( sValue, static_cast<sal_uInt16>(m_xDatabaseDataProvider->getCommandType()),aXML_CommandTypeEnumMap ) )
133  {
134  pList->AddAttribute(lcl_createAttribute(XML_NP_RPT,XML_COMMAND_TYPE),sValue.makeStringAndClear());
135  }
136  const OUString sCommand = m_xDatabaseDataProvider->getCommand();
137  if ( !sCommand.isEmpty() )
138  pList->AddAttribute(lcl_createAttribute(XML_NP_RPT,XML_COMMAND),sCommand);
139 
140  const OUString sFilter( m_xDatabaseDataProvider->getFilter() );
141  if ( !sFilter.isEmpty() )
142  pList->AddAttribute(lcl_createAttribute(XML_NP_RPT,XML_FILTER),sFilter);
143 
144  const bool bEscapeProcessing( m_xDatabaseDataProvider->getEscapeProcessing() );
145  if ( !bEscapeProcessing )
147 
149 
150  m_xDelegatee->startElement(lcl_createAttribute(XML_NP_OFFICE,XML_REPORT),pList);
151 
152  const OUString sTableCalc = lcl_createAttribute(XML_NP_TABLE,XML_CALCULATION_SETTINGS);
153  m_xDelegatee->startElement(sTableCalc,nullptr);
154  pList = new SvXMLAttributeList();
155  pList->AddAttribute(lcl_createAttribute(XML_NP_TABLE,XML_DATE_VALUE),"1899-12-30");
156 
157  const OUString sNullDate = lcl_createAttribute(XML_NP_TABLE,XML_NULL_DATE);
158  m_xDelegatee->startElement(sNullDate,pList);
159  m_xDelegatee->endElement(sNullDate);
160  m_xDelegatee->endElement(sTableCalc);
161  bExport = false;
162  }
163  else if ( _sName == "table:table" )
164  {
165  m_xDelegatee->startElement(lcl_createAttribute(XML_NP_RPT,XML_DETAIL),nullptr);
166  lcl_exportPrettyPrinting(m_xDelegatee);
167  }
168  else if ( _sName == "table:table-header-rows" )
169  {
170  m_bCountColumnHeader = true;
171  }
172  else if ( m_bCountColumnHeader && _sName == "table:table-cell" )
173  {
174  ++m_nColumnCount;
175  }
176  else if ( _sName == "table:table-rows" )
177  {
178  m_xDelegatee->startElement(_sName,xAttribs);
179  exportTableRows();
180  bExport = false;
181  m_bTableRowsStarted = true;
182  m_bFirstRowExported = true;
183  }
184  else if ( m_bTableRowsStarted && m_bFirstRowExported && (_sName == "table:table-row" || _sName == "table:table-cell") )
185  bExport = false;
186  else if ( _sName == "chart:plot-area" )
187  {
188  SvXMLAttributeList* pList = comphelper::getFromUnoTunnel<SvXMLAttributeList>(xAttribs);
189  pList->RemoveAttribute("table:cell-range-address");
190  }
191  else if ( _sName == "chart:categories" )
192  {
193  static OUString s_sCellAddress(lcl_createAttribute(XML_NP_TABLE,XML_CELL_RANGE_ADDRESS));
194  lcl_correctCellAddress(s_sCellAddress,xAttribs);
195  }
196  else if ( _sName == "chart:series" )
197  {
198  static OUString s_sCellAddress(lcl_createAttribute(XML_NP_CHART,XML_VALUES_CELL_RANGE_ADDRESS));
199  lcl_correctCellAddress(s_sCellAddress,xAttribs);
200  }
201  else if ( m_bTableRowsStarted && !m_bFirstRowExported && _sName == "table:table-cell" )
202  {
203  SvXMLAttributeList* pList = comphelper::getFromUnoTunnel<SvXMLAttributeList>(xAttribs);
204  static OUString s_sValue(lcl_createAttribute(XML_NP_OFFICE,XML_VALUE));
205  pList->RemoveAttribute(s_sValue);
206  }
207  else if ( m_bTableRowsStarted && _sName == "text:p" )
208  {
209  bExport = false;
210  }
211  if ( bExport )
212  m_xDelegatee->startElement(_sName,xAttribs);
213 }
214 
215 void SAL_CALL ExportDocumentHandler::endElement(const OUString & _sName)
216 {
217  bool bExport = true;
218  OUString sNewName = _sName;
219  if ( _sName == "office:chart" )
220  {
222  }
223  else if ( _sName == "table:table" )
224  {
225  m_xDelegatee->endElement(_sName);
226  lcl_exportPrettyPrinting(m_xDelegatee);
228  }
229  else if ( _sName == "table:table-header-rows" )
230  {
231  m_bCountColumnHeader = false;
232  }
233  else if ( _sName == "table:table-rows" )
234  m_bTableRowsStarted = false;
235  else if ( m_bTableRowsStarted && m_bFirstRowExported && (_sName == "table:table-row" || _sName == "table:table-cell") )
236  bExport = false;
237  else if ( m_bTableRowsStarted && _sName == "table:table-row" )
238  m_bFirstRowExported = true;
239  else if ( m_bTableRowsStarted && _sName == "text:p" )
240  {
241  bExport = !m_bFirstRowExported;
242  }
243 
244  if ( bExport )
245  m_xDelegatee->endElement(sNewName);
246 }
247 
248 void SAL_CALL ExportDocumentHandler::characters(const OUString & aChars)
249 {
250  if ( !(m_bTableRowsStarted || m_bFirstRowExported) )
251  {
252  m_xDelegatee->characters(aChars);
253  }
254 }
255 
256 void SAL_CALL ExportDocumentHandler::ignorableWhitespace(const OUString & aWhitespaces)
257 {
258  m_xDelegatee->ignorableWhitespace(aWhitespaces);
259 }
260 
261 void SAL_CALL ExportDocumentHandler::processingInstruction(const OUString & aTarget, const OUString & aData)
262 {
263  m_xDelegatee->processingInstruction(aTarget,aData);
264 }
265 
266 void SAL_CALL ExportDocumentHandler::setDocumentLocator(const uno::Reference< xml::sax::XLocator > & xLocator)
267 {
268  m_xDelegatee->setDocumentLocator(xLocator);
269 }
270 void SAL_CALL ExportDocumentHandler::initialize( const uno::Sequence< uno::Any >& _aArguments )
271 {
272  ::osl::MutexGuard aGuard(m_aMutex);
273  comphelper::SequenceAsHashMap aArgs(_aArguments);
274  m_xDelegatee = aArgs.getUnpackedValueOrDefault("DocumentHandler",m_xDelegatee);
276 
277  OSL_ENSURE(m_xDelegatee.is(),"No document handler available!");
278  if ( !m_xDelegatee.is() || !m_xModel.is() )
279  throw uno::Exception("no delegatee and no model", nullptr);
280 
281  m_xDatabaseDataProvider.set(m_xModel->getDataProvider(),uno::UNO_QUERY_THROW);
282  if ( !m_xDatabaseDataProvider->getActiveConnection().is() )
283  throw uno::Exception("no active connection", nullptr);
284 
285  uno::Reference< reflection::XProxyFactory > xProxyFactory = reflection::ProxyFactory::create( m_xContext );
286  m_xProxy = xProxyFactory->createProxy(m_xDelegatee);
287  ::comphelper::query_aggregation(m_xProxy,m_xDelegatee);
288  m_xTypeProvider.set(m_xDelegatee,uno::UNO_QUERY);
289  m_xServiceInfo.set(m_xDelegatee,uno::UNO_QUERY);
290 
291  // set ourself as delegator
292  m_xProxy->setDelegator( *this );
293  const OUString sCommand = m_xDatabaseDataProvider->getCommand();
294  if ( !sCommand.isEmpty() )
295  m_aColumns = ::dbtools::getFieldNamesByCommandDescriptor(m_xDatabaseDataProvider->getActiveConnection()
296  ,m_xDatabaseDataProvider->getCommandType()
297  ,sCommand);
298 
299  uno::Reference< chart::XComplexDescriptionAccess > xDataProvider(m_xDatabaseDataProvider,uno::UNO_QUERY);
300  if ( !xDataProvider.is() )
301  return;
302 
303  m_aColumns.realloc(1);
304  const uno::Sequence< OUString > aColumnNames = xDataProvider->getColumnDescriptions();
305  for(const auto& rColumnName : aColumnNames)
306  {
307  if ( !rColumnName.isEmpty() )
308  {
309  sal_Int32 nCount = m_aColumns.getLength();
310  m_aColumns.realloc(nCount+1);
311  m_aColumns.getArray()[nCount] = rColumnName;
312  }
313  }
314 }
315 
316 uno::Any SAL_CALL ExportDocumentHandler::queryInterface( const uno::Type& _rType )
317 {
318  uno::Any aReturn = ExportDocumentHandler_BASE::queryInterface(_rType);
319  return aReturn.hasValue() ? aReturn : (m_xProxy.is() ? m_xProxy->queryAggregation(_rType) : aReturn);
320 }
321 
322 uno::Sequence< uno::Type > SAL_CALL ExportDocumentHandler::getTypes( )
323 {
324  if ( m_xTypeProvider.is() )
325  return ::comphelper::concatSequences(
326  ExportDocumentHandler_BASE::getTypes(),
327  m_xTypeProvider->getTypes()
328  );
329  return ExportDocumentHandler_BASE::getTypes();
330 }
331 
332 void ExportDocumentHandler::exportTableRows()
333 {
334  const OUString sRow( lcl_createAttribute(XML_NP_TABLE, XML_TABLE_ROW) );
335  m_xDelegatee->startElement(sRow,nullptr);
336 
337  const OUString sValueType( lcl_createAttribute(XML_NP_OFFICE, XML_VALUE_TYPE) );
338 
339  const OUString sCell( lcl_createAttribute(XML_NP_TABLE, XML_TABLE_CELL) );
340  const OUString sP( lcl_createAttribute(XML_NP_TEXT, XML_P) );
341  const OUString sFtext(lcl_createAttribute(XML_NP_RPT,XML_FORMATTED_TEXT) );
342  const OUString sRElement(lcl_createAttribute(XML_NP_RPT,XML_REPORT_ELEMENT) );
343  const OUString sRComponent( lcl_createAttribute(XML_NP_RPT,XML_REPORT_COMPONENT) ) ;
344  const OUString sFormulaAttrib( lcl_createAttribute(XML_NP_RPT,XML_FORMULA) );
345  static constexpr OUStringLiteral s_sFloat = u"float";
346 
348  pCellAtt->AddAttribute(sValueType, "string");
349 
350  bool bRemoveString = true;
351  const sal_Int32 nCount = m_aColumns.getLength();
352  if ( m_nColumnCount > nCount )
353  {
354  const sal_Int32 nEmptyCellCount = m_nColumnCount - nCount;
355  for(sal_Int32 i = 0; i < nEmptyCellCount ; ++i)
356  {
357  m_xDelegatee->startElement(sCell,pCellAtt);
358  if ( bRemoveString )
359  {
360  bRemoveString = false;
361  pCellAtt->RemoveAttribute(sValueType);
362  pCellAtt->AddAttribute(sValueType,s_sFloat);
363  }
364  m_xDelegatee->startElement(sP,nullptr);
365  m_xDelegatee->endElement(sP);
366  m_xDelegatee->endElement(sCell);
367  }
368  }
369  for(const auto& rColumn : std::as_const(m_aColumns))
370  {
371  OUString sFormula = "field:[" + rColumn + "]";
373  pList->AddAttribute(sFormulaAttrib,sFormula);
374 
375  m_xDelegatee->startElement(sCell,pCellAtt);
376  if ( bRemoveString )
377  {
378  bRemoveString = false;
379  pCellAtt->RemoveAttribute(sValueType);
380  pCellAtt->AddAttribute(sValueType,s_sFloat);
381  }
382  m_xDelegatee->startElement(sP,nullptr);
383  m_xDelegatee->startElement(sFtext,pList);
384  m_xDelegatee->startElement(sRElement,nullptr);
385  m_xDelegatee->startElement(sRComponent,nullptr);
386 
387  m_xDelegatee->endElement(sRComponent);
388  m_xDelegatee->endElement(sRElement);
389  m_xDelegatee->endElement(sFtext);
390  m_xDelegatee->endElement(sP);
391  m_xDelegatee->endElement(sCell);
392  }
393 
394  m_xDelegatee->endElement(sRow);
395 }
396 
397 } // namespace rptxml
398 
399 
400 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
402  css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
403 {
404  return cppu::acquire(new rptxml::ExportDocumentHandler(context));
405 }
406 
407 
408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * reportdesign_ExportDocumentHandler_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
XML_VALUES_CELL_RANGE_ADDRESS
Reference< frame::XModel > m_xModel
bool hasValue()
XML_REPORT_ELEMENT
XML_REPORT_COMPONENT
XML_COMMAND_TYPE
OString sFormula
virtual OUString SAL_CALL getValueByName(const OUString &aName) override
static void lcl_correctCellAddress(const OUString &_sName, const uno::Reference< xml::sax::XAttributeList > &xAttribs)
XML_VALUE_TYPE
XML_VALUE
XML_TABLE_CELL
XML_FORMATTED_TEXT
XML_FORMULA
XML_NP_TABLE
int nCount
XML_REPORT
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
XML_QUERY
std::mutex m_aMutex
XML_TOKEN_INVALID
XML_TABLE_ROW
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
void RemoveAttribute(const OUString &sName)
XML_P
int i
Sequence< OUString > getFieldNamesByCommandDescriptor(const Reference< XConnection > &_rxConnection, const sal_Int32 _nCommandType, const OUString &_rCommand, SQLExceptionInfo *_pErrorInfo)
XML_NP_TEXT
XML_CALCULATION_SETTINGS
XML_TABLE
XML_COMMAND
float u
unsigned char sal_Bool
XML_NP_CHART
XML_ESCAPE_PROCESSING
XML_NP_RPT
XML_DETAIL
XML_CELL_RANGE_ADDRESS
XML_FALSE
ExportDocumentHandler(css::uno::Reference< css::uno::XComponentContext > const &context)
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
static void lcl_exportPrettyPrinting(const uno::Reference< xml::sax::XDocumentHandler > &_xDelegatee)
static bool convertEnum(EnumT &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
XML_NULL_DATE
XML_DATE_VALUE
void AddAttribute(const OUString &sName, const OUString &sValue)
XML_FILTER
Reference< XComponentContext > m_xContext
constexpr OUStringLiteral MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
IMPLEMENT_GET_IMPLEMENTATION_ID(DrawController)
XML_NP_OFFICE
OUString lcl_createAttribute(const xmloff::token::XMLTokenEnum &_eNamespace, const xmloff::token::XMLTokenEnum &_eAttribute)
XML_MIMETYPE
sal_uInt16 nPos
bool m_bDetectedRangeSegmentation false