1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
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>
19
20 #include <svl/intitem.hxx>
21 #include <formula/errorcodes.hxx>
22 #include <refdata.hxx>
23
24 namespace sc {
25
ClipContextBase(ScDocument & rDoc)26 ClipContextBase::ClipContextBase(ScDocument& rDoc) :
27 mpSet(new ColumnBlockPositionSet(rDoc)) {}
28
~ClipContextBase()29 ClipContextBase::~ClipContextBase() {}
30
getBlockPosition(SCTAB nTab,SCCOL nCol)31 ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol)
32 {
33 return mpSet->getBlockPosition(nTab, nCol);
34 }
35
CopyFromClipContext(ScDocument & rDoc,ScDocument * pRefUndoDoc,ScDocument * pClipDoc,InsertDeleteFlags nInsertFlag,bool bAsLink,bool bSkipAttrForEmptyCells)36 CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
37 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, InsertDeleteFlags nInsertFlag,
38 bool bAsLink, bool bSkipAttrForEmptyCells) :
39 ClipContextBase(rDoc),
40 mnDestCol1(-1), mnDestCol2(-1),
41 mnDestRow1(-1), mnDestRow2(-1),
42 mnTabStart(-1), mnTabEnd(-1),
43 mrDestDoc(rDoc),
44 mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc),
45 mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE),
46 mpCondFormatList(nullptr),
47 mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells),
48 mbCloneNotes (mnInsertFlag & (InsertDeleteFlags::NOTE|InsertDeleteFlags::ADDNOTES)),
49 mbTableProtected(false)
50 {
51 }
52
~CopyFromClipContext()53 CopyFromClipContext::~CopyFromClipContext()
54 {
55 }
56
setTabRange(SCTAB nStart,SCTAB nEnd)57 void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd)
58 {
59 mnTabStart = nStart;
60 mnTabEnd = nEnd;
61 }
62
getTabStart() const63 SCTAB CopyFromClipContext::getTabStart() const
64 {
65 return mnTabStart;
66 }
67
getTabEnd() const68 SCTAB CopyFromClipContext::getTabEnd() const
69 {
70 return mnTabEnd;
71 }
72
setDestRange(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)73 void CopyFromClipContext::setDestRange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
74 {
75 mnDestCol1 = nCol1;
76 mnDestRow1 = nRow1;
77 mnDestCol2 = nCol2;
78 mnDestRow2 = nRow2;
79 }
80
getDestRange() const81 CopyFromClipContext::Range CopyFromClipContext::getDestRange() const
82 {
83 Range aRet;
84 aRet.mnCol1 = mnDestCol1;
85 aRet.mnCol2 = mnDestCol2;
86 aRet.mnRow1 = mnDestRow1;
87 aRet.mnRow2 = mnDestRow2;
88 return aRet;
89 }
90
getUndoDoc()91 ScDocument* CopyFromClipContext::getUndoDoc()
92 {
93 return mpRefUndoDoc;
94 }
95
getClipDoc()96 ScDocument* CopyFromClipContext::getClipDoc()
97 {
98 return mpClipDoc;
99 }
100
getInsertFlag() const101 InsertDeleteFlags CopyFromClipContext::getInsertFlag() const
102 {
103 return mnInsertFlag;
104 }
105
setDeleteFlag(InsertDeleteFlags nFlag)106 void CopyFromClipContext::setDeleteFlag( InsertDeleteFlags nFlag )
107 {
108 mnDeleteFlag = nFlag;
109 }
110
getDeleteFlag() const111 InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const
112 {
113 return mnDeleteFlag;
114 }
115
setSingleCellColumnSize(size_t nSize)116 void CopyFromClipContext::setSingleCellColumnSize( size_t nSize )
117 {
118 maSingleCells.resize(nSize);
119 maSingleCellAttrs.resize(nSize);
120 maSinglePatterns.resize(nSize, nullptr);
121 maSingleNotes.resize(nSize, nullptr);
122 }
123
getSingleCell(size_t nColOffset)124 ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset )
125 {
126 assert(nColOffset < maSingleCells.size());
127 return maSingleCells[nColOffset];
128 }
129
getSingleCellAttr(size_t nColOffset)130 sc::CellTextAttr& CopyFromClipContext::getSingleCellAttr( size_t nColOffset )
131 {
132 assert(nColOffset < maSingleCellAttrs.size());
133 return maSingleCellAttrs[nColOffset];
134 }
135
setSingleCell(const ScAddress & rSrcPos,const ScColumn & rSrcCol)136 void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColumn& rSrcCol )
137 {
138 SCCOL nColOffset = rSrcPos.Col() - mpClipDoc->GetClipParam().getWholeRange().aStart.Col();
139 ScCellValue& rSrcCell = getSingleCell(nColOffset);
140
141 const sc::CellTextAttr* pAttr = rSrcCol.GetCellTextAttr(rSrcPos.Row());
142
143 if (pAttr)
144 {
145 sc::CellTextAttr& rAttr = getSingleCellAttr(nColOffset);
146 rAttr = *pAttr;
147 }
148
149 if (mbAsLink)
150 {
151 ScSingleRefData aRef;
152 aRef.InitAddress(rSrcPos);
153 aRef.SetFlag3D(true);
154
155 ScTokenArray aArr(*mpClipDoc);
156 aArr.AddSingleReference(aRef);
157 rSrcCell.set(new ScFormulaCell(*mpClipDoc, rSrcPos, aArr));
158 return;
159 }
160
161 rSrcCell.assign(*mpClipDoc, rSrcPos);
162
163 // Check the paste flag to see whether we want to paste this cell. If the
164 // flag says we don't want to paste this cell, we'll return with true.
165 InsertDeleteFlags nFlags = getInsertFlag();
166 bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE;
167 bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE;
168 bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE;
169 bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
170 bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
171
172 switch (rSrcCell.meType)
173 {
174 case CELLTYPE_VALUE:
175 {
176 bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric;
177 if (!bPaste)
178 // Don't paste this.
179 rSrcCell.clear();
180 }
181 break;
182 case CELLTYPE_STRING:
183 case CELLTYPE_EDIT:
184 {
185 if (!bString)
186 // Skip pasting.
187 rSrcCell.clear();
188 }
189 break;
190 case CELLTYPE_FORMULA:
191 {
192 if (bBoolean)
193 {
194 // Check if this formula cell is a boolean cell, and if so, go ahead and paste it.
195 const ScTokenArray* pCode = rSrcCell.mpFormula->GetCode();
196 if (pCode && pCode->GetLen() == 1)
197 {
198 const formula::FormulaToken* p = pCode->FirstToken();
199 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
200 // This is a boolean formula. Good.
201 break;
202 }
203 }
204
205 if (bFormula)
206 // Good.
207 break;
208
209 FormulaError nErr = rSrcCell.mpFormula->GetErrCode();
210 if (nErr != FormulaError::NONE)
211 {
212 // error codes are cloned with values
213 if (!bNumeric)
214 // Error code is treated as numeric value. Don't paste it.
215 rSrcCell.clear();
216 else
217 {
218 // Turn this into a formula cell with just the error code.
219 ScFormulaCell* pErrCell = new ScFormulaCell(*mpClipDoc, rSrcPos);
220 pErrCell->SetErrCode(nErr);
221 rSrcCell.set(pErrCell);
222 }
223 }
224 else if (rSrcCell.mpFormula->IsEmptyDisplayedAsString())
225 {
226 // Empty stays empty and doesn't become 0.
227 rSrcCell.clear();
228 }
229 else if (rSrcCell.mpFormula->IsValue())
230 {
231 bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric;
232 if (!bPaste)
233 {
234 // Don't paste this.
235 rSrcCell.clear();
236 break;
237 }
238
239 // Turn this into a numeric cell.
240 rSrcCell.set(rSrcCell.mpFormula->GetValue());
241 }
242 else if (bString)
243 {
244 svl::SharedString aStr = rSrcCell.mpFormula->GetString();
245 if (aStr.isEmpty())
246 {
247 // do not clone empty string
248 rSrcCell.clear();
249 break;
250 }
251
252 // Turn this into a string or edit cell.
253 if (rSrcCell.mpFormula->IsMultilineResult())
254 {
255 // TODO : Add shared string support to the edit engine to
256 // make this process simpler.
257 ScFieldEditEngine& rEngine = mrDestDoc.GetEditEngine();
258 rEngine.SetTextCurrentDefaults(rSrcCell.mpFormula->GetString().getString());
259 std::unique_ptr<EditTextObject> pObj(rEngine.CreateTextObject());
260 pObj->NormalizeString(mrDestDoc.GetSharedStringPool());
261 rSrcCell.set(*pObj);
262 }
263 else
264 rSrcCell.set(rSrcCell.mpFormula->GetString());
265 }
266 else
267 // We don't want to paste this.
268 rSrcCell.clear();
269 }
270 break;
271 case CELLTYPE_NONE:
272 default:
273 // There is nothing to paste.
274 rSrcCell.clear();
275 }
276 }
277
getSingleCellPattern(size_t nColOffset) const278 const ScPatternAttr* CopyFromClipContext::getSingleCellPattern( size_t nColOffset ) const
279 {
280 assert(nColOffset < maSinglePatterns.size());
281 return maSinglePatterns[nColOffset];
282 }
283
setSingleCellPattern(size_t nColOffset,const ScPatternAttr * pAttr)284 void CopyFromClipContext::setSingleCellPattern( size_t nColOffset, const ScPatternAttr* pAttr )
285 {
286 assert(nColOffset < maSinglePatterns.size());
287 maSinglePatterns[nColOffset] = pAttr;
288 }
289
getSingleCellNote(size_t nColOffset) const290 const ScPostIt* CopyFromClipContext::getSingleCellNote( size_t nColOffset ) const
291 {
292 assert(nColOffset < maSingleNotes.size());
293 return maSingleNotes[nColOffset];
294 }
295
setSingleCellNote(size_t nColOffset,const ScPostIt * pNote)296 void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt* pNote )
297 {
298 assert(nColOffset < maSingleNotes.size());
299 maSingleNotes[nColOffset] = pNote;
300 }
301
setCondFormatList(ScConditionalFormatList * pCondFormatList)302 void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList )
303 {
304 mpCondFormatList = pCondFormatList;
305 }
306
getCondFormatList()307 ScConditionalFormatList* CopyFromClipContext::getCondFormatList()
308 {
309 return mpCondFormatList;
310 }
311
setTableProtected(bool b)312 void CopyFromClipContext::setTableProtected( bool b )
313 {
314 mbTableProtected = b;
315 }
316
isTableProtected() const317 bool CopyFromClipContext::isTableProtected() const
318 {
319 return mbTableProtected;
320 }
321
isAsLink() const322 bool CopyFromClipContext::isAsLink() const
323 {
324 return mbAsLink;
325 }
326
isSkipAttrForEmptyCells() const327 bool CopyFromClipContext::isSkipAttrForEmptyCells() const
328 {
329 return mbSkipAttrForEmptyCells;
330 }
331
isCloneNotes() const332 bool CopyFromClipContext::isCloneNotes() const
333 {
334 return mbCloneNotes;
335 }
336
isDateCell(const ScColumn & rCol,SCROW nRow) const337 bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const
338 {
339 sal_uLong nNumIndex = rCol.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
340 SvNumFormatType nType = mpClipDoc->GetFormatTable()->GetType(nNumIndex);
341 return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || (nType == SvNumFormatType::DATETIME);
342 }
343
CopyToClipContext(ScDocument & rDoc,bool bKeepScenarioFlags)344 CopyToClipContext::CopyToClipContext(
345 ScDocument& rDoc, bool bKeepScenarioFlags) :
346 ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags) {}
347
~CopyToClipContext()348 CopyToClipContext::~CopyToClipContext() {}
349
isKeepScenarioFlags() const350 bool CopyToClipContext::isKeepScenarioFlags() const
351 {
352 return mbKeepScenarioFlags;
353 }
354
CopyToDocContext(ScDocument & rDoc)355 CopyToDocContext::CopyToDocContext(ScDocument& rDoc) :
356 ClipContextBase(rDoc), mbStartListening(true) {}
357
~CopyToDocContext()358 CopyToDocContext::~CopyToDocContext() {}
359
setStartListening(bool b)360 void CopyToDocContext::setStartListening( bool b )
361 {
362 mbStartListening = b;
363 }
364
isStartListening() const365 bool CopyToDocContext::isStartListening() const
366 {
367 return mbStartListening;
368 }
369
MixDocContext(ScDocument & rDoc)370 MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
~MixDocContext()371 MixDocContext::~MixDocContext() {}
372
373 }
374
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
376