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"
24 #include "svl/sharedstringpool.hxx"
26 struct ScDocumentImportImpl
29 sc::StartListeningContext maListenCxt
;
30 sc::ColumnBlockPositionSet maBlockPosSet
;
31 sal_uInt16 mnDefaultScriptNumeric
;
33 ScDocumentImportImpl(ScDocument
& rDoc
) :
37 mnDefaultScriptNumeric(SC_SCRIPTTYPE_UNKNOWN
) {}
40 ScDocumentImport::ScDocumentImport(ScDocument
& rDoc
) : mpImpl(new ScDocumentImportImpl(rDoc
)) {}
41 ScDocumentImport::~ScDocumentImport()
46 ScDocument
& ScDocumentImport::getDoc()
51 const ScDocument
& ScDocumentImport::getDoc() const
56 void ScDocumentImport::setDefaultNumericScript(sal_uInt16 nScript
)
58 mpImpl
->mnDefaultScriptNumeric
= nScript
;
61 void ScDocumentImport::setCellStyleToSheet(SCTAB nTab
, const ScStyleSheet
& rStyle
)
63 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
67 pTab
->ApplyStyleArea(0, 0, MAXCOL
, MAXROW
, rStyle
);
70 SCTAB
ScDocumentImport::getSheetIndex(const OUString
& rName
) const
73 if (!mpImpl
->mrDoc
.GetTable(rName
, nTab
))
79 SCTAB
ScDocumentImport::getSheetCount() const
81 return mpImpl
->mrDoc
.maTabs
.size();
84 bool ScDocumentImport::appendSheet(const OUString
& rName
)
86 SCTAB nTabCount
= mpImpl
->mrDoc
.maTabs
.size();
87 if (!ValidTab(nTabCount
))
90 mpImpl
->mrDoc
.maTabs
.push_back(new ScTable(&mpImpl
->mrDoc
, nTabCount
, rName
));
94 void ScDocumentImport::setOriginDate(sal_uInt16 nYear
, sal_uInt16 nMonth
, sal_uInt16 nDay
)
96 if (!mpImpl
->mrDoc
.pDocOptions
)
97 mpImpl
->mrDoc
.pDocOptions
= new ScDocOptions
;
99 mpImpl
->mrDoc
.pDocOptions
->SetDate(nDay
, nMonth
, nYear
);
102 void ScDocumentImport::setAutoInput(const ScAddress
& rPos
, const OUString
& rStr
, ScSetStringParam
* pStringParam
)
104 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
108 sc::ColumnBlockPosition
* pBlockPos
=
109 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
115 pTab
->aCol
[rPos
.Col()].ParseString(
116 aCell
, rPos
.Row(), rPos
.Tab(), rStr
, mpImpl
->mrDoc
.GetAddressConvention(), pStringParam
);
118 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
119 switch (aCell
.meType
)
121 case CELLTYPE_STRING
:
123 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), *aCell
.mpString
);
126 // Cell takes the ownership of the text object.
127 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mpEditText
);
128 aCell
.mpEditText
= NULL
;
131 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mfValue
);
133 case CELLTYPE_FORMULA
:
134 // This formula cell instance is directly placed in the document without copying.
135 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aCell
.mpFormula
);
136 aCell
.mpFormula
= NULL
;
139 pBlockPos
->miCellPos
= rCells
.set_empty(pBlockPos
->miCellPos
, rPos
.Row(), rPos
.Row());
143 void ScDocumentImport::setNumericCell(const ScAddress
& rPos
, double fVal
)
145 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
149 sc::ColumnBlockPosition
* pBlockPos
=
150 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
155 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
156 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), fVal
);
159 void ScDocumentImport::setStringCell(const ScAddress
& rPos
, const OUString
& rStr
)
161 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
165 sc::ColumnBlockPosition
* pBlockPos
=
166 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
171 svl::SharedString aSS
= mpImpl
->mrDoc
.GetSharedStringPool().intern(rStr
);
175 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
176 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), aSS
);
179 void ScDocumentImport::setEditCell(const ScAddress
& rPos
, EditTextObject
* pEditText
)
181 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
185 sc::ColumnBlockPosition
* pBlockPos
=
186 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
191 pEditText
->NormalizeString(mpImpl
->mrDoc
.GetSharedStringPool());
192 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
193 pBlockPos
->miCellPos
= rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pEditText
);
196 void ScDocumentImport::setFormulaCell(
197 const ScAddress
& rPos
, const OUString
& rFormula
, formula::FormulaGrammar::Grammar eGrammar
)
199 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
203 sc::ColumnBlockPosition
* pBlockPos
=
204 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
209 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
210 pBlockPos
->miCellPos
=
211 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), new ScFormulaCell(&mpImpl
->mrDoc
, rPos
, rFormula
, eGrammar
));
214 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, ScTokenArray
* pArray
)
216 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
220 sc::ColumnBlockPosition
* pBlockPos
=
221 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
226 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
227 pBlockPos
->miCellPos
=
228 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), new ScFormulaCell(&mpImpl
->mrDoc
, rPos
, pArray
));
231 void ScDocumentImport::setFormulaCell(const ScAddress
& rPos
, ScFormulaCell
* pCell
)
233 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rPos
.Tab());
237 sc::ColumnBlockPosition
* pBlockPos
=
238 mpImpl
->maBlockPosSet
.getBlockPosition(rPos
.Tab(), rPos
.Col());
243 sc::CellStoreType
& rCells
= pTab
->aCol
[rPos
.Col()].maCells
;
244 pBlockPos
->miCellPos
=
245 rCells
.set(pBlockPos
->miCellPos
, rPos
.Row(), pCell
);
248 void ScDocumentImport::setMatrixCells(
249 const ScRange
& rRange
, const ScTokenArray
& rArray
, formula::FormulaGrammar::Grammar eGram
)
251 const ScAddress
& rBasePos
= rRange
.aStart
;
253 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(rBasePos
.Tab());
257 sc::ColumnBlockPosition
* pBlockPos
=
258 mpImpl
->maBlockPosSet
.getBlockPosition(rBasePos
.Tab(), rBasePos
.Col());
263 sc::CellStoreType
& rCells
= pTab
->aCol
[rBasePos
.Col()].maCells
;
265 // Set the master cell.
266 ScFormulaCell
* pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, rBasePos
, rArray
, eGram
, MM_FORMULA
);
268 pBlockPos
->miCellPos
=
269 rCells
.set(pBlockPos
->miCellPos
, rBasePos
.Row(), pCell
);
271 // Matrix formulas currently need re-calculation on import.
272 pCell
->SetMatColsRows(
273 rRange
.aEnd
.Col()-rRange
.aStart
.Col()+1, rRange
.aEnd
.Row()-rRange
.aStart
.Row()+1, true);
275 // Set the reference cells.
276 ScSingleRefData aRefData
;
277 aRefData
.InitFlags();
278 aRefData
.SetColRel(true);
279 aRefData
.SetRowRel(true);
280 aRefData
.SetTabRel(true);
281 aRefData
.SetAddress(rBasePos
, rBasePos
);
283 ScTokenArray aArr
; // consists only of one single reference token.
284 ScToken
* t
= static_cast<ScToken
*>(aArr
.AddMatrixSingleReference(aRefData
));
286 ScAddress aPos
= rBasePos
;
287 for (SCROW nRow
= rRange
.aStart
.Row()+1; nRow
<= rRange
.aEnd
.Row(); ++nRow
)
289 // Token array must be cloned so that each formula cell receives its own copy.
291 // Reference in each cell must point to the origin cell relative to the current cell.
292 aRefData
.SetAddress(rBasePos
, aPos
);
293 t
->GetSingleRef() = aRefData
;
294 boost::scoped_ptr
<ScTokenArray
> pTokArr(aArr
.Clone());
295 pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, aPos
, *pTokArr
, eGram
, MM_REFERENCE
);
296 pBlockPos
->miCellPos
=
297 rCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
300 for (SCCOL nCol
= rRange
.aStart
.Col()+1; nCol
<= rRange
.aEnd
.Col(); ++nCol
)
302 pBlockPos
= mpImpl
->maBlockPosSet
.getBlockPosition(rBasePos
.Tab(), nCol
);
306 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
309 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
312 aRefData
.SetAddress(rBasePos
, aPos
);
313 t
->GetSingleRef() = aRefData
;
314 boost::scoped_ptr
<ScTokenArray
> pTokArr(aArr
.Clone());
315 pCell
= new ScFormulaCell(&mpImpl
->mrDoc
, aPos
, *pTokArr
, eGram
, MM_REFERENCE
);
316 pBlockPos
->miCellPos
=
317 rColCells
.set(pBlockPos
->miCellPos
, aPos
.Row(), pCell
);
322 void ScDocumentImport::setTableOpCells(const ScRange
& rRange
, const ScTabOpParam
& rParam
)
324 SCTAB nTab
= rRange
.aStart
.Tab();
325 SCCOL nCol1
= rRange
.aStart
.Col();
326 SCROW nRow1
= rRange
.aStart
.Row();
327 SCCOL nCol2
= rRange
.aEnd
.Col();
328 SCROW nRow2
= rRange
.aEnd
.Row();
330 ScTable
* pTab
= mpImpl
->mrDoc
.FetchTable(nTab
);
334 ScDocument
* pDoc
= &mpImpl
->mrDoc
;
336 OUStringBuffer
aFormulaBuf('=');
337 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocTableOp
));
338 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocOpen
));
340 OUString aSep
= ScCompiler::GetNativeSymbol(ocSep
);
341 if (rParam
.meMode
== ScTabOpParam::Column
) // column only
343 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), true, false, false);
344 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
345 aFormulaBuf
.append(aSep
);
346 aFormulaBuf
.append(rParam
.aRefColCell
.GetRefString(pDoc
, nTab
));
347 aFormulaBuf
.append(aSep
);
348 aRef
.Set(nCol1
, nRow1
, nTab
, false, true, true);
349 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
351 nCol2
= std::min( nCol2
, (SCCOL
)(rParam
.aRefFormulaEnd
.Col() -
352 rParam
.aRefFormulaCell
.Col() + nCol1
+ 1));
354 else if (rParam
.meMode
== ScTabOpParam::Row
) // row only
356 aRef
.Set(rParam
.aRefFormulaCell
.GetAddress(), false, true, false);
357 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
358 aFormulaBuf
.append(aSep
);
359 aFormulaBuf
.append(rParam
.aRefRowCell
.GetRefString(pDoc
, nTab
));
360 aFormulaBuf
.append(aSep
);
361 aRef
.Set(nCol1
, nRow1
, nTab
, true, false, true);
362 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
365 nRow2
, rParam
.aRefFormulaEnd
.Row() - rParam
.aRefFormulaCell
.Row() + nRow1
+ 1);
369 aFormulaBuf
.append(rParam
.aRefFormulaCell
.GetRefString(pDoc
, nTab
));
370 aFormulaBuf
.append(aSep
);
371 aFormulaBuf
.append(rParam
.aRefColCell
.GetRefString(pDoc
, nTab
));
372 aFormulaBuf
.append(aSep
);
373 aRef
.Set(nCol1
, nRow1
+ 1, nTab
, false, true, true);
374 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
375 aFormulaBuf
.append(aSep
);
376 aFormulaBuf
.append(rParam
.aRefRowCell
.GetRefString(pDoc
, nTab
));
377 aFormulaBuf
.append(aSep
);
378 aRef
.Set(nCol1
+ 1, nRow1
, nTab
, true, false, true);
379 aFormulaBuf
.append(aRef
.GetRefString(pDoc
, nTab
));
384 aFormulaBuf
.append(ScCompiler::GetNativeSymbol(ocClose
));
386 ScFormulaCell
aRefCell(
387 pDoc
, ScAddress(nCol1
, nRow1
, nTab
), aFormulaBuf
.makeStringAndClear(),
388 formula::FormulaGrammar::GRAM_NATIVE
, MM_NONE
);
390 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
392 sc::ColumnBlockPosition
* pBlockPos
=
393 mpImpl
->maBlockPosSet
.getBlockPosition(nTab
, nCol
);
396 // Something went horribly wrong.
399 sc::CellStoreType
& rColCells
= pTab
->aCol
[nCol
].maCells
;
401 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
403 ScAddress
aPos(nCol
, nRow
, nTab
);
404 ScFormulaCell
* pCell
= new ScFormulaCell(aRefCell
, *pDoc
, aPos
);
405 pBlockPos
->miCellPos
=
406 rColCells
.set(pBlockPos
->miCellPos
, nRow
, pCell
);
413 class CellStoreInitializer
415 // The pimpl pattern here is intentional.
417 // The problem with having the attributes in CellStoreInitializer
418 // directly is that, as a functor, it might be copied around. In
419 // that case miPos in _copied_ object points ot maAttrs in the
420 // original object, not in the copy. So later, deep in mdds, we end
421 // up comparing iterators from different sequences.
423 // This could be solved by defining copy constructor and operator=,
424 // but given the limited usage of the class, I think it is simpler
425 // to let copies share the state.
428 sc::CellTextAttrStoreType maAttrs
;
429 sc::CellTextAttrStoreType::iterator miPos
;
430 sal_uInt16 mnScriptNumeric
;
432 Impl(const sal_uInt32 nMaxRowCount
, const sal_uInt16 nScriptNumeric
)
433 : maAttrs(nMaxRowCount
), miPos(maAttrs
.begin()), mnScriptNumeric(nScriptNumeric
)
438 sc::StartListeningContext
& mrListenCxt
;
441 CellStoreInitializer(ScDocument
& rDoc
, sc::StartListeningContext
& rCxt
, sal_uInt16 nScriptNumeric
) :
444 mpImpl(new Impl(MAXROWCOUNT
, nScriptNumeric
))
447 boost::shared_ptr
<Impl
> mpImpl
;
449 void operator() (const sc::CellStoreType::value_type
& node
)
451 if (node
.type
== sc::element_type_empty
)
454 // Fill with default values for non-empty cell segments.
455 sc::CellTextAttr aDefault
;
456 if (node
.type
== sc::element_type_numeric
)
457 aDefault
.mnScriptType
= mpImpl
->mnScriptNumeric
;
458 std::vector
<sc::CellTextAttr
> aDefaults(node
.size
, aDefault
);
459 mpImpl
->miPos
= mpImpl
->maAttrs
.set(mpImpl
->miPos
, node
.position
, aDefaults
.begin(), aDefaults
.end());
461 if (node
.type
== sc::element_type_formula
)
463 // Have all formula cells start listening to the document.
464 sc::formula_block::iterator it
= sc::formula_block::begin(*node
.data
);
465 sc::formula_block::iterator itEnd
= sc::formula_block::end(*node
.data
);
466 for (; it
!= itEnd
; ++it
)
468 ScFormulaCell
& rFC
= **it
;
469 rFC
.StartListeningTo(mrListenCxt
);
474 void swap(sc::CellTextAttrStoreType
& rAttrs
)
476 mpImpl
->maAttrs
.swap(rAttrs
);
482 void ScDocumentImport::finalize()
484 // Populate the text width and script type arrays in all columns. Also
485 // activate all formula cells.
486 ScDocument::TableContainer::iterator itTab
= mpImpl
->mrDoc
.maTabs
.begin(), itTabEnd
= mpImpl
->mrDoc
.maTabs
.end();
487 for (; itTab
!= itTabEnd
; ++itTab
)
492 ScTable
& rTab
= **itTab
;
493 ScColumn
* pCol
= &rTab
.aCol
[0];
494 ScColumn
* pColEnd
= pCol
+ static_cast<size_t>(MAXCOLCOUNT
);
495 for (; pCol
!= pColEnd
; ++pCol
)
500 void ScDocumentImport::initColumn(ScColumn
& rCol
)
502 CellStoreInitializer
aFunc(mpImpl
->mrDoc
, mpImpl
->maListenCxt
, mpImpl
->mnDefaultScriptNumeric
);
503 std::for_each(rCol
.maCells
.begin(), rCol
.maCells
.end(), aFunc
);
504 aFunc
.swap(rCol
.maCellTextAttrs
);
505 rCol
.RegroupFormulaCells();
506 rCol
.CellStorageModified();
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */