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