Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / documentimport.cxx
blob3ca06c544e62bc7a693c9c7cb4d5852668fdf6c5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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 "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
28 ScDocument& mrDoc;
29 sc::StartListeningContext maListenCxt;
30 sc::ColumnBlockPositionSet maBlockPosSet;
31 sal_uInt16 mnDefaultScriptNumeric;
33 ScDocumentImportImpl(ScDocument& rDoc) :
34 mrDoc(rDoc),
35 maListenCxt(rDoc),
36 maBlockPosSet(rDoc),
37 mnDefaultScriptNumeric(SC_SCRIPTTYPE_UNKNOWN) {}
40 ScDocumentImport::ScDocumentImport(ScDocument& rDoc) : mpImpl(new ScDocumentImportImpl(rDoc)) {}
41 ScDocumentImport::~ScDocumentImport()
43 delete mpImpl;
46 ScDocument& ScDocumentImport::getDoc()
48 return mpImpl->mrDoc;
51 const ScDocument& ScDocumentImport::getDoc() const
53 return mpImpl->mrDoc;
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);
64 if (!pTab)
65 return;
67 pTab->ApplyStyleArea(0, 0, MAXCOL, MAXROW, rStyle);
70 SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
72 SCTAB nTab = -1;
73 if (!mpImpl->mrDoc.GetTable(rName, nTab))
74 return -1;
76 return 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))
88 return false;
90 mpImpl->mrDoc.maTabs.push_back(new ScTable(&mpImpl->mrDoc, nTabCount, rName));
91 return true;
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());
105 if (!pTab)
106 return;
108 sc::ColumnBlockPosition* pBlockPos =
109 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
111 if (!pBlockPos)
112 return;
114 ScCellValue aCell;
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:
122 // string is copied.
123 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.mpString);
124 break;
125 case CELLTYPE_EDIT:
126 // Cell takes the ownership of the text object.
127 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpEditText);
128 aCell.mpEditText = NULL;
129 break;
130 case CELLTYPE_VALUE:
131 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mfValue);
132 break;
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;
137 break;
138 default:
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());
146 if (!pTab)
147 return;
149 sc::ColumnBlockPosition* pBlockPos =
150 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
152 if (!pBlockPos)
153 return;
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());
162 if (!pTab)
163 return;
165 sc::ColumnBlockPosition* pBlockPos =
166 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
168 if (!pBlockPos)
169 return;
171 svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr);
172 if (!aSS.getData())
173 return;
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());
182 if (!pTab)
183 return;
185 sc::ColumnBlockPosition* pBlockPos =
186 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
188 if (!pBlockPos)
189 return;
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());
200 if (!pTab)
201 return;
203 sc::ColumnBlockPosition* pBlockPos =
204 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
206 if (!pBlockPos)
207 return;
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());
217 if (!pTab)
218 return;
220 sc::ColumnBlockPosition* pBlockPos =
221 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
223 if (!pBlockPos)
224 return;
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());
234 if (!pTab)
235 return;
237 sc::ColumnBlockPosition* pBlockPos =
238 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
240 if (!pBlockPos)
241 return;
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());
254 if (!pTab)
255 return;
257 sc::ColumnBlockPosition* pBlockPos =
258 mpImpl->maBlockPosSet.getBlockPosition(rBasePos.Tab(), rBasePos.Col());
260 if (!pBlockPos)
261 return;
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.
290 aPos.SetRow(nRow);
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);
303 if (!pBlockPos)
304 return;
306 sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
308 aPos.SetCol(nCol);
309 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
311 aPos.SetRow(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);
331 if (!pTab)
332 return;
334 ScDocument* pDoc = &mpImpl->mrDoc;
335 ScRefAddress aRef;
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));
350 nCol1++;
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));
363 ++nRow1;
364 nRow2 = std::min(
365 nRow2, rParam.aRefFormulaEnd.Row() - rParam.aRefFormulaCell.Row() + nRow1 + 1);
367 else // both
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));
380 ++nCol1;
381 ++nRow1;
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);
395 if (!pBlockPos)
396 // Something went horribly wrong.
397 return;
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);
411 namespace {
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.
426 struct Impl
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)
437 ScDocument& mrDoc;
438 sc::StartListeningContext& mrListenCxt;
440 public:
441 CellStoreInitializer(ScDocument& rDoc, sc::StartListeningContext& rCxt, sal_uInt16 nScriptNumeric) :
442 mrDoc(rDoc),
443 mrListenCxt(rCxt),
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)
452 return;
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)
489 if (!*itTab)
490 continue;
492 ScTable& rTab = **itTab;
493 ScColumn* pCol = &rTab.aCol[0];
494 ScColumn* pColEnd = pCol + static_cast<size_t>(MAXCOLCOUNT);
495 for (; pCol != pColEnd; ++pCol)
496 initColumn(*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: */