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