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