1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "documentimport.hxx"
11 #include "document.hxx"
14 #include "formulacell.hxx"
15 #include "docoptio.hxx"
16 #include "globalnames.hxx"
17 #include "mtvelements.hxx"
18 #include "tokenarray.hxx"
19 #include "stringutil.hxx"
20 #include "compiler.hxx"
21 #include "paramisc.hxx"
22 #include "listenercontext.hxx"
23 #include <attarray.hxx>
24 #include <sharedformula.hxx>
26 #include <svl/sharedstringpool.hxx>
27 #include <svl/languageoptions.hxx>
35 bool mbLatinNumFmtOnly
;
37 ColAttr() : mbLatinNumFmtOnly(false) {}
42 std::vector
<ColAttr
> maCols
;
45 typedef std::vector
<TabAttr
> TabAttrsType
;
49 struct ScDocumentImportImpl
52 sc::StartListeningContext maListenCxt
;
53 sc::ColumnBlockPositionSet maBlockPosSet
;
54 SvtScriptType mnDefaultScriptNumeric
;
56 TabAttrsType maTabAttrs
;
58 ScDocumentImportImpl(ScDocument
& rDoc
) :
62 mnDefaultScriptNumeric(SvtScriptType::UNKNOWN
) {}
64 ColAttr
* getColAttr( size_t nTab
, size_t nCol
)
66 if (nTab
> static_cast<size_t>(MAXTAB
) || nCol
> static_cast<size_t>(MAXCOL
))
69 if (nTab
>= maTabAttrs
.size())
70 maTabAttrs
.resize(nTab
+1);
72 TabAttr
& rTab
= maTabAttrs
[nTab
];
73 if (nCol
>= rTab
.maCols
.size())
74 rTab
.maCols
.resize(nCol
+1);
76 return &rTab
.maCols
[nCol
];
80 ScDocumentImport::Attrs::Attrs() : mpData(NULL
), mnSize(0), mbLatinNumFmtOnly(false) {}
82 ScDocumentImport::ScDocumentImport(ScDocument
& rDoc
) : mpImpl(new ScDocumentImportImpl(rDoc
)) {}
83 ScDocumentImport::~ScDocumentImport()
88 ScDocument
& ScDocumentImport::getDoc()
93 const ScDocument
& ScDocumentImport::getDoc() const
98 void ScDocumentImport::setDefaultNumericScript(SvtScriptType nScript
)
100 mpImpl
->mnDefaultScriptNumeric
= nScript
;
103 void ScDocumentImport::setCellStyleToSheet(SCTAB nTab
, const ScStyleSheet
& rStyle
)
105 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
109 pTab
->ApplyStyleArea(0, 0, MAXCOL
, MAXROW
, rStyle
);
112 SCTAB
ScDocumentImport::getSheetIndex(const OUString
& rName
) const
115 if (!mpImpl
->mrDoc
.GetTable(rName
, nTab
))
121 SCTAB
ScDocumentImport::getSheetCount() const
123 return mpImpl
->mrDoc
.maTabs
.size();
126 bool ScDocumentImport::appendSheet(const OUString
& rName
)
128 SCTAB nTabCount
= mpImpl
->mrDoc
.maTabs
.size();
129 if (!ValidTab(nTabCount
))
132 mpImpl
->mrDoc
.maTabs
.push_back(new ScTable(&mpImpl
->mrDoc
, nTabCount
, rName
));
136 void ScDocumentImport::setOriginDate(sal_uInt16 nYear
, sal_uInt16 nMonth
, sal_uInt16 nDay
)
138 if (!mpImpl
->mrDoc
.pDocOptions
)
139 mpImpl
->mrDoc
.pDocOptions
= new ScDocOptions
;
141 mpImpl
->mrDoc
.pDocOptions
->SetDate(nDay
, nMonth
, nYear
);
144 void ScDocumentImport::setAutoInput(const ScAddress
& rPos
, const OUString
& rStr
, ScSetStringParam
* pStringParam
)
146 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
150 sc::ColumnBlockPosition
* pBlockPos
=
151 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
157 pTab
->aCol
[rPos
.Col()].ParseString(
158 aCell
, rPos
.Row(), rPos
.Tab(), rStr
, mpImpl
->mrDoc
.GetAddressConvention(), pStringParam
);
160 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
161 switch (aCell
.meType
)
163 case CELLTYPE_STRING
:
165 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), *aCell
.mpString
);
168 // Cell takes the ownership of the text object.
169 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mpEditText
);
170 aCell
.mpEditText
= NULL
;
173 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mfValue
);
175 case CELLTYPE_FORMULA
:
176 // This formula cell instance is directly placed in the document without copying.
177 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mpFormula
);
178 aCell
.mpFormula
= NULL
;
181 pBlockPos
->miCellPos
= rCells
.set_empty(pBlockPos
->miCellPos
, rPos
.Row(), rPos
.Row());
185 void ScDocumentImport::setNumericCell(const ScAddress
& rPos
, double fVal
)
187 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
191 sc::ColumnBlockPosition
* pBlockPos
=
192 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
197 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
198 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), fVal
);
201 void ScDocumentImport::setStringCell(const ScAddress
& rPos
, const OUString
& rStr
)
203 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
207 sc::ColumnBlockPosition
* pBlockPos
=
208 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
213 svl::SharedString aSS
= mpImpl
->mrDoc
.GetSharedStringPool().intern(rStr
);
217 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
218 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aSS
);
221 void ScDocumentImport::setEditCell(const ScAddress
& rPos
, EditTextObject
* pEditText
)
223 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
227 sc::ColumnBlockPosition
* pBlockPos
=
228 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
233 pEditText
->NormalizeString(mpImpl
->mrDoc
.GetSharedStringPool());
234 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
235 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pEditText
);
238 void ScDocumentImport::setFormulaCell(
239 const ScAddress
& rPos
, const OUString
& rFormula
, formula::FormulaGrammar::Grammar eGrammar
)
241 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
245 sc::ColumnBlockPosition
* pBlockPos
=
246 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
251 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
252 pBlockPos
->miCellPos
=
253 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), new ScFormulaCell(&mpImpl
->mrDoc
, rPos
, rFormula
, eGrammar
));
256 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, ScTokenArray
* pArray
)
258 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
262 sc::ColumnBlockPosition
* pBlockPos
=
263 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
268 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
269 pBlockPos
->miCellPos
=
270 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), new ScFormulaCell(&mpImpl
->mrDoc
, rPos
, pArray
));
273 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, ScFormulaCell
* pCell
)
275 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
279 sc::ColumnBlockPosition
* pBlockPos
=
280 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
285 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
286 pBlockPos
->miCellPos
=
287 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pCell
);
290 void ScDocumentImport::setMatrixCells(
291 const ScRange
& rRange
, const ScTokenArray
& rArray
, formula::FormulaGrammar::Grammar eGram
)
293 const ScAddress
& rBasePos
= rRange
.aStart
;
295 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rBasePos
.Tab());
299 sc::ColumnBlockPosition
* pBlockPos
=
300 mpImpl
->maBlockPosSet
.getBlockPosition(rBasePos
.Tab(), rBasePos
.Col());
305 sc::CellStoreType
& rCells
= pTab
->aCol
[rBasePos
.Col()].maCells
;
307 // Set the master cell.
308 ScFormulaCell
* pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, rBasePos
, rArray
, eGram
, MM_FORMULA
);
310 pBlockPos
->miCellPos
=
311 rCells
.set(pBlockPos
->miCellPos
, rBasePos
.Row(), pCell
);
313 // Matrix formulas currently need re-calculation on import.
314 pCell
->SetMatColsRows(
315 rRange
.aEnd
.Col()-rRange
.aStart
.Col()+1, rRange
.aEnd
.Row()-rRange
.aStart
.Row()+1, true);
317 // Set the reference cells.
318 ScSingleRefData aRefData
;
319 aRefData
.InitFlags();
320 aRefData
.SetColRel(true);
321 aRefData
.SetRowRel(true);
322 aRefData
.SetTabRel(true);
323 aRefData
.SetAddress(rBasePos
, rBasePos
);
325 ScTokenArray aArr
; // consists only of one single reference token.
326 formula::FormulaToken
* t
= aArr
.AddMatrixSingleReference(aRefData
);
328 ScAddress aPos
= rBasePos
;
329 for (SCROW nRow
= rRange
.aStart
.Row()+1; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
331 // Token array must be cloned so that each formula cell receives its own copy.
333 // Reference in each cell must point to the origin cell relative to the current cell.
334 aRefData
.SetAddress(rBasePos
, aPos
);
335 *t
->GetSingleRef() = aRefData
;
336 boost::scoped_ptr
<ScTokenArray
> pTokArr(aArr
.Clone());
337 pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, aPos
, *pTokArr
, eGram
, MM_REFERENCE
);
338 pBlockPos
->miCellPos
=
339 rCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
342 for (SCCOL nCol
= rRange
.aStart
.Col()+1; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
344 pBlockPos
= mpImpl
->maBlockPosSet
.getBlockPosition(rBasePos
.Tab(), nCol
);
348 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
351 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
354 aRefData
.SetAddress(rBasePos
, aPos
);
355 *t
->GetSingleRef() = aRefData
;
356 boost::scoped_ptr
<ScTokenArray
> pTokArr(aArr
.Clone());
357 pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, aPos
, *pTokArr
, eGram
, MM_REFERENCE
);
358 pBlockPos
->miCellPos
=
359 rColCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
364 void ScDocumentImport::setTableOpCells(const ScRange
& rRange
, const ScTabOpParam
& rParam
)
366 SCTAB nTab
= rRange
.aStart
.Tab();
367 SCCOL nCol1
= rRange
.aStart
.Col();
368 SCROW nRow1
= rRange
.aStart
.Row();
369 SCCOL nCol2
= rRange
.aEnd
.Col();
370 SCROW nRow2
= rRange
.aEnd
.Row();
372 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
376 ScDocument
* pDoc
= &mpImpl
->mrDoc
;
378 OUStringBuffer aFormulaBuf
;
379 aFormulaBuf
.append('=');
380 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocTableOp
));
381 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocOpen
));
383 OUString aSep
= ScCompiler::GetNativeSymbol(ocSep
);
384 if (rParam
.meMode
== ScTabOpParam::Column
) // column only
386 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), true, false, false);
387 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
388 aFormulaBuf
.append(aSep
);
389 aFormulaBuf
.append(rParam
.aRefColCell
.GetRefString(pDoc
, nTab
));
390 aFormulaBuf
.append(aSep
);
391 aRef
.Set(nCol1
, nRow1
, nTab
, false, true, true);
392 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
394 nCol2
= std::min( nCol2
, (SCCOL
)(rParam
.aRefFormulaEnd
.Col() -
395 rParam
.aRefFormulaCell
.Col() + nCol1
+ 1));
397 else if (rParam
.meMode
== ScTabOpParam::Row
) // row only
399 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), false, true, false);
400 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
401 aFormulaBuf
.append(aSep
);
402 aFormulaBuf
.append(rParam
.aRefRowCell
.GetRefString(pDoc
, nTab
));
403 aFormulaBuf
.append(aSep
);
404 aRef
.Set(nCol1
, nRow1
, nTab
, true, false, true);
405 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
408 nRow2
, rParam
.aRefFormulaEnd
.Row() - rParam
.aRefFormulaCell
.Row() + nRow1
+ 1);
412 aFormulaBuf
.append(rParam
.aRefFormulaCell
.GetRefString(pDoc
, nTab
));
413 aFormulaBuf
.append(aSep
);
414 aFormulaBuf
.append(rParam
.aRefColCell
.GetRefString(pDoc
, nTab
));
415 aFormulaBuf
.append(aSep
);
416 aRef
.Set(nCol1
, nRow1
+ 1, nTab
, false, true, true);
417 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
418 aFormulaBuf
.append(aSep
);
419 aFormulaBuf
.append(rParam
.aRefRowCell
.GetRefString(pDoc
, nTab
));
420 aFormulaBuf
.append(aSep
);
421 aRef
.Set(nCol1
+ 1, nRow1
, nTab
, true, false, true);
422 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
427 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocClose
));
429 ScFormulaCell
aRefCell(
430 pDoc
, ScAddress(nCol1
, nRow1
, nTab
), aFormulaBuf
.makeStringAndClear(),
431 formula::FormulaGrammar::GRAM_NATIVE
, MM_NONE
);
433 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
435 sc::ColumnBlockPosition
* pBlockPos
=
436 mpImpl
->maBlockPosSet
.getBlockPosition(nTab
, nCol
);
439 // Something went horribly wrong.
442 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
444 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
446 ScAddress
aPos(nCol
, nRow
, nTab
);
447 ScFormulaCell
* pCell
= new ScFormulaCell(aRefCell
, *pDoc
, aPos
);
448 pBlockPos
->miCellPos
=
449 rColCells
.set(pBlockPos
->miCellPos
, nRow
, pCell
);
454 void ScDocumentImport::setAttrEntries( SCTAB nTab
, SCCOL nCol
, Attrs
& rAttrs
)
456 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
460 ScColumn
* pCol
= pTab
->FetchColumn(nCol
);
464 ColAttr
* pColAttr
= mpImpl
->getColAttr(nTab
, nCol
);
466 pColAttr
->mbLatinNumFmtOnly
= rAttrs
.mbLatinNumFmtOnly
;
468 pCol
->pAttrArray
->SetAttrEntries(rAttrs
.mpData
, rAttrs
.mnSize
);
473 class CellStoreInitializer
475 // The pimpl pattern here is intentional.
477 // The problem with having the attributes in CellStoreInitializer
478 // directly is that, as a functor, it might be copied around. In
479 // that case miPos in _copied_ object points ot maAttrs in the
480 // original object, not in the copy. So later, deep in mdds, we end
481 // up comparing iterators from different sequences.
483 // This could be solved by defining copy constructor and operator=,
484 // but given the limited usage of the class, I think it is simpler
485 // to let copies share the state.
488 sc::CellTextAttrStoreType maAttrs
;
489 sc::CellTextAttrStoreType::iterator miPos
;
490 SvtScriptType mnScriptNumeric
;
492 Impl(const sal_uInt32 nMaxRowCount
, const SvtScriptType nScriptNumeric
)
493 : maAttrs(nMaxRowCount
), miPos(maAttrs
.begin()), mnScriptNumeric(nScriptNumeric
)
497 ScDocumentImportImpl
& mrDocImpl
;
502 CellStoreInitializer( ScDocumentImportImpl
& rDocImpl
, SCTAB nTab
, SCCOL nCol
) :
506 mpImpl(new Impl(MAXROWCOUNT
, mrDocImpl
.mnDefaultScriptNumeric
))
509 boost::shared_ptr
<Impl
> mpImpl
;
511 void operator() (const sc::CellStoreType::value_type
& node
)
513 if (node
.type
== sc::element_type_empty
)
516 // Fill with default values for non-empty cell segments.
517 sc::CellTextAttr aDefault
;
520 case sc::element_type_numeric
:
522 aDefault
.mnScriptType
= mpImpl
->mnScriptNumeric
;
523 const ColAttr
* p
= mrDocImpl
.getColAttr(mnTab
, mnCol
);
524 if (p
&& p
->mbLatinNumFmtOnly
)
525 aDefault
.mnScriptType
= SvtScriptType::LATIN
;
528 case sc::element_type_formula
:
530 const ColAttr
* p
= mrDocImpl
.getColAttr(mnTab
, mnCol
);
531 if (p
&& p
->mbLatinNumFmtOnly
)
533 // We can assume latin script type if the block only
534 // contains formula cells with numeric results.
535 ScFormulaCell
** pp
= &sc::formula_block::at(*node
.data
, 0);
536 ScFormulaCell
** ppEnd
= pp
+ node
.size
;
537 bool bNumResOnly
= true;
538 for (; pp
!= ppEnd
; ++pp
)
540 const ScFormulaCell
& rCell
= **pp
;
541 if (!rCell
.IsValueNoError())
549 aDefault
.mnScriptType
= SvtScriptType::LATIN
;
557 std::vector
<sc::CellTextAttr
> aDefaults(node
.size
, aDefault
);
558 mpImpl
->miPos
= mpImpl
->maAttrs
.set(mpImpl
->miPos
, node
.position
, aDefaults
.begin(), aDefaults
.end());
560 if (node
.type
== sc::element_type_formula
)
562 // Have all formula cells start listening to the document.
563 ScFormulaCell
** pp
= &sc::formula_block::at(*node
.data
, 0);
564 ScFormulaCell
** ppEnd
= pp
+ node
.size
;
565 for (; pp
!= ppEnd
; ++pp
)
567 ScFormulaCell
& rFC
= **pp
;
568 if (rFC
.IsSharedTop())
570 // Register formula cells as a group.
571 sc::SharedFormulaUtil::startListeningAsGroup(mrDocImpl
.maListenCxt
, pp
);
572 pp
+= rFC
.GetSharedLength() - 1; // Move to the last one in the group.
575 rFC
.StartListeningTo(mrDocImpl
.maListenCxt
);
580 void swap(sc::CellTextAttrStoreType
& rAttrs
)
582 mpImpl
->maAttrs
.swap(rAttrs
);
588 void ScDocumentImport::finalize()
590 // Populate the text width and script type arrays in all columns. Also
591 // activate all formula cells.
592 ScDocument::TableContainer::iterator itTab
= mpImpl
->mrDoc
.maTabs
.begin(), itTabEnd
= mpImpl
->mrDoc
.maTabs
.end();
593 for (; itTab
!= itTabEnd
; ++itTab
)
598 ScTable
& rTab
= **itTab
;
599 ScColumn
* pCol
= &rTab
.aCol
[0];
600 ScColumn
* pColEnd
= pCol
+ static_cast<size_t>(MAXCOLCOUNT
);
601 for (; pCol
!= pColEnd
; ++pCol
)
606 void ScDocumentImport::initColumn(ScColumn
& rCol
)
608 rCol
.RegroupFormulaCells();
610 CellStoreInitializer
aFunc(*mpImpl
, rCol
.nTab
, rCol
.nCol
);
611 std::for_each(rCol
.maCells
.begin(), rCol
.maCells
.end(), aFunc
);
612 aFunc
.swap(rCol
.maCellTextAttrs
);
614 rCol
.CellStorageModified();
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */