Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / xml / xmltabi.cxx
bloba8e5b99a275683c1862ea535f31a7a26d1d3c068
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"
38 #include <xmloff/xmltkmap.hxx>
39 #include <xmloff/xmltoken.hxx>
40 #include <xmloff/xmlnmspe.hxx>
41 #include <xmloff/XMLEventsImportContext.hxx>
42 #include <sal/log.hxx>
44 #include <tools/urlobj.hxx>
45 #include <sax/fastattribs.hxx>
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.copy(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 mpCacheTable(), 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 SvXMLImportContextRef ScXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
213 const OUString& rLName,
214 const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttrList*/ )
216 const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap());
217 sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLName);
218 if (pExternalRefInfo)
220 return new SvXMLImportContext(GetImport(), nPrefix, rLName);
223 SvXMLImportContext *pContext(nullptr);
225 switch (nToken)
227 case XML_TOK_TABLE_FORMS:
229 GetScImport().GetFormImport()->startPage(GetScImport().GetTables().GetCurrentXDrawPage());
230 bStartFormPage = true;
231 pContext = xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetScImport(), nPrefix, rLName );
233 break;
234 case XML_TOK_TABLE_EVENT_LISTENERS:
235 case XML_TOK_TABLE_EVENT_LISTENERS_EXT:
237 // use XEventsSupplier interface of the sheet
238 uno::Reference<document::XEventsSupplier> xSupplier( GetScImport().GetTables().GetCurrentXSheet(), uno::UNO_QUERY );
239 pContext = new XMLEventsImportContext( GetImport(), nPrefix, rLName, xSupplier );
241 break;
242 default:
246 if( !pContext )
247 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
249 return pContext;
252 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
253 ScXMLTableContext::createFastChildContext( sal_Int32 nElement,
254 const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
256 sax_fastparser::FastAttributeList *pAttribList =
257 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
259 if (pExternalRefInfo)
261 // We only care about the table-row and table-source elements for
262 // external cache data.
263 switch ( nElement )
265 case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
266 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
267 case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
268 // #i101319# don't discard rows in groups or header (repeat range)
269 return new ScXMLExternalRefRowsContext(
270 GetScImport(), *pExternalRefInfo);
271 case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
272 return new ScXMLExternalRefRowContext(
273 GetScImport(), pAttribList, *pExternalRefInfo);
274 case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
275 return new ScXMLExternalRefTabSourceContext(
276 GetScImport(), pAttribList, *pExternalRefInfo);
277 default:
280 return new SvXMLImportContext( GetImport() );
283 SvXMLImportContext *pContext(nullptr);
285 switch ( nElement )
287 case XML_ELEMENT( TABLE, XML_NAMED_EXPRESSIONS ):
289 SCTAB nTab = GetScImport().GetTables().GetCurrentSheet();
290 pContext = new ScXMLNamedExpressionsContext(
291 GetScImport(),
292 new ScXMLNamedExpressionsContext::SheetLocalInserter(GetScImport(), nTab));
294 break;
295 case XML_ELEMENT( TABLE, XML_TABLE_COLUMN_GROUP ):
296 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
297 false, true );
298 break;
299 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_COLUMNS ):
300 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
301 true, false );
302 break;
303 case XML_ELEMENT( TABLE, XML_TABLE_COLUMNS ):
304 pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
305 false, false );
306 break;
307 case XML_ELEMENT( TABLE, XML_TABLE_COLUMN ):
308 pContext = new ScXMLTableColContext( GetScImport(), pAttribList );
309 break;
310 case XML_ELEMENT( TABLE, XML_TABLE_PROTECTION ):
311 case XML_ELEMENT( LO_EXT, XML_TABLE_PROTECTION ):
312 case XML_ELEMENT( OFFICE_EXT, XML_TABLE_PROTECTION ):
313 pContext = new ScXMLTableProtectionContext( GetScImport(), pAttribList );
314 break;
315 case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
316 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
317 false, true );
318 break;
319 case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
320 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
321 true, false );
322 break;
323 case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
324 pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
325 false, false );
326 break;
327 case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
328 pContext = new ScXMLTableRowContext( GetScImport(), pAttribList );
329 break;
330 case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
331 pContext = new ScXMLTableSourceContext( GetScImport(), pAttribList);
332 break;
333 case XML_ELEMENT( TABLE, XML_SCENARIO ):
334 pContext = new ScXMLTableScenarioContext( GetScImport(), pAttribList);
335 break;
336 case XML_ELEMENT( TABLE, XML_SHAPES ):
337 pContext = new ScXMLTableShapesContext( GetScImport() );
338 break;
339 case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMATS ):
340 pContext = new ScXMLConditionalFormatsContext( GetScImport() );
341 break;
342 default:
343 pContext = new SvXMLImportContext( GetImport() );
346 assert(pContext);
348 return pContext;
351 void SAL_CALL ScXMLTableContext::endFastElement(sal_Int32 /*nElement*/)
353 ScXMLImport::MutexGuard aMutexGuard(GetScImport());
354 ScXMLImport& rImport = GetScImport();
355 rImport.GetStylesImportHelper()->EndTable();
356 ScDocument* pDoc(rImport.GetDocument());
357 if (!pDoc)
358 return;
360 ScMyTables& rTables = rImport.GetTables();
361 SCTAB nCurTab = rTables.GetCurrentSheet();
362 if (!sPrintRanges.isEmpty())
364 ScRangeList aRangeList;
365 ScRangeStringConverter::GetRangeListFromString( aRangeList, sPrintRanges, pDoc, ::formula::FormulaGrammar::CONV_OOO );
366 size_t nCount = aRangeList.size();
367 for (size_t i=0; i< nCount; i++ )
369 pDoc->AddPrintRange( nCurTab, aRangeList[i] );
372 else if (!bPrintEntireSheet)
373 // Sheet has "print entire sheet" option by default. Remove it.
374 pDoc->ClearPrintRanges(nCurTab);
376 ScOutlineTable* pOutlineTable(pDoc->GetOutlineTable(nCurTab));
377 if (pOutlineTable)
379 ScOutlineArray& rColArray(pOutlineTable->GetColArray());
380 size_t nDepth = rColArray.GetDepth();
381 for (size_t i = 0; i < nDepth; ++i)
383 size_t nCount = rColArray.GetCount(i);
384 for (size_t j = 0; j < nCount; ++j)
386 const ScOutlineEntry* pEntry = rColArray.GetEntry(i, j);
387 if (pEntry->IsHidden())
388 rColArray.SetVisibleBelow(i, j, false);
391 ScOutlineArray& rRowArray(pOutlineTable->GetRowArray());
392 nDepth = rRowArray.GetDepth();
393 for (size_t i = 0; i < nDepth; ++i)
395 size_t nCount = rRowArray.GetCount(i);
396 for (size_t j = 0; j < nCount; ++j)
398 const ScOutlineEntry* pEntry = rRowArray.GetEntry(i, j);
399 if (pEntry->IsHidden())
400 rRowArray.SetVisibleBelow(i, j, false);
404 if (rTables.HasDrawPage())
406 if (rTables.HasXShapes())
408 rImport.GetShapeImport()->popGroupAndPostProcess();
409 uno::Reference < drawing::XShapes > xTempShapes(rTables.GetCurrentXShapes());
410 rImport.GetShapeImport()->endPage(xTempShapes);
412 if (bStartFormPage)
413 rImport.GetFormImport()->endPage();
416 rTables.DeleteTable();
417 rImport.ProgressBarIncrement();
419 // store stream positions
420 if (!pExternalRefInfo && nStartOffset >= 0 /* && nEndOffset >= 0 */)
422 ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(rImport.GetModel())->GetSheetSaveData();
423 SCTAB nTab = rTables.GetCurrentSheet();
424 // pSheetData->AddStreamPos( nTab, nStartOffset, nEndOffset );
425 pSheetData->StartStreamPos( nTab, nStartOffset );
429 ScXMLTableProtectionContext::ScXMLTableProtectionContext(
430 ScXMLImport& rImport,
431 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
432 ScXMLImportContext( rImport )
434 bool bSelectProtectedCells = false;
435 bool bSelectUnprotectedCells = false;
436 bool bInsertColumns = false;
437 bool bInsertRows = false;
438 bool bDeleteColumns = false;
439 bool bDeleteRows = false;
441 if ( rAttrList.is() )
443 for (auto &aIter : *rAttrList)
445 sal_Int32 nToken = aIter.getToken();
446 switch (nToken)
448 case XML_ELEMENT( TABLE, XML_SELECT_PROTECTED_CELLS ):
449 case XML_ELEMENT( OFFICE_EXT, XML_SELECT_PROTECTED_CELLS ):
450 case XML_ELEMENT( LO_EXT, XML_SELECT_PROTECTED_CELLS ):
451 bSelectProtectedCells = IsXMLToken(aIter, XML_TRUE);
452 break;
453 case XML_ELEMENT( TABLE, XML_SELECT_UNPROTECTED_CELLS ):
454 case XML_ELEMENT( OFFICE_EXT, XML_SELECT_UNPROTECTED_CELLS ):
455 case XML_ELEMENT( LO_EXT, XML_SELECT_UNPROTECTED_CELLS ):
456 bSelectUnprotectedCells = IsXMLToken(aIter, XML_TRUE);
457 break;
458 case XML_ELEMENT( LO_EXT, XML_INSERT_COLUMNS ):
459 bInsertColumns = IsXMLToken(aIter, XML_TRUE);
460 break;
461 case XML_ELEMENT( LO_EXT, XML_INSERT_ROWS ):
462 bInsertRows = IsXMLToken(aIter, XML_TRUE);
463 break;
464 case XML_ELEMENT( LO_EXT, XML_DELETE_COLUMNS ):
465 bDeleteColumns = IsXMLToken(aIter, XML_TRUE);
466 break;
467 case XML_ELEMENT( LO_EXT, XML_DELETE_ROWS ):
468 bDeleteRows = IsXMLToken(aIter, XML_TRUE);
469 break;
470 default:
471 SAL_WARN("sc", "unknown attribute: " << nToken);
476 ScXMLTabProtectionData& rProtectData = GetScImport().GetTables().GetCurrentProtectionData();
477 rProtectData.mbSelectProtectedCells = bSelectProtectedCells;
478 rProtectData.mbSelectUnprotectedCells = bSelectUnprotectedCells;
479 rProtectData.mbInsertColumns = bInsertColumns;
480 rProtectData.mbInsertRows = bInsertRows;
481 rProtectData.mbDeleteColumns = bDeleteColumns;
482 rProtectData.mbDeleteRows = bDeleteRows;
485 ScXMLTableProtectionContext::~ScXMLTableProtectionContext()
489 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLTableProtectionContext::createFastChildContext(
490 sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
492 return nullptr;
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */