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