1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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.
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.
73 if ( rName
.toChar() != '\'' ) // initial quote
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
)
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();
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
];
103 rUrl
= aUrlBuf
.makeStringAndClear();
104 rUrl
= rUrl
.copy(0, rUrl
.getLength()-1); // remove the trailing single-quote.
111 // parsing sheet name.
112 aTabNameBuf
.append(c
);
120 if (aTabNameBuf
.isEmpty())
123 rExtTabName
= aTabNameBuf
.makeStringAndClear();
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
),
137 bStartFormPage(false),
138 bPrintEntireSheet(true)
140 // get start offset in file (if available)
141 nStartOffset
= GetScImport().GetByteOffset();
143 ScXMLTabProtectionData aProtectData
;
147 if ( rAttrList
.is() )
149 for (auto &it
: *rAttrList
)
151 switch (it
.getToken())
153 case XML_ELEMENT( TABLE
, XML_NAME
):
154 sName
= it
.toString();
156 case XML_ELEMENT( TABLE
, XML_STYLE_NAME
):
157 sStyleName
= it
.toString();
159 case XML_ELEMENT( TABLE
, XML_PROTECTED
):
160 aProtectData
.mbProtected
= IsXMLToken( it
, XML_TRUE
);
162 case XML_ELEMENT( TABLE
, XML_PRINT_RANGES
):
163 sPrintRanges
= it
.toString();
165 case XML_ELEMENT( TABLE
, XML_PROTECTION_KEY
):
166 aProtectData
.maPassword
= it
.toString();
168 case XML_ELEMENT( TABLE
, XML_PROTECTION_KEY_DIGEST_ALGORITHM
):
169 aProtectData
.meHash1
= ScPassHashHelper::getHashTypeFromURI( it
.toString() );
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() );
175 case XML_ELEMENT( TABLE
, XML_PRINT
):
177 if ( IsXMLToken( it
, XML_FALSE
) )
178 bPrintEntireSheet
= false;
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();
194 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
195 pExternalRefInfo
->mnFileId
= pRefMgr
->getExternalFileId(aExtUrl
);
196 pExternalRefInfo
->mpCacheTable
= pRefMgr
->getCacheTable(pExternalRefInfo
->mnFileId
, aExtTabName
, true,
198 pExternalRefInfo
->mpCacheTable
->setWholeTableCached();
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.
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
);
243 SvXMLImportContext
*pContext(nullptr);
247 case XML_ELEMENT( TABLE
, XML_NAMED_EXPRESSIONS
):
249 SCTAB nTab
= GetScImport().GetTables().GetCurrentSheet();
250 pContext
= new ScXMLNamedExpressionsContext(
252 std::make_shared
<ScXMLNamedExpressionsContext::SheetLocalInserter
>(GetScImport(), nTab
));
255 case XML_ELEMENT( TABLE
, XML_TABLE_COLUMN_GROUP
):
256 pContext
= new ScXMLTableColsContext( GetScImport(), pAttribList
,
259 case XML_ELEMENT( TABLE
, XML_TABLE_HEADER_COLUMNS
):
260 pContext
= new ScXMLTableColsContext( GetScImport(), pAttribList
,
263 case XML_ELEMENT( TABLE
, XML_TABLE_COLUMNS
):
264 pContext
= new ScXMLTableColsContext( GetScImport(), pAttribList
,
267 case XML_ELEMENT( TABLE
, XML_TABLE_COLUMN
):
268 pContext
= new ScXMLTableColContext( GetScImport(), pAttribList
);
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
);
275 case XML_ELEMENT( TABLE
, XML_TABLE_ROW_GROUP
):
276 pContext
= new ScXMLTableRowsContext( GetScImport(), pAttribList
,
279 case XML_ELEMENT( TABLE
, XML_TABLE_HEADER_ROWS
):
280 pContext
= new ScXMLTableRowsContext( GetScImport(), pAttribList
,
283 case XML_ELEMENT( TABLE
, XML_TABLE_ROWS
):
284 pContext
= new ScXMLTableRowsContext( GetScImport(), pAttribList
,
287 case XML_ELEMENT( TABLE
, XML_TABLE_ROW
):
288 pContext
= new ScXMLTableRowContext( GetScImport(), pAttribList
);
290 case XML_ELEMENT( TABLE
, XML_TABLE_SOURCE
):
291 pContext
= new ScXMLTableSourceContext( GetScImport(), pAttribList
);
293 case XML_ELEMENT( TABLE
, XML_SCENARIO
):
294 pContext
= new ScXMLTableScenarioContext( GetScImport(), pAttribList
);
296 case XML_ELEMENT( TABLE
, XML_SHAPES
):
297 pContext
= new ScXMLTableShapesContext( GetScImport() );
299 case XML_ELEMENT( CALC_EXT
, XML_CONDITIONAL_FORMATS
):
300 pContext
= new ScXMLConditionalFormatsContext( GetScImport() );
302 case XML_ELEMENT(CALC_EXT
, XML_SPARKLINE_GROUPS
):
303 pContext
= new sc::SparklineGroupsImportContext(GetScImport());
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
);
313 case XML_ELEMENT(OFFICE
, XML_FORMS
):
315 GetScImport().GetFormImport()->startPage(GetScImport().GetTables().GetCurrentXDrawPage());
316 bStartFormPage
= true;
317 pContext
= xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetScImport() );
321 XMLOFF_WARN_UNKNOWN_ELEMENT("sc", nElement
);
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());
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
));
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
);
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();
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
);
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
);
439 case XML_ELEMENT( LO_EXT
, XML_INSERT_COLUMNS
):
440 bInsertColumns
= IsXMLToken(aIter
, XML_TRUE
);
442 case XML_ELEMENT( LO_EXT
, XML_INSERT_ROWS
):
443 bInsertRows
= IsXMLToken(aIter
, XML_TRUE
);
445 case XML_ELEMENT( LO_EXT
, XML_DELETE_COLUMNS
):
446 bDeleteColumns
= IsXMLToken(aIter
, XML_TRUE
);
448 case XML_ELEMENT( LO_EXT
, XML_DELETE_ROWS
):
449 bDeleteRows
= IsXMLToken(aIter
, XML_TRUE
);
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: */