Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / source / core / data / clipcontext.cxx
blobfc6f136d0372d9d6a7546d94b1e371d3cc1942c5
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 <memory>
11 #include <clipcontext.hxx>
12 #include <document.hxx>
13 #include <mtvelements.hxx>
14 #include <column.hxx>
15 #include <scitems.hxx>
16 #include <tokenarray.hxx>
17 #include <editutil.hxx>
18 #include <clipparam.hxx>
20 #include <svl/intitem.hxx>
21 #include <svl/numformat.hxx>
22 #include <formula/errorcodes.hxx>
23 #include <refdata.hxx>
24 #include <listenercontext.hxx>
26 namespace sc {
28 ClipContextBase::ClipContextBase(ScDocument& rDoc) :
29 mpSet(new ColumnBlockPositionSet(rDoc)) {}
31 ClipContextBase::~ClipContextBase() {}
33 ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol)
35 return mpSet->getBlockPosition(nTab, nCol);
38 CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
39 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, InsertDeleteFlags nInsertFlag,
40 bool bAsLink, bool bSkipEmptyCells) :
41 ClipContextBase(rDoc),
42 mnDestCol1(-1), mnDestCol2(-1),
43 mnDestRow1(-1), mnDestRow2(-1),
44 mnTabStart(-1), mnTabEnd(-1),
45 mrDestDoc(rDoc),
46 mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc),
47 mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE),
48 mpCondFormatList(nullptr),
49 mbAsLink(bAsLink), mbSkipEmptyCells(bSkipEmptyCells),
50 mbTableProtected(false)
54 CopyFromClipContext::~CopyFromClipContext()
58 void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd)
60 mnTabStart = nStart;
61 mnTabEnd = nEnd;
64 SCTAB CopyFromClipContext::getTabStart() const
66 return mnTabStart;
69 SCTAB CopyFromClipContext::getTabEnd() const
71 return mnTabEnd;
74 void CopyFromClipContext::setDestRange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
76 mnDestCol1 = nCol1;
77 mnDestRow1 = nRow1;
78 mnDestCol2 = nCol2;
79 mnDestRow2 = nRow2;
82 CopyFromClipContext::Range CopyFromClipContext::getDestRange() const
84 Range aRet;
85 aRet.mnCol1 = mnDestCol1;
86 aRet.mnCol2 = mnDestCol2;
87 aRet.mnRow1 = mnDestRow1;
88 aRet.mnRow2 = mnDestRow2;
89 return aRet;
92 ScDocument* CopyFromClipContext::getUndoDoc()
94 return mpRefUndoDoc;
97 ScDocument* CopyFromClipContext::getClipDoc()
99 return mpClipDoc;
102 InsertDeleteFlags CopyFromClipContext::getInsertFlag() const
104 return mnInsertFlag;
107 void CopyFromClipContext::setDeleteFlag( InsertDeleteFlags nFlag )
109 mnDeleteFlag = nFlag;
112 InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const
114 return mnDeleteFlag;
117 void CopyFromClipContext::setListeningFormulaSpans(
118 SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
120 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
121 maListeningFormulaSpans.set(mrDestDoc, nTab, nCol, nRow1, nRow2, true);
124 namespace {
126 class StartListeningAction : public sc::ColumnSpanSet::Action
128 ScDocument& mrDestDoc;
129 sc::StartListeningContext& mrStartCxt;
130 sc::EndListeningContext& mrEndCxt;
132 public:
133 StartListeningAction( ScDocument& rDestDoc, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
134 mrDestDoc(rDestDoc), mrStartCxt(rStartCxt), mrEndCxt(rEndCxt)
138 virtual void execute( const ScAddress& rPos, SCROW nLength, bool bVal ) override
140 if (!bVal)
141 return;
143 SCROW nRow1 = rPos.Row();
144 SCROW nRow2 = nRow1 + nLength - 1;
146 mrDestDoc.StartListeningFromClip(
147 mrStartCxt, mrEndCxt, rPos.Tab(), rPos.Col(), nRow1, rPos.Col(), nRow2);
153 void CopyFromClipContext::startListeningFormulas()
155 auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(mrDestDoc);
156 sc::StartListeningContext aStartCxt(mrDestDoc, pSet);
157 sc::EndListeningContext aEndCxt(mrDestDoc, pSet, nullptr);
159 StartListeningAction aAction(mrDestDoc, aStartCxt, aEndCxt);
160 maListeningFormulaSpans.executeAction(mrDestDoc, aAction);
163 void CopyFromClipContext::setSingleCellColumnSize( size_t nSize )
165 maSingleCells.resize(nSize);
166 maSingleCellAttrs.resize(nSize);
167 maSinglePatterns.resize(nSize, nullptr);
168 maSingleNotes.resize(nSize, nullptr);
169 maSingleSparkline.resize(nSize);
172 ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset )
174 assert(nColOffset < maSingleCells.size());
175 return maSingleCells[nColOffset];
178 sc::CellTextAttr& CopyFromClipContext::getSingleCellAttr( size_t nColOffset )
180 assert(nColOffset < maSingleCellAttrs.size());
181 return maSingleCellAttrs[nColOffset];
184 void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColumn& rSrcCol )
186 SCCOL nColOffset = rSrcPos.Col() - mpClipDoc->GetClipParam().getWholeRange().aStart.Col();
187 ScCellValue& rSrcCell = getSingleCell(nColOffset);
189 const sc::CellTextAttr* pAttr = rSrcCol.GetCellTextAttr(rSrcPos.Row());
191 if (pAttr)
193 sc::CellTextAttr& rAttr = getSingleCellAttr(nColOffset);
194 rAttr = *pAttr;
197 if (mbAsLink)
199 ScSingleRefData aRef;
200 aRef.InitAddress(rSrcPos);
201 aRef.SetFlag3D(true);
203 ScTokenArray aArr(*mpClipDoc);
204 aArr.AddSingleReference(aRef);
205 rSrcCell.set(new ScFormulaCell(*mpClipDoc, rSrcPos, aArr));
206 return;
209 rSrcCell.assign(*mpClipDoc, rSrcPos);
211 // Check the paste flag to see whether we want to paste this cell. If the
212 // flag says we don't want to paste this cell, we'll return with true.
213 InsertDeleteFlags nFlags = getInsertFlag();
214 bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE;
215 bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE;
216 bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE;
217 bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
218 bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
220 switch (rSrcCell.getType())
222 case CELLTYPE_VALUE:
224 bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric;
225 if (!bPaste)
226 // Don't paste this.
227 rSrcCell.clear();
229 break;
230 case CELLTYPE_STRING:
231 case CELLTYPE_EDIT:
233 if (!bString)
234 // Skip pasting.
235 rSrcCell.clear();
237 break;
238 case CELLTYPE_FORMULA:
240 if (bBoolean)
242 // Check if this formula cell is a boolean cell, and if so, go ahead and paste it.
243 const ScTokenArray* pCode = rSrcCell.getFormula()->GetCode();
244 if (pCode && pCode->GetLen() == 1)
246 const formula::FormulaToken* p = pCode->FirstToken();
247 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
248 // This is a boolean formula. Good.
249 break;
253 if (bFormula)
254 // Good.
255 break;
257 FormulaError nErr = rSrcCell.getFormula()->GetErrCode();
258 if (nErr != FormulaError::NONE)
260 // error codes are cloned with values
261 if (!bNumeric)
262 // Error code is treated as numeric value. Don't paste it.
263 rSrcCell.clear();
264 else
266 // Turn this into a formula cell with just the error code.
267 ScFormulaCell* pErrCell = new ScFormulaCell(*mpClipDoc, rSrcPos);
268 pErrCell->SetErrCode(nErr);
269 rSrcCell.set(pErrCell);
272 else if (rSrcCell.getFormula()->IsEmptyDisplayedAsString())
274 // Empty stays empty and doesn't become 0.
275 rSrcCell.clear();
277 else if (rSrcCell.getFormula()->IsValue())
279 bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric;
280 if (!bPaste)
282 // Don't paste this.
283 rSrcCell.clear();
284 break;
287 // Turn this into a numeric cell.
288 rSrcCell.set(rSrcCell.getFormula()->GetValue());
290 else if (bString)
292 svl::SharedString aStr = rSrcCell.getFormula()->GetString();
293 if (aStr.isEmpty())
295 // do not clone empty string
296 rSrcCell.clear();
297 break;
300 // Turn this into a string or edit cell.
301 if (rSrcCell.getFormula()->IsMultilineResult())
303 std::unique_ptr<EditTextObject> pObj(mrDestDoc.CreateSharedStringTextObject(
304 rSrcCell.getFormula()->GetString()));
305 rSrcCell.set(*pObj);
307 else
308 rSrcCell.set(rSrcCell.getFormula()->GetString());
310 else
311 // We don't want to paste this.
312 rSrcCell.clear();
314 break;
315 case CELLTYPE_NONE:
316 default:
317 // There is nothing to paste.
318 rSrcCell.clear();
322 const ScPatternAttr* CopyFromClipContext::getSingleCellPattern( size_t nColOffset ) const
324 assert(nColOffset < maSinglePatterns.size());
325 return maSinglePatterns[nColOffset];
328 void CopyFromClipContext::setSingleCellPattern( size_t nColOffset, const ScPatternAttr* pAttr )
330 assert(nColOffset < maSinglePatterns.size());
331 maSinglePatterns[nColOffset] = pAttr;
334 const ScPostIt* CopyFromClipContext::getSingleCellNote( size_t nColOffset ) const
336 assert(nColOffset < maSingleNotes.size());
337 return maSingleNotes[nColOffset];
340 void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt* pNote )
342 assert(nColOffset < maSingleNotes.size());
343 maSingleNotes[nColOffset] = pNote;
346 std::shared_ptr<sc::Sparkline> const& CopyFromClipContext::getSingleSparkline(size_t nColOffset) const
348 assert(nColOffset < maSingleSparkline.size());
349 return maSingleSparkline[nColOffset];
352 void CopyFromClipContext::setSingleSparkline(size_t nColOffset, std::shared_ptr<sc::Sparkline> const& pSparkline)
354 assert(nColOffset < maSingleSparkline.size());
355 maSingleSparkline[nColOffset] = pSparkline;
358 void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList )
360 mpCondFormatList = pCondFormatList;
363 ScConditionalFormatList* CopyFromClipContext::getCondFormatList()
365 return mpCondFormatList;
368 void CopyFromClipContext::setTableProtected( bool b )
370 mbTableProtected = b;
373 bool CopyFromClipContext::isTableProtected() const
375 return mbTableProtected;
378 bool CopyFromClipContext::isAsLink() const
380 return mbAsLink;
383 bool CopyFromClipContext::isSkipEmptyCells() const
385 return mbSkipEmptyCells;
388 bool CopyFromClipContext::isCloneNotes() const
390 return bool(mnInsertFlag & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES));
393 bool CopyFromClipContext::isCloneSparklines() const
395 return bool(mnInsertFlag & InsertDeleteFlags::SPARKLINES);
398 bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const
400 sal_uInt32 nNumIndex = rCol.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
401 SvNumFormatType nType = mpClipDoc->GetFormatTable()->GetType(nNumIndex);
402 return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || (nType == SvNumFormatType::DATETIME);
405 CopyToClipContext::CopyToClipContext(
406 ScDocument& rDoc, bool bKeepScenarioFlags, bool bCopyChartRanges) :
407 ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags), mbCopyChartRanges(bCopyChartRanges) {}
409 CopyToClipContext::~CopyToClipContext() {}
411 bool CopyToClipContext::isKeepScenarioFlags() const
413 return mbKeepScenarioFlags;
416 CopyToDocContext::CopyToDocContext(ScDocument& rDoc) :
417 ClipContextBase(rDoc), mbStartListening(true) {}
419 CopyToDocContext::~CopyToDocContext() {}
421 void CopyToDocContext::setStartListening( bool b )
423 mbStartListening = b;
426 bool CopyToDocContext::isStartListening() const
428 return mbStartListening;
431 MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
432 MixDocContext::~MixDocContext() {}
436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */