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