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/.
10 #include <documentimport.hxx>
11 #include <document.hxx>
14 #include <formulacell.hxx>
15 #include <docoptio.hxx>
16 #include <mtvelements.hxx>
17 #include <tokenarray.hxx>
18 #include <stringutil.hxx>
19 #include <compiler.hxx>
20 #include <paramisc.hxx>
21 #include <listenercontext.hxx>
22 #include <attarray.hxx>
23 #include <sharedformula.hxx>
24 #include <bcaslot.hxx>
25 #include <scopetools.hxx>
26 #include <numformat.hxx>
28 #include <o3tl/safeint.hxx>
29 #include <svl/sharedstringpool.hxx>
30 #include <svl/languageoptions.hxx>
31 #include <comphelper/configuration.hxx>
32 #include <unordered_map>
38 bool mbLatinNumFmtOnly
;
40 ColAttr() : mbLatinNumFmtOnly(false) {}
45 std::vector
<ColAttr
> maCols
;
50 struct ScDocumentImportImpl
53 sc::StartListeningContext maListenCxt
;
54 std::vector
<sc::TableColumnBlockPositionSet
> maBlockPosSet
;
55 SvtScriptType mnDefaultScriptNumeric
;
57 std::vector
<TabAttr
> maTabAttrs
;
58 std::unordered_map
<sal_uInt32
, bool> maIsLatinScriptMap
;
60 explicit ScDocumentImportImpl(ScDocument
& rDoc
) :
63 mnDefaultScriptNumeric(SvtScriptType::UNKNOWN
),
64 mbFuzzing(comphelper::IsFuzzing())
67 bool isValid( size_t nTab
, size_t nCol
)
69 return (nTab
<= o3tl::make_unsigned(MAXTAB
) && nCol
<= o3tl::make_unsigned(mrDoc
.MaxCol()));
72 ColAttr
* getColAttr( size_t nTab
, size_t nCol
)
74 if (!isValid(nTab
, nCol
))
77 if (nTab
>= maTabAttrs
.size())
78 maTabAttrs
.resize(nTab
+1);
80 TabAttr
& rTab
= maTabAttrs
[nTab
];
81 if (nCol
>= rTab
.maCols
.size())
82 rTab
.maCols
.resize(nCol
+1);
84 return &rTab
.maCols
[nCol
];
87 sc::ColumnBlockPosition
* getBlockPosition( SCTAB nTab
, SCCOL nCol
)
89 if (!isValid(nTab
, nCol
))
92 if (o3tl::make_unsigned(nTab
) >= maBlockPosSet
.size())
94 for (SCTAB i
= maBlockPosSet
.size(); i
<= nTab
; ++i
)
95 maBlockPosSet
.emplace_back(mrDoc
, i
);
98 sc::TableColumnBlockPositionSet
& rTab
= maBlockPosSet
[nTab
];
99 return rTab
.getBlockPosition(nCol
);
102 void invalidateBlockPositionSet(SCTAB nTab
)
104 if (o3tl::make_unsigned(nTab
) >= maBlockPosSet
.size())
107 sc::TableColumnBlockPositionSet
& rTab
= maBlockPosSet
[nTab
];
113 size_t n
= mrDoc
.GetTableCount();
114 for (size_t i
= maBlockPosSet
.size(); i
< n
; ++i
)
115 maBlockPosSet
.emplace_back(mrDoc
, i
);
117 if (maTabAttrs
.size() < n
)
118 maTabAttrs
.resize(n
);
122 ScDocumentImport::Attrs::Attrs() : mbLatinNumFmtOnly(false) {}
124 ScDocumentImport::Attrs::~Attrs() {}
126 ScDocumentImport::ScDocumentImport(ScDocument
& rDoc
) : mpImpl(new ScDocumentImportImpl(rDoc
)) {}
128 ScDocumentImport::~ScDocumentImport()
132 ScDocument
& ScDocumentImport::getDoc()
134 return mpImpl
->mrDoc
;
137 const ScDocument
& ScDocumentImport::getDoc() const
139 return mpImpl
->mrDoc
;
142 void ScDocumentImport::initForSheets()
144 mpImpl
->initForSheets();
147 void ScDocumentImport::setDefaultNumericScript(SvtScriptType nScript
)
149 mpImpl
->mnDefaultScriptNumeric
= nScript
;
152 void ScDocumentImport::setCellStyleToSheet(SCTAB nTab
, const ScStyleSheet
& rStyle
)
154 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
158 pTab
->ApplyStyleArea(0, 0, getDoc().MaxCol(), getDoc().MaxRow(), rStyle
);
161 SCTAB
ScDocumentImport::getSheetIndex(const OUString
& rName
) const
164 if (!mpImpl
->mrDoc
.GetTable(rName
, nTab
))
170 SCTAB
ScDocumentImport::getSheetCount() const
172 return mpImpl
->mrDoc
.maTabs
.size();
175 bool ScDocumentImport::appendSheet(const OUString
& rName
)
177 SCTAB nTabCount
= mpImpl
->mrDoc
.maTabs
.size();
178 if (!ValidTab(nTabCount
))
181 mpImpl
->mrDoc
.maTabs
.emplace_back(new ScTable(mpImpl
->mrDoc
, nTabCount
, rName
));
185 void ScDocumentImport::setSheetName(SCTAB nTab
, const OUString
& rName
)
187 mpImpl
->mrDoc
.SetTabNameOnLoad(nTab
, rName
);
190 void ScDocumentImport::setOriginDate(sal_uInt16 nYear
, sal_uInt16 nMonth
, sal_uInt16 nDay
)
192 if (!mpImpl
->mrDoc
.pDocOptions
)
193 mpImpl
->mrDoc
.pDocOptions
.reset( new ScDocOptions
);
195 mpImpl
->mrDoc
.pDocOptions
->SetDate(nDay
, nMonth
, nYear
);
198 void ScDocumentImport::invalidateBlockPositionSet(SCTAB nTab
)
200 mpImpl
->invalidateBlockPositionSet(nTab
);
203 void ScDocumentImport::setAutoInput(const ScAddress
& rPos
, const OUString
& rStr
, const ScSetStringParam
* pStringParam
)
205 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
209 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
214 // If ScSetStringParam was given, ScColumn::ParseString() shall take care
215 // of checking. Ensure caller said so.
216 assert(!pStringParam
|| pStringParam
->mbCheckLinkFormula
);
219 pTab
->aCol
[rPos
.Col()].ParseString(
220 aCell
, rPos
.Row(), rPos
.Tab(), rStr
, mpImpl
->mrDoc
.GetAddressConvention(), pStringParam
);
222 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
223 switch (aCell
.getType())
225 case CELLTYPE_STRING
:
227 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), *aCell
.getSharedString());
230 // Cell takes the ownership of the text object.
231 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.releaseEditText());
234 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.getDouble());
236 case CELLTYPE_FORMULA
:
238 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *aCell
.getFormula()->GetCode());
239 // This formula cell instance is directly placed in the document without copying.
240 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.releaseFormula());
243 pBlockPos
->miCellPos
= rCells
.set_empty(pBlockPos
->miCellPos
, rPos
.Row(), rPos
.Row());
247 void ScDocumentImport::setNumericCell(const ScAddress
& rPos
, double fVal
)
249 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
253 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
258 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
259 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), fVal
);
262 void ScDocumentImport::setStringCell(const ScAddress
& rPos
, const OUString
& rStr
)
264 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
268 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
273 svl::SharedString aSS
= mpImpl
->mrDoc
.GetSharedStringPool().intern(rStr
);
277 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
278 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aSS
);
281 void ScDocumentImport::setEditCell(const ScAddress
& rPos
, std::unique_ptr
<EditTextObject
> pEditText
)
283 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
287 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
292 pEditText
->NormalizeString(mpImpl
->mrDoc
.GetSharedStringPool());
293 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
294 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pEditText
.release());
297 void ScDocumentImport::setFormulaCell(
298 const ScAddress
& rPos
, const OUString
& rFormula
, formula::FormulaGrammar::Grammar eGrammar
,
299 const double* pResult
)
301 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
305 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
310 std::unique_ptr
<ScFormulaCell
> pFC
=
311 std::make_unique
<ScFormulaCell
>(mpImpl
->mrDoc
, rPos
, rFormula
, eGrammar
);
313 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *pFC
->GetCode());
317 // Set cached result to this formula cell.
318 pFC
->SetResultDouble(*pResult
);
321 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
322 pBlockPos
->miCellPos
=
323 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pFC
.release());
326 void ScDocumentImport::setFormulaCell(
327 const ScAddress
& rPos
, const OUString
& rFormula
, formula::FormulaGrammar::Grammar eGrammar
,
328 const OUString
& rResult
)
330 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
334 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
339 std::unique_ptr
<ScFormulaCell
> pFC
=
340 std::make_unique
<ScFormulaCell
>(mpImpl
->mrDoc
, rPos
, rFormula
, eGrammar
);
342 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *pFC
->GetCode());
344 // Set cached result to this formula cell.
345 pFC
->SetHybridString(mpImpl
->mrDoc
.GetSharedStringPool().intern(rResult
));
347 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
348 pBlockPos
->miCellPos
=
349 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pFC
.release());
352 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, std::unique_ptr
<ScTokenArray
> pArray
)
354 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
358 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
363 std::unique_ptr
<ScFormulaCell
> pFC
=
364 std::make_unique
<ScFormulaCell
>(mpImpl
->mrDoc
, rPos
, std::move(pArray
));
366 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *pFC
->GetCode());
368 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
369 pBlockPos
->miCellPos
=
370 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pFC
.release());
373 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, ScFormulaCell
* pCell
)
375 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
379 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
385 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *pCell
->GetCode());
387 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
389 sc::CellStoreType::position_type aPos
= rCells
.position(rPos
.Row());
390 if (aPos
.first
!= rCells
.end() && aPos
.first
->type
== sc::element_type_formula
)
392 ScFormulaCell
* p
= sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
393 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *p
);
396 pBlockPos
->miCellPos
=
397 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pCell
);
400 void ScDocumentImport::setMatrixCells(
401 const ScRange
& rRange
, const ScTokenArray
& rArray
, formula::FormulaGrammar::Grammar eGram
)
403 const ScAddress
& rBasePos
= rRange
.aStart
;
405 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rBasePos
.Tab());
409 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rBasePos
.Tab(), rBasePos
.Col());
414 if (comphelper::IsFuzzing()) //just too slow
417 sc::CellStoreType
& rCells
= pTab
->aCol
[rBasePos
.Col()].maCells
;
419 // Set the master cell.
420 ScFormulaCell
* pCell
= new ScFormulaCell(mpImpl
->mrDoc
, rBasePos
, rArray
, eGram
, ScMatrixMode::Formula
);
422 mpImpl
->mrDoc
.CheckLinkFormulaNeedingCheck( *pCell
->GetCode());
424 pBlockPos
->miCellPos
=
425 rCells
.set(pBlockPos
->miCellPos
, rBasePos
.Row(), pCell
);
427 // Matrix formulas currently need re-calculation on import.
428 pCell
->SetMatColsRows(
429 rRange
.aEnd
.Col()-rRange
.aStart
.Col()+1, rRange
.aEnd
.Row()-rRange
.aStart
.Row()+1);
431 // Set the reference cells.
432 ScSingleRefData aRefData
;
433 aRefData
.InitFlags();
434 aRefData
.SetColRel(true);
435 aRefData
.SetRowRel(true);
436 aRefData
.SetTabRel(true);
437 aRefData
.SetAddress(mpImpl
->mrDoc
.GetSheetLimits(), rBasePos
, rBasePos
);
439 ScTokenArray
aArr(mpImpl
->mrDoc
); // consists only of one single reference token.
440 formula::FormulaToken
* t
= aArr
.AddMatrixSingleReference(aRefData
);
442 ScAddress aPos
= rBasePos
;
443 for (SCROW nRow
= rRange
.aStart
.Row()+1; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
445 // Token array must be cloned so that each formula cell receives its own copy.
447 // Reference in each cell must point to the origin cell relative to the current cell.
448 aRefData
.SetAddress(mpImpl
->mrDoc
.GetSheetLimits(), rBasePos
, aPos
);
449 *t
->GetSingleRef() = aRefData
;
450 ScTokenArray
aTokArr(aArr
.CloneValue());
451 pCell
= new ScFormulaCell(mpImpl
->mrDoc
, aPos
, aTokArr
, eGram
, ScMatrixMode::Reference
);
452 pBlockPos
->miCellPos
=
453 rCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
456 for (SCCOL nCol
= rRange
.aStart
.Col()+1; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
458 pBlockPos
= mpImpl
->getBlockPosition(rBasePos
.Tab(), nCol
);
462 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
465 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
468 aRefData
.SetAddress(mpImpl
->mrDoc
.GetSheetLimits(), rBasePos
, aPos
);
469 *t
->GetSingleRef() = aRefData
;
470 ScTokenArray
aTokArr(aArr
.CloneValue());
471 pCell
= new ScFormulaCell(mpImpl
->mrDoc
, aPos
, aTokArr
, eGram
, ScMatrixMode::Reference
);
472 pBlockPos
->miCellPos
=
473 rColCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
478 void ScDocumentImport::setTableOpCells(const ScRange
& rRange
, const ScTabOpParam
& rParam
)
480 SCTAB nTab
= rRange
.aStart
.Tab();
481 SCCOL nCol1
= rRange
.aStart
.Col();
482 SCROW nRow1
= rRange
.aStart
.Row();
483 SCCOL nCol2
= rRange
.aEnd
.Col();
484 SCROW nRow2
= rRange
.aEnd
.Row();
486 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
490 ScDocument
& rDoc
= mpImpl
->mrDoc
;
492 OUStringBuffer
aFormulaBuf("="
493 + ScCompiler::GetNativeSymbol(ocTableOp
)
494 + ScCompiler::GetNativeSymbol(ocOpen
));
496 OUString aSep
= ScCompiler::GetNativeSymbol(ocSep
);
497 if (rParam
.meMode
== ScTabOpParam::Column
) // column only
499 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), true, false, false);
500 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
)
502 + rParam
.aRefColCell
.GetRefString(rDoc
, nTab
)
504 aRef
.Set(nCol1
, nRow1
, nTab
, false, true, true);
505 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
));
507 nCol2
= std::min( nCol2
, static_cast<SCCOL
>(rParam
.aRefFormulaEnd
.Col() -
508 rParam
.aRefFormulaCell
.Col() + nCol1
+ 1));
510 else if (rParam
.meMode
== ScTabOpParam::Row
) // row only
512 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), false, true, false);
513 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
)
515 + rParam
.aRefRowCell
.GetRefString(rDoc
, nTab
)
517 aRef
.Set(nCol1
, nRow1
, nTab
, true, false, true);
518 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
));
521 nRow2
, rParam
.aRefFormulaEnd
.Row() - rParam
.aRefFormulaCell
.Row() + nRow1
+ 1);
525 aFormulaBuf
.append(rParam
.aRefFormulaCell
.GetRefString(rDoc
, nTab
)
527 + rParam
.aRefColCell
.GetRefString(rDoc
, nTab
)
529 aRef
.Set(nCol1
, nRow1
+ 1, nTab
, false, true, true);
530 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
)
532 + rParam
.aRefRowCell
.GetRefString(rDoc
, nTab
)
534 aRef
.Set(nCol1
+ 1, nRow1
, nTab
, true, false, true);
535 aFormulaBuf
.append(aRef
.GetRefString(rDoc
, nTab
));
540 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocClose
));
542 ScFormulaCell
aRefCell(
543 rDoc
, ScAddress(nCol1
, nRow1
, nTab
), aFormulaBuf
.makeStringAndClear(),
544 formula::FormulaGrammar::GRAM_NATIVE
, ScMatrixMode::NONE
);
546 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
548 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(nTab
, nCol
);
551 // Something went horribly wrong.
554 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
556 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
558 ScAddress
aPos(nCol
, nRow
, nTab
);
559 ScFormulaCell
* pCell
= new ScFormulaCell(aRefCell
, rDoc
, aPos
);
560 pBlockPos
->miCellPos
=
561 rColCells
.set(pBlockPos
->miCellPos
, nRow
, pCell
);
566 void ScDocumentImport::fillDownCells(const ScAddress
& rPos
, SCROW nFillSize
)
568 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
572 sc::ColumnBlockPosition
* pBlockPos
= mpImpl
->getBlockPosition(rPos
.Tab(), rPos
.Col());
577 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
578 ScRefCellValue aRefCell
= pTab
->aCol
[rPos
.Col()].GetCellValue(*pBlockPos
, rPos
.Row());
580 switch (aRefCell
.getType())
584 std::vector
<double> aCopied(nFillSize
, aRefCell
.getDouble());
585 pBlockPos
->miCellPos
= rCells
.set(
586 pBlockPos
->miCellPos
, rPos
.Row()+1, aCopied
.begin(), aCopied
.end());
589 case CELLTYPE_STRING
:
591 std::vector
<svl::SharedString
> aCopied(nFillSize
, *aRefCell
.getSharedString());
592 pBlockPos
->miCellPos
= rCells
.set(
593 pBlockPos
->miCellPos
, rPos
.Row()+1, aCopied
.begin(), aCopied
.end());
601 void ScDocumentImport::setAttrEntries( SCTAB nTab
, SCCOL nColStart
, SCCOL nColEnd
, Attrs
&& rAttrs
)
603 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
607 for(SCCOL nCol
= nColStart
; nCol
<= nColEnd
; ++nCol
)
609 ColAttr
* pColAttr
= mpImpl
->getColAttr(nTab
, nCol
);
611 pColAttr
->mbLatinNumFmtOnly
= rAttrs
.mbLatinNumFmtOnly
;
614 pTab
->SetAttrEntries( nColStart
, nColEnd
, std::move( rAttrs
.mvData
));
617 void ScDocumentImport::setRowsVisible(SCTAB nTab
, SCROW nRowStart
, SCROW nRowEnd
, bool bVisible
)
621 getDoc().ShowRows(nRowStart
, nRowEnd
, nTab
, false);
622 getDoc().SetDrawPageSize(nTab
);
623 getDoc().UpdatePageBreaks( nTab
);
631 void ScDocumentImport::setMergedCells(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
633 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
637 pTab
->SetMergedCells(nCol1
, nRow1
, nCol2
, nRow2
);
642 class CellStoreInitializer
644 // The pimpl pattern here is intentional.
646 // The problem with having the attributes in CellStoreInitializer
647 // directly is that, as a functor, it might be copied around. In
648 // that case miPos in _copied_ object points to maAttrs in the
649 // original object, not in the copy. So later, deep in mdds, we end
650 // up comparing iterators from different sequences.
652 // This could be solved by defining copy constructor and operator=,
653 // but given the limited usage of the class, I think it is simpler
654 // to let copies share the state.
657 sc::CellTextAttrStoreType maAttrs
;
658 sc::CellTextAttrStoreType::iterator miPos
;
659 SvtScriptType mnScriptNumeric
;
661 explicit Impl(const ScSheetLimits
& rSheetLimits
, const SvtScriptType nScriptNumeric
)
662 : maAttrs(rSheetLimits
.GetMaxRowCount()), miPos(maAttrs
.begin()), mnScriptNumeric(nScriptNumeric
)
666 ScDocumentImportImpl
& mrDocImpl
;
671 CellStoreInitializer( ScDocumentImportImpl
& rDocImpl
, SCTAB nTab
, SCCOL nCol
) :
675 mpImpl(std::make_shared
<Impl
>(rDocImpl
.mrDoc
.GetSheetLimits(), mrDocImpl
.mnDefaultScriptNumeric
))
678 std::shared_ptr
<Impl
> mpImpl
;
680 void operator() (const sc::CellStoreType::value_type
& node
)
682 if (node
.type
== sc::element_type_empty
)
685 // Fill with default values for non-empty cell segments.
686 sc::CellTextAttr aDefault
;
689 case sc::element_type_numeric
:
691 aDefault
.mnScriptType
= mpImpl
->mnScriptNumeric
;
692 const ColAttr
* p
= mrDocImpl
.getColAttr(mnTab
, mnCol
);
693 if (p
&& p
->mbLatinNumFmtOnly
)
694 aDefault
.mnScriptType
= SvtScriptType::LATIN
;
697 case sc::element_type_formula
:
699 const ColAttr
* p
= mrDocImpl
.getColAttr(mnTab
, mnCol
);
700 if (p
&& p
->mbLatinNumFmtOnly
)
702 // We can assume latin script type if the block only
703 // contains formula cells with numeric results.
704 ScFormulaCell
** pp
= &sc::formula_block::at(*node
.data
, 0);
705 ScFormulaCell
** ppEnd
= pp
+ node
.size
;
706 bool bNumResOnly
= true;
707 for (; pp
!= ppEnd
; ++pp
)
709 const ScFormulaCell
& rCell
= **pp
;
710 if (!rCell
.IsValueNoError())
718 aDefault
.mnScriptType
= SvtScriptType::LATIN
;
726 std::vector
<sc::CellTextAttr
> aDefaults(node
.size
, aDefault
);
727 mpImpl
->miPos
= mpImpl
->maAttrs
.set(mpImpl
->miPos
, node
.position
, aDefaults
.begin(), aDefaults
.end());
729 if (node
.type
!= sc::element_type_formula
)
732 if (mrDocImpl
.mbFuzzing
) // skip listening when fuzzing
735 // Have all formula cells start listening to the document.
736 ScFormulaCell
** pp
= &sc::formula_block::at(*node
.data
, 0);
737 ScFormulaCell
** ppEnd
= pp
+ node
.size
;
738 for (; pp
!= ppEnd
; ++pp
)
740 ScFormulaCell
& rFC
= **pp
;
741 if (rFC
.IsSharedTop())
743 // Register formula cells as a group.
744 sc::SharedFormulaUtil::startListeningAsGroup(mrDocImpl
.maListenCxt
, pp
);
745 pp
+= rFC
.GetSharedLength() - 1; // Move to the last one in the group.
748 rFC
.StartListeningTo(mrDocImpl
.maListenCxt
);
752 void swap(sc::CellTextAttrStoreType
& rAttrs
)
754 mpImpl
->maAttrs
.swap(rAttrs
);
760 void ScDocumentImport::finalize()
762 // Populate the text width and script type arrays in all columns. Also
763 // activate all formula cells.
764 for (auto& rxTab
: mpImpl
->mrDoc
.maTabs
)
769 ScTable
& rTab
= *rxTab
;
770 SCCOL nNumCols
= rTab
.aCol
.size();
771 for (SCCOL nColIdx
= 0; nColIdx
< nNumCols
; ++nColIdx
)
772 initColumn(rTab
.aCol
[nColIdx
]);
775 mpImpl
->mrDoc
.finalizeOutlineImport();
778 void ScDocumentImport::initColumn(ScColumn
& rCol
)
780 rCol
.RegroupFormulaCells();
782 CellStoreInitializer
aFunc(*mpImpl
, rCol
.nTab
, rCol
.nCol
);
783 std::for_each(rCol
.maCells
.begin(), rCol
.maCells
.end(), aFunc
);
784 aFunc
.swap(rCol
.maCellTextAttrs
);
786 rCol
.CellStorageModified();
791 class CellStoreAfterImportBroadcaster
795 CellStoreAfterImportBroadcaster() {}
797 void operator() (const sc::CellStoreType::value_type
& node
)
799 if (node
.type
== sc::element_type_formula
)
801 // Broadcast all formula cells marked for recalc.
802 ScFormulaCell
** pp
= &sc::formula_block::at(*node
.data
, 0);
803 ScFormulaCell
** ppEnd
= pp
+ node
.size
;
804 for (; pp
!= ppEnd
; ++pp
)
806 if ((*pp
)->GetCode()->IsRecalcModeMustAfterImport())
815 void ScDocumentImport::broadcastRecalcAfterImport()
817 sc::AutoCalcSwitch
aACSwitch( mpImpl
->mrDoc
, false);
818 ScBulkBroadcast
aBulkBroadcast( mpImpl
->mrDoc
.GetBASM(), SfxHintId::ScDataChanged
);
820 for (auto& rxTab
: mpImpl
->mrDoc
.maTabs
)
825 ScTable
& rTab
= *rxTab
;
826 SCCOL nNumCols
= rTab
.aCol
.size();
827 for (SCCOL nColIdx
= 0; nColIdx
< nNumCols
; ++nColIdx
)
828 broadcastRecalcAfterImportColumn(rTab
.aCol
[nColIdx
]);
832 void ScDocumentImport::broadcastRecalcAfterImportColumn(ScColumn
& rCol
)
834 CellStoreAfterImportBroadcaster aFunc
;
835 std::for_each(rCol
.maCells
.begin(), rCol
.maCells
.end(), aFunc
);
839 bool ScDocumentImport::isLatinScript(const ScPatternAttr
& rPatAttr
)
841 SvNumberFormatter
* pFormatter
= mpImpl
->mrDoc
.GetFormatTable();
842 sal_uInt32 nKey
= rPatAttr
.GetNumberFormat(pFormatter
);
843 return isLatinScript(nKey
);
846 bool ScDocumentImport::isLatinScript(sal_uInt32 nFormat
)
848 auto it
= mpImpl
->maIsLatinScriptMap
.find(nFormat
);
849 if (it
!= mpImpl
->maIsLatinScriptMap
.end())
851 bool b
= sc::NumFmtUtil::isLatinScript(nFormat
, mpImpl
->mrDoc
);
852 mpImpl
->maIsLatinScriptMap
.emplace(nFormat
, b
);
856 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */