LibreOffice Module sc (master) 1
documentimport.cxx
Go to the documentation of this file.
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>
32#include <unordered_map>
33
34namespace {
35
36struct ColAttr
37{
38 bool mbLatinNumFmtOnly;
39
40 ColAttr() : mbLatinNumFmtOnly(false) {}
41};
42
43struct TabAttr
44{
45 std::vector<ColAttr> maCols;
46};
47
48}
49
51{
54 std::vector<sc::TableColumnBlockPositionSet> maBlockPosSet;
57 std::vector<TabAttr> maTabAttrs;
58 std::unordered_map<sal_uInt32, bool> maIsLatinScriptMap;
59
61 mrDoc(rDoc),
62 maListenCxt(rDoc),
64 mbFuzzing(utl::ConfigManager::IsFuzzing())
65 {}
66
67 bool isValid( size_t nTab, size_t nCol )
68 {
69 return (nTab <= o3tl::make_unsigned(MAXTAB) && nCol <= o3tl::make_unsigned(mrDoc.MaxCol()));
70 }
71
72 ColAttr* getColAttr( size_t nTab, size_t nCol )
73 {
74 if (!isValid(nTab, nCol))
75 return nullptr;
76
77 if (nTab >= maTabAttrs.size())
78 maTabAttrs.resize(nTab+1);
79
80 TabAttr& rTab = maTabAttrs[nTab];
81 if (nCol >= rTab.maCols.size())
82 rTab.maCols.resize(nCol+1);
83
84 return &rTab.maCols[nCol];
85 }
86
88 {
89 if (!isValid(nTab, nCol))
90 return nullptr;
91
92 if (o3tl::make_unsigned(nTab) >= maBlockPosSet.size())
93 {
94 for (SCTAB i = maBlockPosSet.size(); i <= nTab; ++i)
95 maBlockPosSet.emplace_back(mrDoc, i);
96 }
97
99 return rTab.getBlockPosition(nCol);
100 }
101
103 {
104 if (o3tl::make_unsigned(nTab) >= maBlockPosSet.size())
105 return;
106
108 rTab.invalidate();
109 }
110
112 {
113 size_t n = mrDoc.GetTableCount();
114 for (size_t i = maBlockPosSet.size(); i < n; ++i)
115 maBlockPosSet.emplace_back(mrDoc, i);
116
117 if (maTabAttrs.size() < n)
118 maTabAttrs.resize(n);
119 }
120};
121
122ScDocumentImport::Attrs::Attrs() : mbLatinNumFmtOnly(false) {}
123
125
127
129{
130}
131
133{
134 return mpImpl->mrDoc;
135}
136
138{
139 return mpImpl->mrDoc;
140}
141
143{
144 mpImpl->initForSheets();
145}
146
148{
149 mpImpl->mnDefaultScriptNumeric = nScript;
150}
151
153{
154 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
155 if (!pTab)
156 return;
157
158 pTab->ApplyStyleArea(0, 0, getDoc().MaxCol(), getDoc().MaxRow(), rStyle);
159}
160
161SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
162{
163 SCTAB nTab = -1;
164 if (!mpImpl->mrDoc.GetTable(rName, nTab))
165 return -1;
166
167 return nTab;
168}
169
171{
172 return mpImpl->mrDoc.maTabs.size();
173}
174
175bool ScDocumentImport::appendSheet(const OUString& rName)
176{
177 SCTAB nTabCount = mpImpl->mrDoc.maTabs.size();
178 if (!ValidTab(nTabCount))
179 return false;
180
181 mpImpl->mrDoc.maTabs.emplace_back(new ScTable(mpImpl->mrDoc, nTabCount, rName));
182 return true;
183}
184
185void ScDocumentImport::setSheetName(SCTAB nTab, const OUString& rName)
186{
187 mpImpl->mrDoc.SetTabNameOnLoad(nTab, rName);
188}
189
190void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uInt16 nDay)
191{
192 if (!mpImpl->mrDoc.pDocOptions)
193 mpImpl->mrDoc.pDocOptions.reset( new ScDocOptions );
194
195 mpImpl->mrDoc.pDocOptions->SetDate(nDay, nMonth, nYear);
196}
197
199{
200 mpImpl->invalidateBlockPositionSet(nTab);
201}
202
203void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr, const ScSetStringParam* pStringParam)
204{
205 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
206 if (!pTab)
207 return;
208
209 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
210
211 if (!pBlockPos)
212 return;
213
214 // If ScSetStringParam was given, ScColumn::ParseString() shall take care
215 // of checking. Ensure caller said so.
216 assert(!pStringParam || pStringParam->mbCheckLinkFormula);
217
218 ScCellValue aCell;
219 pTab->aCol[rPos.Col()].ParseString(
220 aCell, rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention(), pStringParam);
221
222 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
223 switch (aCell.getType())
224 {
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());
244 }
245}
246
247void ScDocumentImport::setNumericCell(const ScAddress& rPos, double fVal)
248{
249 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
250 if (!pTab)
251 return;
252
253 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
254
255 if (!pBlockPos)
256 return;
257
258 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
259 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), fVal);
260}
261
262void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr)
263{
264 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
265 if (!pTab)
266 return;
267
268 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
269
270 if (!pBlockPos)
271 return;
272
273 svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr);
274 if (!aSS.getData())
275 return;
276
277 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
278 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aSS);
279}
280
281void ScDocumentImport::setEditCell(const ScAddress& rPos, std::unique_ptr<EditTextObject> pEditText)
282{
283 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
284 if (!pTab)
285 return;
286
287 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
288
289 if (!pBlockPos)
290 return;
291
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());
295}
296
298 const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar,
299 const double* pResult )
300{
301 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
302 if (!pTab)
303 return;
304
305 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
306
307 if (!pBlockPos)
308 return;
309
310 std::unique_ptr<ScFormulaCell> pFC =
311 std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, rFormula, eGrammar);
312
313 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
314
315 if (pResult)
316 {
317 // Set cached result to this formula cell.
318 pFC->SetResultDouble(*pResult);
319 }
320
321 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
322 pBlockPos->miCellPos =
323 rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
324}
325
327 const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar,
328 const OUString& rResult )
329{
330 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
331 if (!pTab)
332 return;
333
334 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
335
336 if (!pBlockPos)
337 return;
338
339 std::unique_ptr<ScFormulaCell> pFC =
340 std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, rFormula, eGrammar);
341
342 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
343
344 // Set cached result to this formula cell.
345 pFC->SetHybridString(mpImpl->mrDoc.GetSharedStringPool().intern(rResult));
346
347 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
348 pBlockPos->miCellPos =
349 rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
350}
351
352void ScDocumentImport::setFormulaCell(const ScAddress& rPos, std::unique_ptr<ScTokenArray> pArray)
353{
354 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
355 if (!pTab)
356 return;
357
358 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
359
360 if (!pBlockPos)
361 return;
362
363 std::unique_ptr<ScFormulaCell> pFC =
364 std::make_unique<ScFormulaCell>(mpImpl->mrDoc, rPos, std::move(pArray));
365
366 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pFC->GetCode());
367
368 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
369 pBlockPos->miCellPos =
370 rCells.set(pBlockPos->miCellPos, rPos.Row(), pFC.release());
371}
372
374{
375 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
376 if (!pTab)
377 return;
378
379 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
380
381 if (!pBlockPos)
382 return;
383
384 if (pCell)
385 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
386
387 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
388
389 sc::CellStoreType::position_type aPos = rCells.position(rPos.Row());
390 if (aPos.first != rCells.end() && aPos.first->type == sc::element_type_formula)
391 {
392 ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
394 }
395
396 pBlockPos->miCellPos =
397 rCells.set(pBlockPos->miCellPos, rPos.Row(), pCell);
398}
399
401 const ScRange& rRange, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram)
402{
403 const ScAddress& rBasePos = rRange.aStart;
404
405 ScTable* pTab = mpImpl->mrDoc.FetchTable(rBasePos.Tab());
406 if (!pTab)
407 return;
408
409 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rBasePos.Tab(), rBasePos.Col());
410
411 if (!pBlockPos)
412 return;
413
414 if (utl::ConfigManager::IsFuzzing()) //just too slow
415 return;
416
417 sc::CellStoreType& rCells = pTab->aCol[rBasePos.Col()].maCells;
418
419 // Set the master cell.
420 ScFormulaCell* pCell = new ScFormulaCell(mpImpl->mrDoc, rBasePos, rArray, eGram, ScMatrixMode::Formula);
421
422 mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
423
424 pBlockPos->miCellPos =
425 rCells.set(pBlockPos->miCellPos, rBasePos.Row(), pCell);
426
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);
430
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);
438
439 ScTokenArray aArr(mpImpl->mrDoc); // consists only of one single reference token.
440 formula::FormulaToken* t = aArr.AddMatrixSingleReference(aRefData);
441
442 ScAddress aPos = rBasePos;
443 for (SCROW nRow = rRange.aStart.Row()+1; nRow <= rRange.aEnd.Row(); ++nRow)
444 {
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);
454 }
455
456 for (SCCOL nCol = rRange.aStart.Col()+1; nCol <= rRange.aEnd.Col(); ++nCol)
457 {
458 pBlockPos = mpImpl->getBlockPosition(rBasePos.Tab(), nCol);
459 if (!pBlockPos)
460 return;
461
462 sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
463
464 aPos.SetCol(nCol);
465 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
466 {
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);
474 }
475 }
476}
477
479{
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();
485
486 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
487 if (!pTab)
488 return;
489
490 ScDocument& rDoc = mpImpl->mrDoc;
491 ScRefAddress aRef;
492 OUStringBuffer aFormulaBuf;
493 aFormulaBuf.append('=');
494 aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocTableOp));
495 aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocOpen));
496
497 OUString aSep = ScCompiler::GetNativeSymbol(ocSep);
498 if (rParam.meMode == ScTabOpParam::Column) // column only
499 {
500 aRef.Set(rParam.aRefFormulaCell.GetAddress(), true, false, false);
501 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
502 aFormulaBuf.append(aSep);
503 aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
504 aFormulaBuf.append(aSep);
505 aRef.Set(nCol1, nRow1, nTab, false, true, true);
506 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
507 nCol1++;
508 nCol2 = std::min( nCol2, static_cast<SCCOL>(rParam.aRefFormulaEnd.Col() -
509 rParam.aRefFormulaCell.Col() + nCol1 + 1));
510 }
511 else if (rParam.meMode == ScTabOpParam::Row) // row only
512 {
513 aRef.Set(rParam.aRefFormulaCell.GetAddress(), false, true, false);
514 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
515 aFormulaBuf.append(aSep);
516 aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
517 aFormulaBuf.append(aSep);
518 aRef.Set(nCol1, nRow1, nTab, true, false, true);
519 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
520 ++nRow1;
521 nRow2 = std::min(
522 nRow2, rParam.aRefFormulaEnd.Row() - rParam.aRefFormulaCell.Row() + nRow1 + 1);
523 }
524 else // both
525 {
526 aFormulaBuf.append(rParam.aRefFormulaCell.GetRefString(rDoc, nTab));
527 aFormulaBuf.append(aSep);
528 aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
529 aFormulaBuf.append(aSep);
530 aRef.Set(nCol1, nRow1 + 1, nTab, false, true, true);
531 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
532 aFormulaBuf.append(aSep);
533 aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
534 aFormulaBuf.append(aSep);
535 aRef.Set(nCol1 + 1, nRow1, nTab, true, false, true);
536 aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
537 ++nCol1;
538 ++nRow1;
539 }
540
541 aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocClose));
542
543 ScFormulaCell aRefCell(
544 rDoc, ScAddress(nCol1, nRow1, nTab), aFormulaBuf.makeStringAndClear(),
546
547 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
548 {
549 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(nTab, nCol);
550
551 if (!pBlockPos)
552 // Something went horribly wrong.
553 return;
554
555 sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
556
557 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
558 {
559 ScAddress aPos(nCol, nRow, nTab);
560 ScFormulaCell* pCell = new ScFormulaCell(aRefCell, rDoc, aPos);
561 pBlockPos->miCellPos =
562 rColCells.set(pBlockPos->miCellPos, nRow, pCell);
563 }
564 }
565}
566
568{
569 ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
570 if (!pTab)
571 return;
572
573 sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
574
575 if (!pBlockPos)
576 return;
577
578 sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
579 ScRefCellValue aRefCell = pTab->aCol[rPos.Col()].GetCellValue(*pBlockPos, rPos.Row());
580
581 switch (aRefCell.getType())
582 {
583 case CELLTYPE_VALUE:
584 {
585 std::vector<double> aCopied(nFillSize, aRefCell.getDouble());
586 pBlockPos->miCellPos = rCells.set(
587 pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
588 break;
589 }
590 case CELLTYPE_STRING:
591 {
592 std::vector<svl::SharedString> aCopied(nFillSize, *aRefCell.getSharedString());
593 pBlockPos->miCellPos = rCells.set(
594 pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
595 break;
596 }
597 default:
598 break;
599 }
600}
601
602void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs&& rAttrs )
603{
604 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
605 if (!pTab)
606 return;
607
608 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol )
609 {
610 ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
611 if (pColAttr)
612 pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly;
613 }
614
615 pTab->SetAttrEntries( nColStart, nColEnd, std::move( rAttrs.mvData ));
616}
617
618void ScDocumentImport::setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible)
619{
620 if (!bVisible)
621 {
622 getDoc().ShowRows(nRowStart, nRowEnd, nTab, false);
623 getDoc().SetDrawPageSize(nTab);
624 getDoc().UpdatePageBreaks( nTab );
625 }
626 else
627 {
628 assert(false);
629 }
630}
631
632void ScDocumentImport::setMergedCells(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
633{
634 ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
635 if (!pTab)
636 return;
637
638 pTab->SetMergedCells(nCol1, nRow1, nCol2, nRow2);
639}
640
641namespace {
642
643class CellStoreInitializer
644{
645 // The pimpl pattern here is intentional.
646 //
647 // The problem with having the attributes in CellStoreInitializer
648 // directly is that, as a functor, it might be copied around. In
649 // that case miPos in _copied_ object points to maAttrs in the
650 // original object, not in the copy. So later, deep in mdds, we end
651 // up comparing iterators from different sequences.
652 //
653 // This could be solved by defining copy constructor and operator=,
654 // but given the limited usage of the class, I think it is simpler
655 // to let copies share the state.
656 struct Impl
657 {
659 sc::CellTextAttrStoreType::iterator miPos;
660 SvtScriptType mnScriptNumeric;
661
662 explicit Impl(const ScSheetLimits& rSheetLimits, const SvtScriptType nScriptNumeric)
663 : maAttrs(rSheetLimits.GetMaxRowCount()), miPos(maAttrs.begin()), mnScriptNumeric(nScriptNumeric)
664 {}
665 };
666
667 ScDocumentImportImpl& mrDocImpl;
668 SCTAB mnTab;
669 SCCOL mnCol;
670
671public:
672 CellStoreInitializer( ScDocumentImportImpl& rDocImpl, SCTAB nTab, SCCOL nCol ) :
673 mrDocImpl(rDocImpl),
674 mnTab(nTab),
675 mnCol(nCol),
676 mpImpl(std::make_shared<Impl>(rDocImpl.mrDoc.GetSheetLimits(), mrDocImpl.mnDefaultScriptNumeric))
677 {}
678
679 std::shared_ptr<Impl> mpImpl;
680
681 void operator() (const sc::CellStoreType::value_type& node)
682 {
683 if (node.type == sc::element_type_empty)
684 return;
685
686 // Fill with default values for non-empty cell segments.
687 sc::CellTextAttr aDefault;
688 switch (node.type)
689 {
691 {
692 aDefault.mnScriptType = mpImpl->mnScriptNumeric;
693 const ColAttr* p = mrDocImpl.getColAttr(mnTab, mnCol);
694 if (p && p->mbLatinNumFmtOnly)
695 aDefault.mnScriptType = SvtScriptType::LATIN;
696 }
697 break;
699 {
700 const ColAttr* p = mrDocImpl.getColAttr(mnTab, mnCol);
701 if (p && p->mbLatinNumFmtOnly)
702 {
703 // We can assume latin script type if the block only
704 // contains formula cells with numeric results.
705 ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
706 ScFormulaCell** ppEnd = pp + node.size;
707 bool bNumResOnly = true;
708 for (; pp != ppEnd; ++pp)
709 {
710 const ScFormulaCell& rCell = **pp;
711 if (!rCell.IsValueNoError())
712 {
713 bNumResOnly = false;
714 break;
715 }
716 }
717
718 if (bNumResOnly)
719 aDefault.mnScriptType = SvtScriptType::LATIN;
720 }
721 }
722 break;
723 default:
724 ;
725 }
726
727 std::vector<sc::CellTextAttr> aDefaults(node.size, aDefault);
728 mpImpl->miPos = mpImpl->maAttrs.set(mpImpl->miPos, node.position, aDefaults.begin(), aDefaults.end());
729
730 if (node.type != sc::element_type_formula)
731 return;
732
733 if (mrDocImpl.mbFuzzing) // skip listening when fuzzing
734 return;
735
736 // Have all formula cells start listening to the document.
737 ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
738 ScFormulaCell** ppEnd = pp + node.size;
739 for (; pp != ppEnd; ++pp)
740 {
741 ScFormulaCell& rFC = **pp;
742 if (rFC.IsSharedTop())
743 {
744 // Register formula cells as a group.
746 pp += rFC.GetSharedLength() - 1; // Move to the last one in the group.
747 }
748 else
749 rFC.StartListeningTo(mrDocImpl.maListenCxt);
750 }
751 }
752
753 void swap(sc::CellTextAttrStoreType& rAttrs)
754 {
755 mpImpl->maAttrs.swap(rAttrs);
756 }
757};
758
759}
760
762{
763 // Populate the text width and script type arrays in all columns. Also
764 // activate all formula cells.
765 for (auto& rxTab : mpImpl->mrDoc.maTabs)
766 {
767 if (!rxTab)
768 continue;
769
770 ScTable& rTab = *rxTab;
771 SCCOL nNumCols = rTab.aCol.size();
772 for (SCCOL nColIdx = 0; nColIdx < nNumCols; ++nColIdx)
773 initColumn(rTab.aCol[nColIdx]);
774 }
775
776 mpImpl->mrDoc.finalizeOutlineImport();
777}
778
780{
781 rCol.RegroupFormulaCells();
782
783 CellStoreInitializer aFunc(*mpImpl, rCol.nTab, rCol.nCol);
784 std::for_each(rCol.maCells.begin(), rCol.maCells.end(), aFunc);
785 aFunc.swap(rCol.maCellTextAttrs);
786
787 rCol.CellStorageModified();
788}
789
790namespace {
791
792class CellStoreAfterImportBroadcaster
793{
794public:
795
796 CellStoreAfterImportBroadcaster() {}
797
798 void operator() (const sc::CellStoreType::value_type& node)
799 {
800 if (node.type == sc::element_type_formula)
801 {
802 // Broadcast all formula cells marked for recalc.
803 ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
804 ScFormulaCell** ppEnd = pp + node.size;
805 for (; pp != ppEnd; ++pp)
806 {
807 if ((*pp)->GetCode()->IsRecalcModeMustAfterImport())
808 (*pp)->SetDirty();
809 }
810 }
811 }
812};
813
814}
815
817{
818 sc::AutoCalcSwitch aACSwitch( mpImpl->mrDoc, false);
819 ScBulkBroadcast aBulkBroadcast( mpImpl->mrDoc.GetBASM(), SfxHintId::ScDataChanged);
820
821 for (auto& rxTab : mpImpl->mrDoc.maTabs)
822 {
823 if (!rxTab)
824 continue;
825
826 ScTable& rTab = *rxTab;
827 SCCOL nNumCols = rTab.aCol.size();
828 for (SCCOL nColIdx = 0; nColIdx < nNumCols; ++nColIdx)
830 }
831}
832
834{
835 CellStoreAfterImportBroadcaster aFunc;
836 std::for_each(rCol.maCells.begin(), rCol.maCells.end(), aFunc);
837}
838
839
841{
842 SvNumberFormatter* pFormatter = mpImpl->mrDoc.GetFormatTable();
843 sal_uInt32 nKey = rPatAttr.GetNumberFormat(pFormatter);
844 return isLatinScript(nKey);
845}
846
847bool ScDocumentImport::isLatinScript(sal_uInt32 nFormat)
848{
849 auto it = mpImpl->maIsLatinScriptMap.find(nFormat);
850 if (it != mpImpl->maIsLatinScriptMap.end())
851 return it->second;
852 bool b = sc::NumFmtUtil::isLatinScript(nFormat, mpImpl->mrDoc);
853 mpImpl->maIsLatinScriptMap.emplace(nFormat, b);
854 return b;
855}
856
857/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
bool ValidTab(SCTAB nTab)
Definition: address.hxx:111
const SCTAB MAXTAB
Definition: address.hxx:70
SCTAB Tab() const
Definition: address.hxx:283
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
SCCOL Col() const
Definition: address.hxx:279
SCCOL size() const
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1660
SCCOL nCol
Definition: column.hxx:203
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:187
SCTAB nTab
Definition: column.hxx:204
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3674
sc::CellStoreType maCells
Definition: column.hxx:196
void setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible)
void setMatrixCells(const ScRange &rRange, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGrammar)
void setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uInt16 nDay)
void initColumn(ScColumn &rCol)
void initForSheets()
Initialize the storage for all sheets after all the sheet instances have been created in the document...
void setMergedCells(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
void setEditCell(const ScAddress &rPos, std::unique_ptr< EditTextObject > pEditText)
void broadcastRecalcAfterImport()
Broadcast all formula cells that are marked with FormulaTokenArray::IsRecalcModeMustAfterImport() for...
void setStringCell(const ScAddress &rPos, const OUString &rStr)
bool appendSheet(const OUString &rName)
void setDefaultNumericScript(SvtScriptType nScript)
void setFormulaCell(const ScAddress &rPos, const OUString &rFormula, formula::FormulaGrammar::Grammar eGrammar, const double *pResult=nullptr)
void setTableOpCells(const ScRange &rRange, const ScTabOpParam &rParam)
ScDocument & getDoc()
bool isLatinScript(sal_uInt32 nFormat)
small cache for hot call during import
void setSheetName(SCTAB nTab, const OUString &rName)
ScDocumentImport()=delete
void invalidateBlockPositionSet(SCTAB nTab)
static void broadcastRecalcAfterImportColumn(ScColumn &rCol)
SCTAB getSheetCount() const
std::unique_ptr< ScDocumentImportImpl > mpImpl
void setAttrEntries(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs &&rAttrs)
Set an array of cell attributes to specified range of columns.
SCTAB getSheetIndex(const OUString &rName) const
void setNumericCell(const ScAddress &rPos, double fVal)
void fillDownCells(const ScAddress &rPos, SCROW nFillSize)
void setAutoInput(const ScAddress &rPos, const OUString &rStr, const ScSetStringParam *pStringParam=nullptr)
void setCellStyleToSheet(SCTAB nTab, const ScStyleSheet &rStyle)
Apply specified cell style to an entire sheet.
void UpdatePageBreaks(SCTAB nTab, const ScRange *pUserArea=nullptr)
Definition: document.cxx:6337
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
SC_DLLPUBLIC void SetDrawPageSize(SCTAB nTab)
Definition: documen9.cxx:195
SC_DLLPUBLIC void ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
Definition: document.cxx:4374
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:317
SCROW GetSharedLength() const
bool IsValueNoError()
bool IsSharedTop() const
void StartListeningTo(ScDocument &rDoc)
void SetDirty(bool bDirtyFlag=true)
void SetMatColsRows(SCCOL nCols, SCROW nRows)
ScTokenArray * GetCode()
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1301
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
SCCOL Col() const
Definition: address.hxx:886
OUString GetRefString(const ScDocument &rDocument, SCTAB nActTab, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1) const
Definition: address.cxx:2490
const ScAddress & GetAddress() const
Definition: address.hxx:881
void Set(const ScAddress &rAdr, bool bNewRelCol, bool bNewRelRow, bool bNewRelTab)
Definition: address.hxx:914
SCROW Row() const
Definition: address.hxx:890
void ApplyStyleArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScStyleSheet &rStyle)
Definition: table2.cxx:3013
void SetAttrEntries(SCCOL nStartCol, SCCOL nEndCol, std::vector< ScAttrEntry > &&vNewData)
Definition: table2.cxx:2914
ScColContainer aCol
Definition: table.hxx:160
void SetMergedCells(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: table2.cxx:2344
static const OUString & GetNativeSymbol(OpCode eOp)
Temporarily switch on/off auto calculation mode.
Definition: scopetools.hxx:27
static bool isLatinScript(const ScPatternAttr &rPat, ScDocument &rDoc)
Check if the attribute pattern has a number format that only produces latin script output.
Definition: numformat.cxx:31
static void startListeningAsGroup(StartListeningContext &rCxt, ScFormulaCell **ppSharedTop)
Have all formula cells belonging to a group start listening to their references.
static void unshareFormulaCell(const CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Turn a shared formula cell into a non-shared one, and split it off from the adjacent formula cell gro...
Set of column block positions only for one table.
ColumnBlockPosition * getBlockPosition(SCCOL nCol)
rtl_uString * getData()
static bool IsFuzzing()
sal_Int32 mnCol
UNKNOWN
@ CELLTYPE_EDIT
Definition: global.hxx:276
@ CELLTYPE_STRING
Definition: global.hxx:274
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_VALUE
Definition: global.hxx:273
void * p
sal_Int64 n
SvtScriptType
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
std::shared_ptr< T > make_shared(Args &&... args)
enumrange< T >::Iterator begin(enumrange< T >)
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:50
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:56
mdds::mtv::soa::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:57
const SvxPageUsage aArr[]
ocClose
ocOpen
ocSep
ocTableOp
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:32
ScFormulaCell * releaseFormula()
Definition: cellvalue.hxx:63
const svl::SharedString * getSharedString() const
Definition: cellvalue.hxx:60
EditTextObject * releaseEditText()
Definition: cellvalue.hxx:62
CellType getType() const
Definition: cellvalue.cxx:296
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:59
double getDouble() const
Definition: cellvalue.hxx:58
ColAttr * getColAttr(size_t nTab, size_t nCol)
std::unordered_map< sal_uInt32, bool > maIsLatinScriptMap
sc::StartListeningContext maListenCxt
ScDocumentImportImpl(ScDocument &rDoc)
sc::ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
bool isValid(size_t nTab, size_t nCol)
SvtScriptType mnDefaultScriptNumeric
void invalidateBlockPositionSet(SCTAB nTab)
std::vector< TabAttr > maTabAttrs
std::vector< sc::TableColumnBlockPositionSet > maBlockPosSet
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
double getDouble() const
Definition: cellvalue.hxx:134
const svl::SharedString * getSharedString() const
Definition: cellvalue.hxx:135
CellType getType() const
Definition: cellvalue.hxx:133
Store parameters used in the ScDocument::SetString() method.
Definition: stringutil.hxx:35
bool mbCheckLinkFormula
When true and the string results in a compiled formula, check the formula tokens for presence of func...
Definition: stringutil.hxx:100
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void SetAddress(const ScSheetLimits &rLimits, const ScAddress &rAddr, const ScAddress &rPos)
Definition: refdata.cxx:213
void SetRowRel(bool bVal)
Definition: refdata.hxx:66
void SetTabRel(bool bVal)
Definition: refdata.hxx:68
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:54
void SetColRel(bool bVal)
Definition: refdata.hxx:64
Parameter for data table aka multiple operations.
Definition: paramisc.hxx:46
ScRefAddress aRefFormulaEnd
Definition: paramisc.hxx:50
ScRefAddress aRefColCell
Definition: paramisc.hxx:52
ScRefAddress aRefFormulaCell
Definition: paramisc.hxx:49
ScRefAddress aRefRowCell
Definition: paramisc.hxx:51
SvtScriptType mnScriptType
Store position data for column array storage.
CellStoreType::iterator miCellPos
bool bVisible
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17