tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / data / documentimport.cxx
blobb2e823c4a511dfd211c434d7f32ce6f9ecf9fc99
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/.
8 */
10 #include <documentimport.hxx>
11 #include <document.hxx>
12 #include <table.hxx>
13 #include <column.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>
34 namespace {
36 struct ColAttr
38 bool mbLatinNumFmtOnly;
40 ColAttr() : mbLatinNumFmtOnly(false) {}
43 struct TabAttr
45 std::vector<ColAttr> maCols;
50 struct ScDocumentImportImpl
52 ScDocument& mrDoc;
53 sc::StartListeningContext maListenCxt;
54 std::vector<sc::TableColumnBlockPositionSet> maBlockPosSet;
55 SvtScriptType mnDefaultScriptNumeric;
56 bool mbFuzzing;
57 std::vector<TabAttr> maTabAttrs;
58 std::unordered_map<sal_uInt32, bool> maIsLatinScriptMap;
60 explicit ScDocumentImportImpl(ScDocument& rDoc) :
61 mrDoc(rDoc),
62 maListenCxt(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))
75 return nullptr;
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))
90 return nullptr;
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())
105 return;
107 sc::TableColumnBlockPositionSet& rTab = maBlockPosSet[nTab];
108 rTab.invalidate();
111 void initForSheets()
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);
155 if (!pTab)
156 return;
158 pTab->ApplyStyleArea(0, 0, getDoc().MaxCol(), getDoc().MaxRow(), rStyle);
161 SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
163 SCTAB nTab = -1;
164 if (!mpImpl->mrDoc.GetTable(rName, nTab))
165 return -1;
167 return 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))
179 return false;
181 mpImpl->mrDoc.maTabs.emplace_back(new ScTable(mpImpl->mrDoc, nTabCount, rName));
182 return true;
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());
206 if (!pTab)
207 return;
209 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
211 if (!pBlockPos)
212 return;
214 // If ScSetStringParam was given, ScColumn::ParseString() shall take care
215 // of checking. Ensure caller said so.
216 assert(!pStringParam || pStringParam->mbCheckLinkFormula);
218 ScCellValue aCell;
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:
226 // string is copied.
227 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.getSharedString());
228 break;
229 case CELLTYPE_EDIT:
230 // Cell takes the ownership of the text object.
231 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.releaseEditText());
232 break;
233 case CELLTYPE_VALUE:
234 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.getDouble());
235 break;
236 case CELLTYPE_FORMULA:
237 if (!pStringParam)
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());
241 break;
242 default:
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());
250 if (!pTab)
251 return;
253 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
255 if (!pBlockPos)
256 return;
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());
265 if (!pTab)
266 return;
268 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
270 if (!pBlockPos)
271 return;
273 svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr);
274 if (!aSS.getData())
275 return;
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());
284 if (!pTab)
285 return;
287 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
289 if (!pBlockPos)
290 return;
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());
302 if (!pTab)
303 return;
305 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
307 if (!pBlockPos)
308 return;
310 std::unique_ptr<ScFormulaCell> pFC =
311 std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, rFormula, eGrammar);
313 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
315 if (pResult)
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());
331 if (!pTab)
332 return;
334 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
336 if (!pBlockPos)
337 return;
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());
355 if (!pTab)
356 return;
358 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
360 if (!pBlockPos)
361 return;
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());
376 if (!pTab)
377 return;
379 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
381 if (!pBlockPos)
382 return;
384 if (pCell)
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());
406 if (!pTab)
407 return;
409 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rBasePos.Tab(), rBasePos.Col());
411 if (!pBlockPos)
412 return;
414 if (comphelper::IsFuzzing()) //just too slow
415 return;
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.
446 aPos.SetRow(nRow);
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);
459 if (!pBlockPos)
460 return;
462 sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
464 aPos.SetCol(nCol);
465 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
467 aPos.SetRow(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);
487 if (!pTab)
488 return;
490 ScDocument& rDoc = mpImpl->mrDoc;
491 ScRefAddress aRef;
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)
501 + aSep
502 + rParam.aRefColCell.GetRefString(rDoc, nTab)
503 + aSep);
504 aRef.Set(nCol1, nRow1, nTab, false, true, true);
505 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
506 nCol1++;
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)
514 + aSep
515 + rParam.aRefRowCell.GetRefString(rDoc, nTab)
516 + aSep);
517 aRef.Set(nCol1, nRow1, nTab, true, false, true);
518 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
519 ++nRow1;
520 nRow2 = std::min(
521 nRow2, rParam.aRefFormulaEnd.Row() - rParam.aRefFormulaCell.Row() + nRow1 + 1);
523 else // both
525 aFormulaBuf.append(rParam.aRefFormulaCell.GetRefString(rDoc, nTab)
526 + aSep
527 + rParam.aRefColCell.GetRefString(rDoc, nTab)
528 + aSep);
529 aRef.Set(nCol1, nRow1 + 1, nTab, false, true, true);
530 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab)
531 + aSep
532 + rParam.aRefRowCell.GetRefString(rDoc, nTab)
533 + aSep);
534 aRef.Set(nCol1 + 1, nRow1, nTab, true, false, true);
535 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
536 ++nCol1;
537 ++nRow1;
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);
550 if (!pBlockPos)
551 // Something went horribly wrong.
552 return;
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());
569 if (!pTab)
570 return;
572 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
574 if (!pBlockPos)
575 return;
577 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
578 ScRefCellValue aRefCell = pTab->aCol[rPos.Col()].GetCellValue(*pBlockPos, rPos.Row());
580 switch (aRefCell.getType())
582 case CELLTYPE_VALUE:
584 std::vector<double> aCopied(nFillSize, aRefCell.getDouble());
585 pBlockPos->miCellPos = rCells.set(
586 pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
587 break;
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());
594 break;
596 default:
597 break;
601 void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs&& rAttrs )
603 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
604 if (!pTab)
605 return;
607 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol )
609 ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
610 if (pColAttr)
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)
619 if (!bVisible)
621 getDoc().ShowRows(nRowStart, nRowEnd, nTab, false);
622 getDoc().SetDrawPageSize(nTab);
623 getDoc().UpdatePageBreaks( nTab );
625 else
627 assert(false);
631 void ScDocumentImport::setMergedCells(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
633 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
634 if (!pTab)
635 return;
637 pTab->SetMergedCells(nCol1, nRow1, nCol2, nRow2);
640 namespace {
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.
655 struct Impl
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;
667 SCTAB mnTab;
668 SCCOL mnCol;
670 public:
671 CellStoreInitializer( ScDocumentImportImpl& rDocImpl, SCTAB nTab, SCCOL nCol ) :
672 mrDocImpl(rDocImpl),
673 mnTab(nTab),
674 mnCol(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)
683 return;
685 // Fill with default values for non-empty cell segments.
686 sc::CellTextAttr aDefault;
687 switch (node.type)
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;
696 break;
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())
712 bNumResOnly = false;
713 break;
717 if (bNumResOnly)
718 aDefault.mnScriptType = SvtScriptType::LATIN;
721 break;
722 default:
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)
730 return;
732 if (mrDocImpl.mbFuzzing) // skip listening when fuzzing
733 return;
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.
747 else
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)
766 if (!rxTab)
767 continue;
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();
789 namespace {
791 class CellStoreAfterImportBroadcaster
793 public:
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())
807 (*pp)->SetDirty();
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)
822 if (!rxTab)
823 continue;
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())
850 return it->second;
851 bool b = sc::NumFmtUtil::isLatinScript(nFormat, mpImpl->mrDoc);
852 mpImpl->maIsLatinScriptMap.emplace(nFormat, b);
853 return b;
856 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */