1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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  */
9 
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>
27 
28 #include <o3tl/safeint.hxx>
29 #include <svl/sharedstringpool.hxx>
30 #include <svl/languageoptions.hxx>
31 #include <unotools/configmgr.hxx>
32 #include <unordered_map>
33 
34 namespace {
35 
36 struct ColAttr
37 {
38     bool mbLatinNumFmtOnly;
39 
ColAttr__anon62e4202e0111::ColAttr40     ColAttr() : mbLatinNumFmtOnly(false) {}
41 };
42 
43 struct TabAttr
44 {
45     std::vector<ColAttr> maCols;
46 };
47 
48 }
49 
50 struct ScDocumentImportImpl
51 {
52     ScDocument& mrDoc;
53     sc::StartListeningContext maListenCxt;
54     std::vector<sc::TableColumnBlockPositionSet> maBlockPosSet;
55     SvtScriptType mnDefaultScriptNumeric;
56     std::vector<TabAttr> maTabAttrs;
57     std::unordered_map<sal_uInt32, bool> maIsLatinScriptMap;
58 
ScDocumentImportImplScDocumentImportImpl59     explicit ScDocumentImportImpl(ScDocument& rDoc) :
60         mrDoc(rDoc),
61         maListenCxt(rDoc),
62         mnDefaultScriptNumeric(SvtScriptType::UNKNOWN) {}
63 
isValidScDocumentImportImpl64     bool isValid( size_t nTab, size_t nCol )
65     {
66         return (nTab <= o3tl::make_unsigned(MAXTAB) && nCol <= o3tl::make_unsigned(mrDoc.MaxCol()));
67     }
68 
getColAttrScDocumentImportImpl69     ColAttr* getColAttr( size_t nTab, size_t nCol )
70     {
71         if (!isValid(nTab, nCol))
72             return nullptr;
73 
74         if (nTab >= maTabAttrs.size())
75             maTabAttrs.resize(nTab+1);
76 
77         TabAttr& rTab = maTabAttrs[nTab];
78         if (nCol >= rTab.maCols.size())
79             rTab.maCols.resize(nCol+1);
80 
81         return &rTab.maCols[nCol];
82     }
83 
getBlockPositionScDocumentImportImpl84     sc::ColumnBlockPosition* getBlockPosition( SCTAB nTab, SCCOL nCol )
85     {
86         if (!isValid(nTab, nCol))
87             return nullptr;
88 
89         if (o3tl::make_unsigned(nTab) >= maBlockPosSet.size())
90         {
91             for (SCTAB i = maBlockPosSet.size(); i <= nTab; ++i)
92                 maBlockPosSet.emplace_back(mrDoc, i);
93         }
94 
95         sc::TableColumnBlockPositionSet& rTab = maBlockPosSet[nTab];
96         return rTab.getBlockPosition(nCol);
97     }
98 
invalidateBlockPositionSetScDocumentImportImpl99     void invalidateBlockPositionSet(SCTAB nTab)
100     {
101         if (o3tl::make_unsigned(nTab) >= maBlockPosSet.size())
102             return;
103 
104         sc::TableColumnBlockPositionSet& rTab = maBlockPosSet[nTab];
105         rTab.invalidate();
106     }
107 
initForSheetsScDocumentImportImpl108     void initForSheets()
109     {
110         size_t n = mrDoc.GetTableCount();
111         for (size_t i = maBlockPosSet.size(); i < n; ++i)
112             maBlockPosSet.emplace_back(mrDoc, i);
113 
114         if (maTabAttrs.size() < n)
115             maTabAttrs.resize(n);
116     }
117 };
118 
Attrs()119 ScDocumentImport::Attrs::Attrs() : mbLatinNumFmtOnly(false) {}
120 
~Attrs()121 ScDocumentImport::Attrs::~Attrs() {}
122 
ScDocumentImport(ScDocument & rDoc)123 ScDocumentImport::ScDocumentImport(ScDocument& rDoc) : mpImpl(new ScDocumentImportImpl(rDoc)) {}
124 
~ScDocumentImport()125 ScDocumentImport::~ScDocumentImport()
126 {
127 }
128 
getDoc()129 ScDocument& ScDocumentImport::getDoc()
130 {
131     return mpImpl->mrDoc;
132 }
133 
getDoc() const134 const ScDocument& ScDocumentImport::getDoc() const
135 {
136     return mpImpl->mrDoc;
137 }
138 
initForSheets()139 void ScDocumentImport::initForSheets()
140 {
141     mpImpl->initForSheets();
142 }
143 
setDefaultNumericScript(SvtScriptType nScript)144 void ScDocumentImport::setDefaultNumericScript(SvtScriptType nScript)
145 {
146     mpImpl->mnDefaultScriptNumeric = nScript;
147 }
148 
setCellStyleToSheet(SCTAB nTab,const ScStyleSheet & rStyle)149 void ScDocumentImport::setCellStyleToSheet(SCTAB nTab, const ScStyleSheet& rStyle)
150 {
151     ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
152     if (!pTab)
153         return;
154 
155     pTab->ApplyStyleArea(0, 0, getDoc().MaxCol(), getDoc().MaxRow(), rStyle);
156 }
157 
getSheetIndex(const OUString & rName) const158 SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
159 {
160     SCTAB nTab = -1;
161     if (!mpImpl->mrDoc.GetTable(rName, nTab))
162         return -1;
163 
164     return nTab;
165 }
166 
getSheetCount() const167 SCTAB ScDocumentImport::getSheetCount() const
168 {
169     return mpImpl->mrDoc.maTabs.size();
170 }
171 
appendSheet(const OUString & rName)172 bool ScDocumentImport::appendSheet(const OUString& rName)
173 {
174     SCTAB nTabCount = mpImpl->mrDoc.maTabs.size();
175     if (!ValidTab(nTabCount))
176         return false;
177 
178     mpImpl->mrDoc.maTabs.emplace_back(new ScTable(mpImpl->mrDoc, nTabCount, rName));
179     return true;
180 }
181 
setSheetName(SCTAB nTab,const OUString & rName)182 void ScDocumentImport::setSheetName(SCTAB nTab, const OUString& rName)
183 {
184     mpImpl->mrDoc.SetTabNameOnLoad(nTab, rName);
185 }
186 
setOriginDate(sal_uInt16 nYear,sal_uInt16 nMonth,sal_uInt16 nDay)187 void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uInt16 nDay)
188 {
189     if (!mpImpl->mrDoc.pDocOptions)
190         mpImpl->mrDoc.pDocOptions.reset( new ScDocOptions );
191 
192     mpImpl->mrDoc.pDocOptions->SetDate(nDay, nMonth, nYear);
193 }
194 
invalidateBlockPositionSet(SCTAB nTab)195 void ScDocumentImport::invalidateBlockPositionSet(SCTAB nTab)
196 {
197     mpImpl->invalidateBlockPositionSet(nTab);
198 }
199 
setAutoInput(const ScAddress & rPos,const OUString & rStr,const ScSetStringParam * pStringParam)200 void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr, const ScSetStringParam* pStringParam)
201 {
202     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
203     if (!pTab)
204         return;
205 
206     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
207 
208     if (!pBlockPos)
209         return;
210 
211     // If ScSetStringParam was given, ScColumn::ParseString() shall take care
212     // of checking. Ensure caller said so.
213     assert(!pStringParam || pStringParam->mbCheckLinkFormula);
214 
215     ScCellValue aCell;
216     pTab->aCol[rPos.Col()].ParseString(
217         aCell, rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention(), pStringParam);
218 
219     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
220     switch (aCell.meType)
221     {
222         case CELLTYPE_STRING:
223             // string is copied.
224             pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.mpString);
225         break;
226         case CELLTYPE_EDIT:
227             // Cell takes the ownership of the text object.
228             pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpEditText);
229             aCell.mpEditText = nullptr;
230         break;
231         case CELLTYPE_VALUE:
232             pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mfValue);
233         break;
234         case CELLTYPE_FORMULA:
235             if (!pStringParam)
236                 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *aCell.mpFormula->GetCode());
237             // This formula cell instance is directly placed in the document without copying.
238             pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpFormula);
239             aCell.mpFormula = nullptr;
240         break;
241         default:
242             pBlockPos->miCellPos = rCells.set_empty(pBlockPos->miCellPos, rPos.Row(), rPos.Row());
243     }
244 }
245 
setNumericCell(const ScAddress & rPos,double fVal)246 void ScDocumentImport::setNumericCell(const ScAddress& rPos, double fVal)
247 {
248     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
249     if (!pTab)
250         return;
251 
252     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
253 
254     if (!pBlockPos)
255         return;
256 
257     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
258     pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), fVal);
259 }
260 
setStringCell(const ScAddress & rPos,const OUString & rStr)261 void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr)
262 {
263     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
264     if (!pTab)
265         return;
266 
267     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
268 
269     if (!pBlockPos)
270         return;
271 
272     svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr);
273     if (!aSS.getData())
274         return;
275 
276     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
277     pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aSS);
278 }
279 
setEditCell(const ScAddress & rPos,std::unique_ptr<EditTextObject> pEditText)280 void ScDocumentImport::setEditCell(const ScAddress& rPos, std::unique_ptr<EditTextObject> pEditText)
281 {
282     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
283     if (!pTab)
284         return;
285 
286     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
287 
288     if (!pBlockPos)
289         return;
290 
291     pEditText->NormalizeString(mpImpl->mrDoc.GetSharedStringPool());
292     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
293     pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), pEditText.release());
294 }
295 
setFormulaCell(const ScAddress & rPos,const OUString & rFormula,formula::FormulaGrammar::Grammar eGrammar,const double * pResult)296 void ScDocumentImport::setFormulaCell(
297     const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar,
298     const double* pResult )
299 {
300     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
301     if (!pTab)
302         return;
303 
304     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
305 
306     if (!pBlockPos)
307         return;
308 
309     std::unique_ptr<ScFormulaCell> pFC =
310         std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, rFormula, eGrammar);
311 
312     mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
313 
314     if (pResult)
315     {
316         // Set cached result to this formula cell.
317         pFC->SetResultDouble(*pResult);
318     }
319 
320     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
321     pBlockPos->miCellPos =
322         rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
323 }
324 
setFormulaCell(const ScAddress & rPos,const OUString & rFormula,formula::FormulaGrammar::Grammar eGrammar,const OUString & rResult)325 void ScDocumentImport::setFormulaCell(
326     const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar,
327     const OUString& rResult )
328 {
329     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
330     if (!pTab)
331         return;
332 
333     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
334 
335     if (!pBlockPos)
336         return;
337 
338     std::unique_ptr<ScFormulaCell> pFC =
339         std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, rFormula, eGrammar);
340 
341     mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
342 
343     // Set cached result to this formula cell.
344     pFC->SetHybridString(mpImpl->mrDoc.GetSharedStringPool().intern(rResult));
345 
346     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
347     pBlockPos->miCellPos =
348         rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
349 }
350 
setFormulaCell(const ScAddress & rPos,std::unique_ptr<ScTokenArray> pArray)351 void ScDocumentImport::setFormulaCell(const ScAddress& rPos, std::unique_ptr<ScTokenArray> pArray)
352 {
353     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
354     if (!pTab)
355         return;
356 
357     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
358 
359     if (!pBlockPos)
360         return;
361 
362     std::unique_ptr<ScFormulaCell> pFC =
363         std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, std::move(pArray));
364 
365     mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
366 
367     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
368     pBlockPos->miCellPos =
369         rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
370 }
371 
setFormulaCell(const ScAddress & rPos,ScFormulaCell * pCell)372 void ScDocumentImport::setFormulaCell(const ScAddress& rPos, ScFormulaCell* pCell)
373 {
374     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
375     if (!pTab)
376         return;
377 
378     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
379 
380     if (!pBlockPos)
381         return;
382 
383     if (pCell)
384         mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
385 
386     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
387     pBlockPos->miCellPos =
388         rCells.set(pBlockPos->miCellPos, rPos.Row(), pCell);
389 }
390 
setMatrixCells(const ScRange & rRange,const ScTokenArray & rArray,formula::FormulaGrammar::Grammar eGram)391 void ScDocumentImport::setMatrixCells(
392     const ScRange& rRange, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram)
393 {
394     const ScAddress& rBasePos = rRange.aStart;
395 
396     ScTable* pTab = mpImpl->mrDoc.FetchTable(rBasePos.Tab());
397     if (!pTab)
398         return;
399 
400     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rBasePos.Tab(), rBasePos.Col());
401 
402     if (!pBlockPos)
403         return;
404 
405     if (utl::ConfigManager::IsFuzzing()) //just too slow
406         return;
407 
408     sc::CellStoreType& rCells = pTab->aCol[rBasePos.Col()].maCells;
409 
410     // Set the master cell.
411     ScFormulaCell* pCell = new ScFormulaCell(mpImpl->mrDoc, rBasePos, rArray, eGram, ScMatrixMode::Formula);
412 
413     mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
414 
415     pBlockPos->miCellPos =
416         rCells.set(pBlockPos->miCellPos, rBasePos.Row(), pCell);
417 
418     // Matrix formulas currently need re-calculation on import.
419     pCell->SetMatColsRows(
420         rRange.aEnd.Col()-rRange.aStart.Col()+1, rRange.aEnd.Row()-rRange.aStart.Row()+1);
421 
422     // Set the reference cells.
423     ScSingleRefData aRefData;
424     aRefData.InitFlags();
425     aRefData.SetColRel(true);
426     aRefData.SetRowRel(true);
427     aRefData.SetTabRel(true);
428     aRefData.SetAddress(mpImpl->mrDoc.GetSheetLimits(), rBasePos, rBasePos);
429 
430     ScTokenArray aArr(mpImpl->mrDoc); // consists only of one single reference token.
431     formula::FormulaToken* t = aArr.AddMatrixSingleReference(aRefData);
432 
433     ScAddress aPos = rBasePos;
434     for (SCROW nRow = rRange.aStart.Row()+1; nRow <= rRange.aEnd.Row(); ++nRow)
435     {
436         // Token array must be cloned so that each formula cell receives its own copy.
437         aPos.SetRow(nRow);
438         // Reference in each cell must point to the origin cell relative to the current cell.
439         aRefData.SetAddress(mpImpl->mrDoc.GetSheetLimits(), rBasePos, aPos);
440         *t->GetSingleRef() = aRefData;
441         std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
442         pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
443         pBlockPos->miCellPos =
444             rCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
445     }
446 
447     for (SCCOL nCol = rRange.aStart.Col()+1; nCol <= rRange.aEnd.Col(); ++nCol)
448     {
449         pBlockPos = mpImpl->getBlockPosition(rBasePos.Tab(), nCol);
450         if (!pBlockPos)
451             return;
452 
453         sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
454 
455         aPos.SetCol(nCol);
456         for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
457         {
458             aPos.SetRow(nRow);
459             aRefData.SetAddress(mpImpl->mrDoc.GetSheetLimits(), rBasePos, aPos);
460             *t->GetSingleRef() = aRefData;
461             std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
462             pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
463             pBlockPos->miCellPos =
464                 rColCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
465         }
466     }
467 }
468 
setTableOpCells(const ScRange & rRange,const ScTabOpParam & rParam)469 void ScDocumentImport::setTableOpCells(const ScRange& rRange, const ScTabOpParam& rParam)
470 {
471     SCTAB nTab = rRange.aStart.Tab();
472     SCCOL nCol1 = rRange.aStart.Col();
473     SCROW nRow1 = rRange.aStart.Row();
474     SCCOL nCol2 = rRange.aEnd.Col();
475     SCROW nRow2 = rRange.aEnd.Row();
476 
477     ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
478     if (!pTab)
479         return;
480 
481     ScDocument& rDoc = mpImpl->mrDoc;
482     ScRefAddress aRef;
483     OUStringBuffer aFormulaBuf;
484     aFormulaBuf.append('=');
485     aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocTableOp));
486     aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocOpen));
487 
488     OUString aSep = ScCompiler::GetNativeSymbol(ocSep);
489     if (rParam.meMode == ScTabOpParam::Column) // column only
490     {
491         aRef.Set(rParam.aRefFormulaCell.GetAddress(), true, false, false);
492         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
493         aFormulaBuf.append(aSep);
494         aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
495         aFormulaBuf.append(aSep);
496         aRef.Set(nCol1, nRow1, nTab, false, true, true);
497         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
498         nCol1++;
499         nCol2 = std::min( nCol2, static_cast<SCCOL>(rParam.aRefFormulaEnd.Col() -
500                     rParam.aRefFormulaCell.Col() + nCol1 + 1));
501     }
502     else if (rParam.meMode == ScTabOpParam::Row) // row only
503     {
504         aRef.Set(rParam.aRefFormulaCell.GetAddress(), false, true, false);
505         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
506         aFormulaBuf.append(aSep);
507         aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
508         aFormulaBuf.append(aSep);
509         aRef.Set(nCol1, nRow1, nTab, true, false, true);
510         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
511         ++nRow1;
512         nRow2 = std::min(
513             nRow2, rParam.aRefFormulaEnd.Row() - rParam.aRefFormulaCell.Row() + nRow1 + 1);
514     }
515     else // both
516     {
517         aFormulaBuf.append(rParam.aRefFormulaCell.GetRefString(rDoc, nTab));
518         aFormulaBuf.append(aSep);
519         aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
520         aFormulaBuf.append(aSep);
521         aRef.Set(nCol1, nRow1 + 1, nTab, false, true, true);
522         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
523         aFormulaBuf.append(aSep);
524         aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
525         aFormulaBuf.append(aSep);
526         aRef.Set(nCol1 + 1, nRow1, nTab, true, false, true);
527         aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
528         ++nCol1;
529         ++nRow1;
530     }
531 
532     aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocClose));
533 
534     ScFormulaCell aRefCell(
535         rDoc, ScAddress(nCol1, nRow1, nTab), aFormulaBuf.makeStringAndClear(),
536         formula::FormulaGrammar::GRAM_NATIVE, ScMatrixMode::NONE);
537 
538     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
539     {
540         sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(nTab, nCol);
541 
542         if (!pBlockPos)
543             // Something went horribly wrong.
544             return;
545 
546         sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
547 
548         for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
549         {
550             ScAddress aPos(nCol, nRow, nTab);
551             ScFormulaCell* pCell = new ScFormulaCell(aRefCell, rDoc, aPos);
552             pBlockPos->miCellPos =
553                 rColCells.set(pBlockPos->miCellPos, nRow, pCell);
554         }
555     }
556 }
557 
fillDownCells(const ScAddress & rPos,SCROW nFillSize)558 void ScDocumentImport::fillDownCells(const ScAddress& rPos, SCROW nFillSize)
559 {
560     ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
561     if (!pTab)
562         return;
563 
564     sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
565 
566     if (!pBlockPos)
567         return;
568 
569     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
570     ScRefCellValue aRefCell = pTab->aCol[rPos.Col()].GetCellValue(*pBlockPos, rPos.Row());
571 
572     switch (aRefCell.meType)
573     {
574         case CELLTYPE_VALUE:
575         {
576             std::vector<double> aCopied(nFillSize, aRefCell.mfValue);
577             pBlockPos->miCellPos = rCells.set(
578                 pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
579             break;
580         }
581         case CELLTYPE_STRING:
582         {
583             std::vector<svl::SharedString> aCopied(nFillSize, *aRefCell.mpString);
584             pBlockPos->miCellPos = rCells.set(
585                 pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
586             break;
587         }
588         default:
589             break;
590     }
591 }
592 
setAttrEntries(SCTAB nTab,SCCOL nCol,Attrs && rAttrs)593 void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nCol, Attrs&& rAttrs )
594 {
595     ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
596     if (!pTab)
597         return;
598 
599     ScColumn* pCol = pTab->FetchColumn(nCol);
600     if (!pCol)
601         return;
602 
603     ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
604     if (pColAttr)
605         pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly;
606 
607     pCol->pAttrArray->SetAttrEntries(std::move(rAttrs.mvData));
608 }
609 
setRowsVisible(SCTAB nTab,SCROW nRowStart,SCROW nRowEnd,bool bVisible)610 void ScDocumentImport::setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible)
611 {
612     if (!bVisible)
613     {
614         getDoc().ShowRows(nRowStart, nRowEnd, nTab, false);
615         getDoc().SetDrawPageSize(nTab);
616         getDoc().UpdatePageBreaks( nTab );
617     }
618     else
619     {
620         assert(false);
621     }
622 }
623 
setMergedCells(SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)624 void ScDocumentImport::setMergedCells(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
625 {
626     ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
627     if (!pTab)
628         return;
629 
630     pTab->SetMergedCells(nCol1, nRow1, nCol2, nRow2);
631 }
632 
633 namespace {
634 
635 class CellStoreInitializer
636 {
637     // The pimpl pattern here is intentional.
638     //
639     // The problem with having the attributes in CellStoreInitializer
640     // directly is that, as a functor, it might be copied around. In
641     // that case miPos in _copied_ object points to maAttrs in the
642     // original object, not in the copy. So later, deep in mdds, we end
643     // up comparing iterators from different sequences.
644     //
645     // This could be solved by defining copy constructor and operator=,
646     // but given the limited usage of the class, I think it is simpler
647     // to let copies share the state.
648     struct Impl
649     {
650         sc::CellTextAttrStoreType maAttrs;
651         sc::CellTextAttrStoreType::iterator miPos;
652         SvtScriptType mnScriptNumeric;
653 
Impl__anon62e4202e0211::CellStoreInitializer::Impl654         explicit Impl(const ScSheetLimits& rSheetLimits, const SvtScriptType nScriptNumeric)
655             : maAttrs(rSheetLimits.GetMaxRowCount()), miPos(maAttrs.begin()), mnScriptNumeric(nScriptNumeric)
656         {}
657     };
658 
659     ScDocumentImportImpl& mrDocImpl;
660     SCTAB mnTab;
661     SCCOL mnCol;
662 
663 public:
CellStoreInitializer(ScDocumentImportImpl & rDocImpl,SCTAB nTab,SCCOL nCol)664     CellStoreInitializer( ScDocumentImportImpl& rDocImpl, SCTAB nTab, SCCOL nCol ) :
665         mrDocImpl(rDocImpl),
666         mnTab(nTab),
667         mnCol(nCol),
668         mpImpl(std::make_shared<Impl>(rDocImpl.mrDoc.GetSheetLimits(), mrDocImpl.mnDefaultScriptNumeric))
669     {}
670 
671     std::shared_ptr<Impl> mpImpl;
672 
operator ()(const sc::CellStoreType::value_type & node)673     void operator() (const sc::CellStoreType::value_type& node)
674     {
675         if (node.type == sc::element_type_empty)
676             return;
677 
678         // Fill with default values for non-empty cell segments.
679         sc::CellTextAttr aDefault;
680         switch (node.type)
681         {
682             case sc::element_type_numeric:
683             {
684                 aDefault.mnScriptType = mpImpl->mnScriptNumeric;
685                 const ColAttr* p = mrDocImpl.getColAttr(mnTab, mnCol);
686                 if (p && p->mbLatinNumFmtOnly)
687                     aDefault.mnScriptType = SvtScriptType::LATIN;
688             }
689             break;
690             case sc::element_type_formula:
691             {
692                 const ColAttr* p = mrDocImpl.getColAttr(mnTab, mnCol);
693                 if (p && p->mbLatinNumFmtOnly)
694                 {
695                     // We can assume latin script type if the block only
696                     // contains formula cells with numeric results.
697                     ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
698                     ScFormulaCell** ppEnd = pp + node.size;
699                     bool bNumResOnly = true;
700                     for (; pp != ppEnd; ++pp)
701                     {
702                         const ScFormulaCell& rCell = **pp;
703                         if (!rCell.IsValueNoError())
704                         {
705                             bNumResOnly = false;
706                             break;
707                         }
708                     }
709 
710                     if (bNumResOnly)
711                         aDefault.mnScriptType = SvtScriptType::LATIN;
712                 }
713             }
714             break;
715             default:
716                 ;
717         }
718 
719         std::vector<sc::CellTextAttr> aDefaults(node.size, aDefault);
720         mpImpl->miPos = mpImpl->maAttrs.set(mpImpl->miPos, node.position, aDefaults.begin(), aDefaults.end());
721 
722         if (node.type != sc::element_type_formula)
723             return;
724 
725         // Have all formula cells start listening to the document.
726         ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
727         ScFormulaCell** ppEnd = pp + node.size;
728         for (; pp != ppEnd; ++pp)
729         {
730             ScFormulaCell& rFC = **pp;
731             if (rFC.IsSharedTop())
732             {
733                 // Register formula cells as a group.
734                 sc::SharedFormulaUtil::startListeningAsGroup(mrDocImpl.maListenCxt, pp);
735                 pp += rFC.GetSharedLength() - 1; // Move to the last one in the group.
736             }
737             else
738                 rFC.StartListeningTo(mrDocImpl.maListenCxt);
739         }
740     }
741 
swap(sc::CellTextAttrStoreType & rAttrs)742     void swap(sc::CellTextAttrStoreType& rAttrs)
743     {
744         mpImpl->maAttrs.swap(rAttrs);
745     }
746 };
747 
748 }
749 
finalize()750 void ScDocumentImport::finalize()
751 {
752     // Populate the text width and script type arrays in all columns. Also
753     // activate all formula cells.
754     for (auto& rxTab : mpImpl->mrDoc.maTabs)
755     {
756         if (!rxTab)
757             continue;
758 
759         ScTable& rTab = *rxTab;
760         SCCOL nNumCols = rTab.aCol.size();
761         for (SCCOL nColIdx = 0; nColIdx < nNumCols; ++nColIdx)
762             initColumn(rTab.aCol[nColIdx]);
763     }
764 
765     mpImpl->mrDoc.finalizeOutlineImport();
766 }
767 
initColumn(ScColumn & rCol)768 void ScDocumentImport::initColumn(ScColumn& rCol)
769 {
770     rCol.RegroupFormulaCells();
771 
772     CellStoreInitializer aFunc(*mpImpl, rCol.nTab, rCol.nCol);
773     std::for_each(rCol.maCells.begin(), rCol.maCells.end(), aFunc);
774     aFunc.swap(rCol.maCellTextAttrs);
775 
776     rCol.CellStorageModified();
777 }
778 
779 namespace {
780 
781 class CellStoreAfterImportBroadcaster
782 {
783 public:
784 
CellStoreAfterImportBroadcaster()785     CellStoreAfterImportBroadcaster() {}
786 
operator ()(const sc::CellStoreType::value_type & node)787     void operator() (const sc::CellStoreType::value_type& node)
788     {
789         if (node.type == sc::element_type_formula)
790         {
791             // Broadcast all formula cells marked for recalc.
792             ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
793             ScFormulaCell** ppEnd = pp + node.size;
794             for (; pp != ppEnd; ++pp)
795             {
796                 if ((*pp)->GetCode()->IsRecalcModeMustAfterImport())
797                     (*pp)->SetDirty();
798             }
799         }
800     }
801 };
802 
803 }
804 
broadcastRecalcAfterImport()805 void ScDocumentImport::broadcastRecalcAfterImport()
806 {
807     sc::AutoCalcSwitch aACSwitch( mpImpl->mrDoc, false);
808     ScBulkBroadcast aBulkBroadcast( mpImpl->mrDoc.GetBASM(), SfxHintId::ScDataChanged);
809 
810     for (auto& rxTab : mpImpl->mrDoc.maTabs)
811     {
812         if (!rxTab)
813             continue;
814 
815         ScTable& rTab = *rxTab;
816         SCCOL nNumCols = rTab.aCol.size();
817         for (SCCOL nColIdx = 0; nColIdx < nNumCols; ++nColIdx)
818             broadcastRecalcAfterImportColumn(rTab.aCol[nColIdx]);
819     }
820 }
821 
broadcastRecalcAfterImportColumn(ScColumn & rCol)822 void ScDocumentImport::broadcastRecalcAfterImportColumn(ScColumn& rCol)
823 {
824     CellStoreAfterImportBroadcaster aFunc;
825     std::for_each(rCol.maCells.begin(), rCol.maCells.end(), aFunc);
826 }
827 
828 
isLatinScript(const ScPatternAttr & rPatAttr)829 bool ScDocumentImport::isLatinScript(const ScPatternAttr& rPatAttr)
830 {
831     SvNumberFormatter* pFormatter = mpImpl->mrDoc.GetFormatTable();
832     sal_uInt32 nKey = rPatAttr.GetNumberFormat(pFormatter);
833     return isLatinScript(nKey);
834 }
835 
isLatinScript(sal_uInt32 nFormat)836 bool ScDocumentImport::isLatinScript(sal_uInt32 nFormat)
837 {
838     auto it = mpImpl->maIsLatinScriptMap.find(nFormat);
839     if (it != mpImpl->maIsLatinScriptMap.end())
840         return it->second;
841     bool b = sc::NumFmtUtil::isLatinScript(nFormat, mpImpl->mrDoc);
842     mpImpl->maIsLatinScriptMap.emplace(nFormat, b);
843     return b;
844 }
845 
846 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
847