fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / documentimport.cxx
blob18346fae2a528fc5da6734bc37b12eebec24015e
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"
23 #include <attarray.hxx>
24 #include <sharedformula.hxx>
26 #include <svl/sharedstringpool.hxx>
27 #include <svl/languageoptions.hxx>
29 #include <vector>
31 namespace {
33 struct ColAttr
35 bool mbLatinNumFmtOnly;
37 ColAttr() : mbLatinNumFmtOnly(false) {}
40 struct TabAttr
42 std::vector<ColAttr> maCols;
45 typedef std::vector<TabAttr> TabAttrsType;
49 struct ScDocumentImportImpl
51 ScDocument& mrDoc;
52 sc::StartListeningContext maListenCxt;
53 sc::ColumnBlockPositionSet maBlockPosSet;
54 SvtScriptType mnDefaultScriptNumeric;
56 TabAttrsType maTabAttrs;
58 ScDocumentImportImpl(ScDocument& rDoc) :
59 mrDoc(rDoc),
60 maListenCxt(rDoc),
61 maBlockPosSet(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))
67 return NULL;
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()
85 delete mpImpl;
88 ScDocument& ScDocumentImport::getDoc()
90 return mpImpl->mrDoc;
93 const ScDocument& ScDocumentImport::getDoc() const
95 return mpImpl->mrDoc;
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);
106 if (!pTab)
107 return;
109 pTab->ApplyStyleArea(0, 0, MAXCOL, MAXROW, rStyle);
112 SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
114 SCTAB nTab = -1;
115 if (!mpImpl->mrDoc.GetTable(rName, nTab))
116 return -1;
118 return 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))
130 return false;
132 mpImpl->mrDoc.maTabs.push_back(new ScTable(&mpImpl->mrDoc, nTabCount, rName));
133 return true;
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());
147 if (!pTab)
148 return;
150 sc::ColumnBlockPosition* pBlockPos =
151 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
153 if (!pBlockPos)
154 return;
156 ScCellValue aCell;
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:
164 // string is copied.
165 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.mpString);
166 break;
167 case CELLTYPE_EDIT:
168 // Cell takes the ownership of the text object.
169 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpEditText);
170 aCell.mpEditText = NULL;
171 break;
172 case CELLTYPE_VALUE:
173 pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mfValue);
174 break;
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;
179 break;
180 default:
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());
188 if (!pTab)
189 return;
191 sc::ColumnBlockPosition* pBlockPos =
192 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
194 if (!pBlockPos)
195 return;
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());
204 if (!pTab)
205 return;
207 sc::ColumnBlockPosition* pBlockPos =
208 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
210 if (!pBlockPos)
211 return;
213 svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr);
214 if (!aSS.getData())
215 return;
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());
224 if (!pTab)
225 return;
227 sc::ColumnBlockPosition* pBlockPos =
228 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
230 if (!pBlockPos)
231 return;
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());
242 if (!pTab)
243 return;
245 sc::ColumnBlockPosition* pBlockPos =
246 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
248 if (!pBlockPos)
249 return;
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());
259 if (!pTab)
260 return;
262 sc::ColumnBlockPosition* pBlockPos =
263 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
265 if (!pBlockPos)
266 return;
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());
276 if (!pTab)
277 return;
279 sc::ColumnBlockPosition* pBlockPos =
280 mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
282 if (!pBlockPos)
283 return;
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());
296 if (!pTab)
297 return;
299 sc::ColumnBlockPosition* pBlockPos =
300 mpImpl->maBlockPosSet.getBlockPosition(rBasePos.Tab(), rBasePos.Col());
302 if (!pBlockPos)
303 return;
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.
332 aPos.SetRow(nRow);
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);
345 if (!pBlockPos)
346 return;
348 sc::CellStoreType& rColCells = pTab->aCol[nCol].maCells;
350 aPos.SetCol(nCol);
351 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
353 aPos.SetRow(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);
373 if (!pTab)
374 return;
376 ScDocument* pDoc = &mpImpl->mrDoc;
377 ScRefAddress aRef;
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));
393 nCol1++;
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));
406 ++nRow1;
407 nRow2 = std::min(
408 nRow2, rParam.aRefFormulaEnd.Row() - rParam.aRefFormulaCell.Row() + nRow1 + 1);
410 else // both
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));
423 ++nCol1;
424 ++nRow1;
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);
438 if (!pBlockPos)
439 // Something went horribly wrong.
440 return;
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);
457 if (!pTab)
458 return;
460 ScColumn* pCol = pTab->FetchColumn(nCol);
461 if (!pCol)
462 return;
464 ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
465 if (pColAttr)
466 pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly;
468 pCol->pAttrArray->SetAttrEntries(rAttrs.mpData, rAttrs.mnSize);
471 namespace {
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.
486 struct Impl
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;
498 SCTAB mnTab;
499 SCCOL mnCol;
501 public:
502 CellStoreInitializer( ScDocumentImportImpl& rDocImpl, SCTAB nTab, SCCOL nCol ) :
503 mrDocImpl(rDocImpl),
504 mnTab(nTab),
505 mnCol(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)
514 return;
516 // Fill with default values for non-empty cell segments.
517 sc::CellTextAttr aDefault;
518 switch (node.type)
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;
527 break;
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())
543 bNumResOnly = false;
544 break;
548 if (bNumResOnly)
549 aDefault.mnScriptType = SvtScriptType::LATIN;
552 break;
553 default:
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.
574 else
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)
595 if (!*itTab)
596 continue;
598 ScTable& rTab = **itTab;
599 ScColumn* pCol = &rTab.aCol[0];
600 ScColumn* pColEnd = pCol + static_cast<size_t>(MAXCOLCOUNT);
601 for (; pCol != pColEnd; ++pCol)
602 initColumn(*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: */