Update git submodules
[LibreOffice.git] / sc / source / filter / oox / querytablebuffer.cxx
blobf027ab7a4d941fa3e27b294c62a00e10ce5c7c4c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <querytablebuffer.hxx>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XEnumerationAccess.hpp>
24 #include <com/sun/star/sheet/XAreaLink.hpp>
25 #include <com/sun/star/sheet/XAreaLinks.hpp>
26 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
27 #include <osl/diagnose.h>
28 #include <oox/core/filterbase.hxx>
29 #include <oox/helper/binaryinputstream.hxx>
30 #include <oox/helper/attributelist.hxx>
31 #include <oox/token/properties.hxx>
32 #include <oox/token/tokens.hxx>
33 #include <addressconverter.hxx>
34 #include <biffhelper.hxx>
35 #include <connectionsbuffer.hxx>
36 #include <defnamesbuffer.hxx>
37 #include <docuno.hxx>
39 namespace oox::xls {
41 using namespace ::com::sun::star::container;
42 using namespace ::com::sun::star::sheet;
43 using namespace ::com::sun::star::table;
44 using namespace ::com::sun::star::uno;
46 namespace {
48 const sal_uInt32 BIFF12_QUERYTABLE_HEADERS = 0x00000001;
49 const sal_uInt32 BIFF12_QUERYTABLE_ROWNUMBERS = 0x00000002;
50 const sal_uInt32 BIFF12_QUERYTABLE_DISABLEREFRESH = 0x00000004;
51 const sal_uInt32 BIFF12_QUERYTABLE_BACKGROUND = 0x00000008;
52 const sal_uInt32 BIFF12_QUERYTABLE_FIRSTBACKGROUND = 0x00000010;
53 const sal_uInt32 BIFF12_QUERYTABLE_REFRESHONLOAD = 0x00000020;
54 const sal_uInt32 BIFF12_QUERYTABLE_FILLFORMULAS = 0x00000100;
55 const sal_uInt32 BIFF12_QUERYTABLE_SAVEDATA = 0x00000200;
56 const sal_uInt32 BIFF12_QUERYTABLE_DISABLEEDIT = 0x00000400;
57 const sal_uInt32 BIFF12_QUERYTABLE_PRESERVEFORMAT = 0x00000800;
58 const sal_uInt32 BIFF12_QUERYTABLE_ADJUSTCOLWIDTH = 0x00001000;
59 const sal_uInt32 BIFF12_QUERYTABLE_INTERMEDIATE = 0x00002000;
60 const sal_uInt32 BIFF12_QUERYTABLE_APPLYNUMFMT = 0x00004000;
61 const sal_uInt32 BIFF12_QUERYTABLE_APPLYFONT = 0x00008000;
62 const sal_uInt32 BIFF12_QUERYTABLE_APPLYALIGNMENT = 0x00010000;
63 const sal_uInt32 BIFF12_QUERYTABLE_APPLYBORDER = 0x00020000;
64 const sal_uInt32 BIFF12_QUERYTABLE_APPLYFILL = 0x00040000;
65 const sal_uInt32 BIFF12_QUERYTABLE_APPLYPROTECTION = 0x00080000;
67 void lclAppendWebQueryTableName( OUStringBuffer& rTables, std::u16string_view rTableName )
69 if( !rTableName.empty() )
71 if( !rTables.isEmpty() )
72 rTables.append( ';' );
73 rTables.append( OUString::Concat("HTML__") + rTableName );
77 void lclAppendWebQueryTableIndex( OUStringBuffer& rTables, sal_Int32 nTableIndex )
79 if( nTableIndex > 0 )
81 if( !rTables.isEmpty() )
82 rTables.append( ';' );
83 rTables.append( "HTML_" + OUString::number( nTableIndex ) );
87 OUString lclBuildWebQueryTables( const WebPrModel::TablesVector& rTables )
89 if( rTables.empty() )
90 return u"HTML_tables"_ustr;
92 OUStringBuffer aTables;
93 for( const auto& rTable : rTables )
95 if( rTable.has< OUString >() )
96 lclAppendWebQueryTableName( aTables, rTable.get< OUString >() );
97 else if( rTable.has< sal_Int32 >() )
98 lclAppendWebQueryTableIndex( aTables, rTable.get< sal_Int32 >() );
100 return aTables.makeStringAndClear();
103 Reference< XAreaLink > lclFindAreaLink(
104 const Reference< XAreaLinks >& rxAreaLinks, const ScAddress& rDestPos,
105 std::u16string_view rFileUrl, std::u16string_view rTables, std::u16string_view rFilterName, std::u16string_view rFilterOptions )
109 Reference< XEnumerationAccess > xAreaLinksEA( rxAreaLinks, UNO_QUERY_THROW );
110 Reference< XEnumeration > xAreaLinksEnum( xAreaLinksEA->createEnumeration(), UNO_SET_THROW );
111 while( xAreaLinksEnum->hasMoreElements() )
113 Reference< XAreaLink > xAreaLink( xAreaLinksEnum->nextElement(), UNO_QUERY_THROW );
114 PropertySet aPropSet( xAreaLink );
115 CellRangeAddress aDestArea = xAreaLink->getDestArea();
116 OUString aString;
117 if( (rDestPos.Tab() == aDestArea.Sheet) && (rDestPos.Col() == aDestArea.StartColumn) && (rDestPos.Row() == aDestArea.StartRow) &&
118 (rTables == xAreaLink->getSourceArea()) &&
119 aPropSet.getProperty( aString, PROP_Url ) && (rFileUrl == aString) &&
120 aPropSet.getProperty( aString, PROP_Filter ) && (rFilterName == aString) &&
121 aPropSet.getProperty( aString, PROP_FilterOptions ) && (rFilterOptions == aString) )
122 return xAreaLink;
125 catch( Exception& )
128 return Reference< XAreaLink >();
131 } // namespace
133 QueryTableModel::QueryTableModel() :
134 mnConnId( -1 ),
135 mnGrowShrinkType( XML_insertDelete ),
136 mbHeaders( true ),
137 mbRowNumbers( false ),
138 mbDisableRefresh( false ),
139 mbBackground( true ),
140 mbFirstBackground( false ),
141 mbRefreshOnLoad( false ),
142 mbFillFormulas( false ),
143 mbRemoveDataOnSave( false ),
144 mbDisableEdit( false ),
145 mbPreserveFormat( true ),
146 mbAdjustColWidth( true ),
147 mbIntermediate( false )
151 QueryTable::QueryTable( const WorksheetHelper& rHelper ) :
152 WorksheetHelper( rHelper )
156 void QueryTable::importQueryTable( const AttributeList& rAttribs )
158 maModel.maDefName = rAttribs.getXString( XML_name, OUString() );
159 maModel.mnConnId = rAttribs.getInteger( XML_connectionId, -1 );
160 maModel.mnGrowShrinkType = rAttribs.getToken( XML_growShrinkType, XML_insertDelete );
161 maModel.mnAutoFormatId = rAttribs.getInteger( XML_autoFormatId, 0 );
162 maModel.mbHeaders = rAttribs.getBool( XML_headers, true );
163 maModel.mbRowNumbers = rAttribs.getBool( XML_rowNumbers, false );
164 maModel.mbDisableRefresh = rAttribs.getBool( XML_disableRefresh, false );
165 maModel.mbBackground = rAttribs.getBool( XML_backgroundRefresh, true );
166 maModel.mbFirstBackground = rAttribs.getBool( XML_firstBackgroundRefresh, false );
167 maModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
168 maModel.mbFillFormulas = rAttribs.getBool( XML_fillFormulas, false );
169 maModel.mbRemoveDataOnSave = rAttribs.getBool( XML_removeDataOnSave, false );
170 maModel.mbDisableEdit = rAttribs.getBool( XML_disableEdit, false );
171 maModel.mbPreserveFormat = rAttribs.getBool( XML_preserveFormatting, true );
172 maModel.mbAdjustColWidth = rAttribs.getBool( XML_adjustColumnWidth, true );
173 maModel.mbIntermediate = rAttribs.getBool( XML_intermediate, false );
174 maModel.mbApplyNumFmt = rAttribs.getBool( XML_applyNumberFormats, false );
175 maModel.mbApplyFont = rAttribs.getBool( XML_applyFontFormats, false );
176 maModel.mbApplyAlignment = rAttribs.getBool( XML_applyAlignmentFormats, false );
177 maModel.mbApplyBorder = rAttribs.getBool( XML_applyBorderFormats, false );
178 maModel.mbApplyFill = rAttribs.getBool( XML_applyPatternFormats, false );
179 // OOXML and BIFF12 documentation differ: OOXML mentions width/height, BIFF12 mentions protection
180 maModel.mbApplyProtection = rAttribs.getBool( XML_applyWidthHeightFormats, false );
183 void QueryTable::importQueryTable( SequenceInputStream& rStrm )
185 sal_uInt32 nFlags;
186 nFlags = rStrm.readuInt32();
187 maModel.mnAutoFormatId = rStrm.readuInt16();
188 maModel.mnConnId = rStrm.readInt32();
189 rStrm >> maModel.maDefName;
191 static const sal_Int32 spnGrowShrinkTypes[] = { XML_insertClear, XML_insertDelete, XML_overwriteClear };
192 maModel.mnGrowShrinkType = STATIC_ARRAY_SELECT( spnGrowShrinkTypes, extractValue< sal_uInt8 >( nFlags, 6, 2 ), XML_insertDelete );
194 maModel.mbHeaders = getFlag( nFlags, BIFF12_QUERYTABLE_HEADERS );
195 maModel.mbRowNumbers = getFlag( nFlags, BIFF12_QUERYTABLE_ROWNUMBERS );
196 maModel.mbDisableRefresh = getFlag( nFlags, BIFF12_QUERYTABLE_DISABLEREFRESH );
197 maModel.mbBackground = getFlag( nFlags, BIFF12_QUERYTABLE_BACKGROUND );
198 maModel.mbFirstBackground = getFlag( nFlags, BIFF12_QUERYTABLE_FIRSTBACKGROUND );
199 maModel.mbRefreshOnLoad = getFlag( nFlags, BIFF12_QUERYTABLE_REFRESHONLOAD );
200 maModel.mbFillFormulas = getFlag( nFlags, BIFF12_QUERYTABLE_FILLFORMULAS );
201 maModel.mbRemoveDataOnSave = !getFlag( nFlags, BIFF12_QUERYTABLE_SAVEDATA ); // flag negated in BIFF12
202 maModel.mbDisableEdit = getFlag( nFlags, BIFF12_QUERYTABLE_DISABLEEDIT );
203 maModel.mbPreserveFormat = getFlag( nFlags, BIFF12_QUERYTABLE_PRESERVEFORMAT );
204 maModel.mbAdjustColWidth = getFlag( nFlags, BIFF12_QUERYTABLE_ADJUSTCOLWIDTH );
205 maModel.mbIntermediate = getFlag( nFlags, BIFF12_QUERYTABLE_INTERMEDIATE );
206 maModel.mbApplyNumFmt = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYNUMFMT );
207 maModel.mbApplyFont = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYFONT );
208 maModel.mbApplyAlignment = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYALIGNMENT );
209 maModel.mbApplyBorder = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYBORDER );
210 maModel.mbApplyFill = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYFILL );
211 maModel.mbApplyProtection = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYPROTECTION );
214 void QueryTable::finalizeImport()
216 ConnectionRef xConnection = getConnections().getConnection( maModel.mnConnId );
217 OSL_ENSURE( xConnection, "QueryTable::finalizeImport - missing connection object" );
218 if( !(xConnection && (xConnection->getConnectionType() == BIFF12_CONNECTION_HTML)) )
219 return;
221 // check that valid web query properties exist
222 const WebPrModel* pWebPr = xConnection->getModel().mxWebPr.get();
223 if( !pWebPr || pWebPr->mbXml )
224 return;
226 OUString aFileUrl = getBaseFilter().getAbsoluteUrl( pWebPr->maUrl );
227 if( aFileUrl.isEmpty() )
228 return;
230 // resolve destination cell range (stored as defined name containing the range)
231 OUString aDefName = maModel.maDefName.replace( ' ', '_' ).replace( '-', '_' );
232 DefinedNameRef xDefName = getDefinedNames().getByModelName( aDefName, getSheetIndex() );
233 OSL_ENSURE( xDefName, "QueryTable::finalizeImport - missing defined name" );
234 if( !xDefName )
235 return;
237 ScRange aDestRange;
238 bool bIsRange = xDefName->getAbsoluteRange( aDestRange ) && (aDestRange.aStart.Tab() == getSheetIndex());
239 OSL_ENSURE( bIsRange, "QueryTable::finalizeImport - defined name does not contain valid cell range" );
240 if( !(bIsRange && getAddressConverter().checkCellRange( aDestRange, false, true )) )
241 return;
243 // find tables mode: entire document, all tables, or specific tables
244 OUString aTables = pWebPr->mbHtmlTables ? lclBuildWebQueryTables( pWebPr->maTables ) : u"HTML_all"_ustr;
245 if( aTables.isEmpty() )
246 return;
250 PropertySet aDocProps(( Reference< css::beans::XPropertySet >(getDocument()) ));
251 Reference< XAreaLinks > xAreaLinks( aDocProps.getAnyProperty( PROP_AreaLinks ), UNO_QUERY_THROW );
252 CellAddress aDestPos( aDestRange.aStart.Tab(), aDestRange.aStart.Col(), aDestRange.aStart.Row() );
253 static constexpr OUString aFilterName = u"calc_HTML_WebQuery"_ustr;
254 xAreaLinks->insertAtPosition( aDestPos, aFileUrl, aTables, aFilterName, /*aFilterOptions*/u""_ustr );
255 // set refresh interval (convert minutes to seconds)
256 sal_Int32 nRefreshPeriod = xConnection->getModel().mnInterval * 60;
257 if( nRefreshPeriod > 0 )
259 PropertySet aPropSet( lclFindAreaLink( xAreaLinks, aDestRange.aStart, aFileUrl, aTables, aFilterName, /*aFilterOptions*/u"" ) );
260 aPropSet.setProperty( PROP_RefreshPeriod, nRefreshPeriod );
263 catch( Exception& )
268 QueryTableBuffer::QueryTableBuffer( const WorksheetHelper& rHelper ) :
269 WorksheetHelper( rHelper )
273 QueryTable& QueryTableBuffer::createQueryTable()
275 QueryTableVector::value_type xQueryTable = std::make_shared<QueryTable>( *this );
276 maQueryTables.push_back( xQueryTable );
277 return *xQueryTable;
280 void QueryTableBuffer::finalizeImport()
282 maQueryTables.forEachMem( &QueryTable::finalizeImport );
285 } // namespace oox::xls
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */