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
