Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / source / filter / xml / xmltabi.cxx
blob217e08bebcedbc8de566b882a44fb77a884734bc
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 "xmltabi.hxx"
21 #include "xmlimprt.hxx"
22 #include "xmlrowi.hxx"
23 #include "xmlcoli.hxx"
24 #include "xmlsceni.hxx"
25 #include "xmlexternaltabi.hxx"
26 #include "xmlnexpi.hxx"
27 #include <document.hxx>
28 #include <docuno.hxx>
29 #include <olinetab.hxx>
30 #include "XMLTableShapesContext.hxx"
31 #include "XMLTableSourceContext.hxx"
32 #include "XMLStylesImportHelper.hxx"
33 #include <rangeutl.hxx>
34 #include <externalrefmgr.hxx>
35 #include <sheetdata.hxx>
36 #include "xmlcondformat.hxx"
37 #include "SparklineGroupsImportContext.hxx"
39 #include <xmloff/xmltoken.hxx>
40 #include <xmloff/xmlnamespace.hxx>
41 #include <xmloff/XMLEventsImportContext.hxx>
43 #include <tools/urlobj.hxx>
44 #include <sax/fastattribs.hxx>
45 #include <com/sun/star/sheet/XSpreadsheet.hpp>
46 #include <comphelper/servicehelper.hxx>
48 using namespace com::sun::star;
49 using namespace xmloff::token;
50 using ::com::sun::star::uno::Reference;
51 using ::com::sun::star::uno::UNO_QUERY;
52 using ::com::sun::star::xml::sax::XAttributeList;
54 /**
55 * Determine whether this table is an external reference cache from its
56 * name. There is currently no way of determining whether a table is a
57 * regular table or an external reference cache other than examining the
58 * name itself. We should probably introduce a new boolean value for
59 * table:table element and use it instead of doing this, to make it more
60 * reliable and future-proof.
62 * @param rName
64 * @return
66 static bool lcl_isExternalRefCache(const OUString& rName, OUString& rUrl, OUString& rExtTabName)
68 // 'file:///path/to/file.ods'#MySheet
69 // 'file:///path/to/file.ods'#MySheet with space
70 // 'file:///path/to/file's.ods'#Sheet (Notice the quote in the file name.
71 // That's allowed.)
73 if ( rName.toChar() != '\'' ) // initial quote
74 return false;
76 // #i114504# Other schemes besides "file:" are also allowed.
77 // CompareProtocolScheme is quick, only looks at the start of the string.
78 INetProtocol eProt = INetURLObject::CompareProtocolScheme( rName.subView(1) );
79 if ( eProt == INetProtocol::NotValid )
80 return false;
82 OUString aPrefix = INetURLObject::GetScheme( eProt );
83 sal_Int32 nPrefLen = aPrefix.getLength();
85 OUStringBuffer aUrlBuf, aTabNameBuf;
86 aUrlBuf.append( aPrefix );
87 sal_Int32 n = rName.getLength();
88 const sal_Unicode* p = rName.getStr();
90 bool bInUrl = true;
91 sal_Unicode cPrev = 0;
92 for (sal_Int32 i = nPrefLen+1; i < n; ++i) // start the loop after quote and prefix
94 const sal_Unicode c = p[i];
95 if (bInUrl)
97 // parsing file URL
98 if (c == '#')
100 if (cPrev != '\'')
101 return false;
103 rUrl = aUrlBuf.makeStringAndClear();
104 rUrl = rUrl.copy(0, rUrl.getLength()-1); // remove the trailing single-quote.
105 bInUrl = false;
107 else
108 aUrlBuf.append(c);
110 else
111 // parsing sheet name.
112 aTabNameBuf.append(c);
114 cPrev = c;
117 if (bInUrl)
118 return false;
120 if (aTabNameBuf.isEmpty())
121 return false;
123 rExtTabName = aTabNameBuf.makeStringAndClear();
125 return true;
128 ScXMLExternalTabData::ScXMLExternalTabData() :
129 mnRow(0), mnCol(0), mnFileId(0)
133 ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
134 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
135 ScXMLImportContext( rImport ),
136 nStartOffset(-1),
137 bStartFormPage(false),
138 bPrintEntireSheet(true)
140 // get start offset in file (if available)
141 nStartOffset = GetScImport().GetByteOffset();
143 ScXMLTabProtectionData aProtectData;
144 OUString sName;
145 OUString sStyleName;
147 if ( rAttrList.is() )
149 for (auto &it : *rAttrList)
151 switch (it.getToken())
153 case XML_ELEMENT( TABLE, XML_NAME ):
154 sName = it.toString();
155 break;
156 case XML_ELEMENT( TABLE, XML_STYLE_NAME ):
157 sStyleName = it.toString();
158 break;
159 case XML_ELEMENT( TABLE, XML_PROTECTED ):
160 aProtectData.mbProtected = IsXMLToken( it, XML_TRUE );
161 break;
162 case XML_ELEMENT( TABLE, XML_PRINT_RANGES ):
163 sPrintRanges = it.toString();
164 break;
165 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY ):
166 aProtectData.maPassword = it.toString();
167 break;
168 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM ):
169 aProtectData.meHash1 = ScPassHashHelper::getHashTypeFromURI( it.toString() );
170 break;
171 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2 ):
172 case XML_ELEMENT( LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2 ):
173 aProtectData.meHash2 = ScPassHashHelper::getHashTypeFromURI( it.toString() );
174 break;
175 case XML_ELEMENT( TABLE, XML_PRINT ):
177 if ( IsXMLToken( it, XML_FALSE) )
178 bPrintEntireSheet = false;
180 break;
186 OUString aExtUrl, aExtTabName;
187 if (lcl_isExternalRefCache(sName, aExtUrl, aExtTabName))
189 // This is an external ref cache table.
190 pExternalRefInfo.reset(new ScXMLExternalTabData);
191 ScDocument* pDoc = GetScImport().GetDocument();
192 if (pDoc)
194 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
195 pExternalRefInfo->mnFileId = pRefMgr->getExternalFileId(aExtUrl);
196 pExternalRefInfo->mpCacheTable = pRefMgr->getCacheTable(pExternalRefInfo->mnFileId, aExtTabName, true,
197 nullptr, &aExtUrl);
198 pExternalRefInfo->mpCacheTable->setWholeTableCached();
201 else
203 // This is a regular table.
204 GetScImport().GetTables().NewSheet(sName, sStyleName, aProtectData);
208 ScXMLTableContext::~ScXMLTableContext()
212 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
213 ScXMLTableContext::createFastChildContext( sal_Int32 nElement,
214 const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
216 sax_fastparser::FastAttributeList *pAttribList =
217 &sax_fastparser::castToFastAttributeList( xAttrList );
219 if (pExternalRefInfo)
221 // We only care about the table-row and table-source elements for
222 // external cache data.
223 switch ( nElement )
225 case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
226 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
227 case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
228 // #i101319# don't discard rows in groups or header (repeat range)
229 return new ScXMLExternalRefRowsContext(
230 GetScImport(), *pExternalRefInfo);
231 case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
232 return new ScXMLExternalRefRowContext(
233 GetScImport(), pAttribList, *pExternalRefInfo);
234 case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
235 return new ScXMLExternalRefTabSourceContext(
236 GetScImport(), pAttribList, *pExternalRefInfo);
237 default:
240 return nullptr;
243 SvXMLImportContext *pContext(nullptr);
245 switch ( nElement )
247 case XML_ELEMENT( TABLE, XML_NAMED_EXPRESSIONS ):
249 SCTAB nTab = GetScImport().GetTables().GetCurrentSheet();
250 pContext = new ScXMLNamedExpressionsContext(
251 GetScImport(),
252 std::make_shared<ScXMLNamedExpressionsContext::SheetLocalInserter>(GetScImport(), nTab));
254 break;
255 case XML_ELEMENT( TABLE, XML_TABLE_COLUMN_GROUP ):
256 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
257 false, true );
258 break;
259 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_COLUMNS ):
260 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
261 true, false );
262 break;
263 case XML_ELEMENT( TABLE, XML_TABLE_COLUMNS ):
264 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
265 false, false );
266 break;
267 case XML_ELEMENT( TABLE, XML_TABLE_COLUMN ):
268 pContext = new ScXMLTableColContext( GetScImport(), pAttribList );
269 break;
270 case XML_ELEMENT( TABLE, XML_TABLE_PROTECTION ):
271 case XML_ELEMENT( LO_EXT, XML_TABLE_PROTECTION ):
272 case XML_ELEMENT( OFFICE_EXT, XML_TABLE_PROTECTION ):
273 pContext = new ScXMLTableProtectionContext( GetScImport(), pAttribList );
274 break;
275 case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
276 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
277 false, true );
278 break;
279 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
280 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
281 true, false );
282 break;
283 case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
284 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
285 false, false );
286 break;
287 case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
288 pContext = new ScXMLTableRowContext( GetScImport(), pAttribList );
289 break;
290 case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
291 pContext = new ScXMLTableSourceContext( GetScImport(), pAttribList);
292 break;
293 case XML_ELEMENT( TABLE, XML_SCENARIO ):
294 pContext = new ScXMLTableScenarioContext( GetScImport(), pAttribList);
295 break;
296 case XML_ELEMENT( TABLE, XML_SHAPES ):
297 pContext = new ScXMLTableShapesContext( GetScImport() );
298 break;
299 case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMATS ):
300 pContext = new ScXMLConditionalFormatsContext( GetScImport() );
301 break;
302 case XML_ELEMENT(CALC_EXT, XML_SPARKLINE_GROUPS):
303 pContext = new sc::SparklineGroupsImportContext(GetScImport());
304 break;
305 case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS):
306 case XML_ELEMENT(OFFICE_EXT, XML_EVENT_LISTENERS):
308 // use XEventsSupplier interface of the sheet
309 uno::Reference<document::XEventsSupplier> xSupplier( GetScImport().GetTables().GetCurrentXSheet(), uno::UNO_QUERY );
310 pContext = new XMLEventsImportContext( GetImport(), xSupplier );
312 break;
313 case XML_ELEMENT(OFFICE, XML_FORMS):
315 GetScImport().GetFormImport()->startPage(GetScImport().GetTables().GetCurrentXDrawPage());
316 bStartFormPage = true;
317 pContext = xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetScImport() );
319 break;
320 default:
321 XMLOFF_WARN_UNKNOWN_ELEMENT("sc", nElement);
322 break;
325 return pContext;
328 void SAL_CALL ScXMLTableContext::endFastElement(sal_Int32 /*nElement*/)
330 ScXMLImport::MutexGuard aMutexGuard(GetScImport());
331 ScXMLImport& rImport = GetScImport();
332 rImport.GetStylesImportHelper()->EndTable();
333 ScDocument* pDoc(rImport.GetDocument());
334 if (!pDoc)
335 return;
337 ScMyTables& rTables = rImport.GetTables();
338 SCTAB nCurTab = rTables.GetCurrentSheet();
339 // tdf#51022 process only print ranges of internal sheets
340 if (!pExternalRefInfo)
342 if (!sPrintRanges.isEmpty())
344 ScRangeList aRangeList;
345 ScRangeStringConverter::GetRangeListFromString(aRangeList, sPrintRanges, *pDoc, ::formula::FormulaGrammar::CONV_OOO);
346 size_t nCount = aRangeList.size();
347 for (size_t i = 0; i < nCount; i++)
349 pDoc->AddPrintRange(nCurTab, aRangeList[i]);
352 else if (!bPrintEntireSheet)
353 // Sheet has "print entire sheet" option by default. Remove it.
354 pDoc->ClearPrintRanges(nCurTab);
357 ScOutlineTable* pOutlineTable(pDoc->GetOutlineTable(nCurTab));
358 if (pOutlineTable)
360 ScOutlineArray& rColArray(pOutlineTable->GetColArray());
361 size_t nDepth = rColArray.GetDepth();
362 for (size_t i = 0; i < nDepth; ++i)
364 size_t nCount = rColArray.GetCount(i);
365 for (size_t j = 0; j < nCount; ++j)
367 const ScOutlineEntry* pEntry = rColArray.GetEntry(i, j);
368 if (pEntry->IsHidden())
369 rColArray.SetVisibleBelow(i, j, false);
372 ScOutlineArray& rRowArray(pOutlineTable->GetRowArray());
373 nDepth = rRowArray.GetDepth();
374 for (size_t i = 0; i < nDepth; ++i)
376 size_t nCount = rRowArray.GetCount(i);
377 for (size_t j = 0; j < nCount; ++j)
379 const ScOutlineEntry* pEntry = rRowArray.GetEntry(i, j);
380 if (pEntry->IsHidden())
381 rRowArray.SetVisibleBelow(i, j, false);
385 if (rTables.HasDrawPage())
387 if (rTables.HasXShapes())
389 rImport.GetShapeImport()->popGroupAndPostProcess();
390 uno::Reference < drawing::XShapes > xTempShapes(rTables.GetCurrentXShapes());
391 rImport.GetShapeImport()->endPage(xTempShapes);
393 if (bStartFormPage)
394 rImport.GetFormImport()->endPage();
397 rTables.DeleteTable();
398 rImport.ProgressBarIncrement();
400 // store stream positions
401 if (!pExternalRefInfo && nStartOffset >= 0 /* && nEndOffset >= 0 */)
403 ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(rImport.GetModel())->GetSheetSaveData();
404 SCTAB nTab = rTables.GetCurrentSheet();
405 // pSheetData->AddStreamPos( nTab, nStartOffset, nEndOffset );
406 pSheetData->StartStreamPos( nTab, nStartOffset );
410 ScXMLTableProtectionContext::ScXMLTableProtectionContext(
411 ScXMLImport& rImport,
412 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
413 ScXMLImportContext( rImport )
415 bool bSelectProtectedCells = false;
416 bool bSelectUnprotectedCells = false;
417 bool bInsertColumns = false;
418 bool bInsertRows = false;
419 bool bDeleteColumns = false;
420 bool bDeleteRows = false;
422 if ( rAttrList.is() )
424 for (auto &aIter : *rAttrList)
426 sal_Int32 nToken = aIter.getToken();
427 switch (nToken)
429 case XML_ELEMENT( TABLE, XML_SELECT_PROTECTED_CELLS ):
430 case XML_ELEMENT( OFFICE_EXT, XML_SELECT_PROTECTED_CELLS ):
431 case XML_ELEMENT( LO_EXT, XML_SELECT_PROTECTED_CELLS ):
432 bSelectProtectedCells = IsXMLToken(aIter, XML_TRUE);
433 break;
434 case XML_ELEMENT( TABLE, XML_SELECT_UNPROTECTED_CELLS ):
435 case XML_ELEMENT( OFFICE_EXT, XML_SELECT_UNPROTECTED_CELLS ):
436 case XML_ELEMENT( LO_EXT, XML_SELECT_UNPROTECTED_CELLS ):
437 bSelectUnprotectedCells = IsXMLToken(aIter, XML_TRUE);
438 break;
439 case XML_ELEMENT( LO_EXT, XML_INSERT_COLUMNS ):
440 bInsertColumns = IsXMLToken(aIter, XML_TRUE);
441 break;
442 case XML_ELEMENT( LO_EXT, XML_INSERT_ROWS ):
443 bInsertRows = IsXMLToken(aIter, XML_TRUE);
444 break;
445 case XML_ELEMENT( LO_EXT, XML_DELETE_COLUMNS ):
446 bDeleteColumns = IsXMLToken(aIter, XML_TRUE);
447 break;
448 case XML_ELEMENT( LO_EXT, XML_DELETE_ROWS ):
449 bDeleteRows = IsXMLToken(aIter, XML_TRUE);
450 break;
451 default:
452 XMLOFF_WARN_UNKNOWN("sc", aIter);
457 ScXMLTabProtectionData& rProtectData = GetScImport().GetTables().GetCurrentProtectionData();
458 rProtectData.mbSelectProtectedCells = bSelectProtectedCells;
459 rProtectData.mbSelectUnprotectedCells = bSelectUnprotectedCells;
460 rProtectData.mbInsertColumns = bInsertColumns;
461 rProtectData.mbInsertRows = bInsertRows;
462 rProtectData.mbDeleteColumns = bDeleteColumns;
463 rProtectData.mbDeleteRows = bDeleteRows;
466 ScXMLTableProtectionContext::~ScXMLTableProtectionContext()
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */