1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 28 29 // INCLUDE --------------------------------------------------------------- 30 31 #include "scitems.hxx" 32 #include <editeng/boxitem.hxx> 33 #include <editeng/bolnitem.hxx> 34 #include <editeng/editdata.hxx> // can be removed if table has a bLayoutRTL flag 35 #include <editeng/shaditem.hxx> 36 37 #include "fillinfo.hxx" 38 #include "document.hxx" 39 #include "cell.hxx" 40 #include "table.hxx" 41 #include "attrib.hxx" 42 #include "attarray.hxx" 43 #include "markarr.hxx" 44 #include "markdata.hxx" 45 #include "patattr.hxx" 46 #include "poolhelp.hxx" 47 #include "docpool.hxx" 48 #include "conditio.hxx" 49 #include "stlpool.hxx" 50 51 // ----------------------------------------------------------------------- 52 53 const sal_uInt16 ROWINFO_MAX = 1024; 54 55 56 enum FillInfoLinePos 57 { 58 FILP_TOP, 59 FILP_BOTTOM, 60 FILP_LEFT, 61 FILP_RIGHT 62 }; 63 64 65 inline const SvxBorderLine* GetNullOrLine( const SvxBoxItem* pBox, FillInfoLinePos eWhich ) 66 { 67 if (pBox) 68 { 69 if (eWhich==FILP_TOP) 70 return pBox->GetTop(); 71 else if (eWhich==FILP_BOTTOM) 72 return pBox->GetBottom(); 73 else if (eWhich==FILP_LEFT) 74 return pBox->GetLeft(); 75 else 76 return pBox->GetRight(); 77 } 78 else 79 return NULL; 80 } 81 82 // aehnlich wie in output.cxx 83 84 void lcl_GetMergeRange( SCsCOL nX, SCsROW nY, SCSIZE nArrY, 85 ScDocument* pDoc, RowInfo* pRowInfo, 86 SCCOL nX1, SCROW nY1, SCCOL /* nX2 */, SCROW /* nY2 */, SCTAB nTab, 87 SCsCOL& rStartX, SCsROW& rStartY, SCsCOL& rEndX, SCsROW& rEndY ) 88 { 89 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1]; 90 91 rStartX = nX; 92 rStartY = nY; 93 sal_Bool bHOver = pInfo->bHOverlapped; 94 sal_Bool bVOver = pInfo->bVOverlapped; 95 SCCOL nLastCol; 96 SCROW nLastRow; 97 98 while (bHOver) // nY konstant 99 { 100 --rStartX; 101 if (rStartX >= (SCsCOL) nX1 && !pDoc->ColHidden(rStartX, nTab, nLastCol)) 102 { 103 bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped; 104 bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped; 105 } 106 else 107 { 108 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( 109 rStartX, rStartY, nTab, ATTR_MERGE_FLAG ))->GetValue(); 110 bHOver = ((nOverlap & SC_MF_HOR) != 0); 111 bVOver = ((nOverlap & SC_MF_VER) != 0); 112 } 113 } 114 115 while (bVOver) 116 { 117 --rStartY; 118 119 if (nArrY>0) 120 --nArrY; // lokale Kopie ! 121 122 if (rStartX >= (SCsCOL) nX1 && rStartY >= (SCsROW) nY1 && 123 !pDoc->ColHidden(rStartX, nTab, nLastCol) && 124 !pDoc->RowHidden(rStartY, nTab, nLastRow) && 125 (SCsROW) pRowInfo[nArrY].nRowNo == rStartY) 126 { 127 bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped; 128 bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped; 129 } 130 else 131 { 132 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( 133 rStartX, rStartY, nTab, ATTR_MERGE_FLAG ))->GetValue(); 134 bHOver = ((nOverlap & SC_MF_HOR) != 0); 135 bVOver = ((nOverlap & SC_MF_VER) != 0); 136 } 137 } 138 139 const ScMergeAttr* pMerge; 140 if (rStartX >= (SCsCOL) nX1 && rStartY >= (SCsROW) nY1 && 141 !pDoc->ColHidden(rStartX, nTab, nLastCol) && 142 !pDoc->RowHidden(rStartY, nTab, nLastRow) && 143 (SCsROW) pRowInfo[nArrY].nRowNo == rStartY) 144 { 145 pMerge = (const ScMergeAttr*) &pRowInfo[nArrY].pCellInfo[rStartX+1].pPatternAttr-> 146 GetItem(ATTR_MERGE); 147 } 148 else 149 pMerge = (const ScMergeAttr*) pDoc->GetAttr(rStartX,rStartY,nTab,ATTR_MERGE); 150 151 rEndX = rStartX + pMerge->GetColMerge() - 1; 152 rEndY = rStartY + pMerge->GetRowMerge() - 1; 153 } 154 155 #define CELLINFO(x,y) pRowInfo[nArrY+y].pCellInfo[nArrX+x] 156 157 void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, 158 SCTAB nTab, double nScaleX, double nScaleY, 159 sal_Bool bPageMode, sal_Bool bFormulaMode, const ScMarkData* pMarkData ) 160 { 161 DBG_ASSERT( pTab[nTab], "Tabelle existiert nicht" ); 162 163 sal_Bool bLayoutRTL = IsLayoutRTL( nTab ); 164 165 ScDocumentPool* pPool = xPoolHelper->GetDocPool(); 166 ScStyleSheetPool* pStlPool = xPoolHelper->GetStylePool(); 167 168 RowInfo* pRowInfo = rTabInfo.mpRowInfo; 169 170 const SvxBrushItem* pDefBackground = 171 (const SvxBrushItem*) &pPool->GetDefaultItem( ATTR_BACKGROUND ); 172 const ScMergeAttr* pDefMerge = 173 (const ScMergeAttr*) &pPool->GetDefaultItem( ATTR_MERGE ); 174 const SvxShadowItem* pDefShadow = 175 (const SvxShadowItem*) &pPool->GetDefaultItem( ATTR_SHADOW ); 176 177 SCROW nThisRow; 178 SCCOL nX; 179 SCROW nY; 180 SCsROW nSignedY; 181 SCCOL nArrX; 182 SCSIZE nArrY; 183 SCSIZE nArrCount; 184 sal_Bool bAnyMerged = sal_False; 185 sal_Bool bAnyShadow = sal_False; 186 sal_Bool bAnyCondition = sal_False; 187 188 sal_Bool bTabProtect = IsTabProtected(nTab); 189 190 // fuer Blockmarken von zusammengefassten Zellen mit 191 // versteckter erster Zeile / Spalte 192 sal_Bool bPaintMarks = sal_False; 193 sal_Bool bSkipMarks = sal_False; 194 SCCOL nBlockStartX = 0, nBlockEndX = 0; 195 SCROW nBlockEndY = 0, nBlockStartY = 0; 196 if (pMarkData && pMarkData->IsMarked()) 197 { 198 ScRange aTmpRange; 199 pMarkData->GetMarkArea(aTmpRange); 200 if ( nTab >= aTmpRange.aStart.Tab() && nTab <= aTmpRange.aEnd.Tab() ) 201 { 202 nBlockStartX = aTmpRange.aStart.Col(); 203 nBlockStartY = aTmpRange.aStart.Row(); 204 nBlockEndX = aTmpRange.aEnd.Col(); 205 nBlockEndY = aTmpRange.aEnd.Row(); 206 ExtendHidden( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY, nTab ); //? noetig ? 207 if (pMarkData->IsMarkNegative()) 208 bSkipMarks = sal_True; 209 else 210 bPaintMarks = sal_True; 211 } 212 } 213 214 // zuerst nur die Eintraege fuer die ganze Spalte 215 216 nArrY=0; 217 SCROW nYExtra = nY2+1; 218 sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight; 219 SCROW nDocHeightEndRow = -1; 220 for (nSignedY=((SCsROW)nY1)-1; nSignedY<=(SCsROW)nYExtra; nSignedY++) 221 { 222 if (nSignedY >= 0) 223 nY = (SCROW) nSignedY; 224 else 225 nY = MAXROW+1; // ungueltig 226 227 if (nY > nDocHeightEndRow) 228 { 229 if (ValidRow(nY)) 230 nDocHeight = GetRowHeight( nY, nTab, NULL, &nDocHeightEndRow ); 231 else 232 nDocHeight = ScGlobal::nStdRowHeight; 233 } 234 235 if ( nArrY==0 || nDocHeight || nY > MAXROW ) 236 { 237 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 238 pThisRowInfo->pCellInfo = NULL; // wird unten belegt 239 240 sal_uInt16 nHeight = (sal_uInt16) ( nDocHeight * nScaleY ); 241 if (!nHeight) 242 nHeight = 1; 243 244 pThisRowInfo->nRowNo = nY; //! Fall < 0 ? 245 pThisRowInfo->nHeight = nHeight; 246 pThisRowInfo->bEmptyBack = sal_True; 247 pThisRowInfo->bEmptyText = sal_True; 248 pThisRowInfo->bChanged = sal_True; 249 pThisRowInfo->bAutoFilter = sal_False; 250 pThisRowInfo->bPushButton = sal_False; 251 pThisRowInfo->nRotMaxCol = SC_ROTMAX_NONE; 252 253 ++nArrY; 254 if (nArrY >= ROWINFO_MAX) 255 { 256 DBG_ERROR("Zu grosser Bereich bei FillInfo" ); 257 nYExtra = nSignedY; // Ende 258 nY2 = nYExtra - 1; // Bereich anpassen 259 } 260 } 261 else 262 if (nSignedY==(SCsROW) nYExtra) // zusaetzliche Zeile verdeckt ? 263 ++nYExtra; 264 } 265 nArrCount = nArrY; // incl. Dummys 266 267 // rotierter Text... 268 269 // Attribut im Dokument ueberhaupt verwendet? 270 sal_Bool bAnyItem = sal_False; 271 sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE ); 272 for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++) 273 if (pPool->GetItem2( ATTR_ROTATE_VALUE, nItem )) 274 { 275 bAnyItem = sal_True; 276 break; 277 } 278 279 SCCOL nRotMax = nX2; 280 if ( bAnyItem && HasAttrib( 0,nY1,nTab, MAXCOL,nY2+1,nTab, 281 HASATTR_ROTATE | HASATTR_CONDITIONAL ) ) 282 { 283 //! Conditionals auch bei HASATTR_ROTATE abfragen ???? 284 285 DBG_ASSERT( nArrCount>2, "nArrCount zu klein" ); 286 // FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-2, nX1, nX2 ); 287 FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-1, nX1, nX2 ); 288 // FindMaxRotCol setzt nRotMaxCol 289 290 for (nArrY=0; nArrY<nArrCount; nArrY++) 291 if (pRowInfo[nArrY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nArrY].nRotMaxCol > nRotMax) 292 nRotMax = pRowInfo[nArrY].nRotMaxCol; 293 } 294 295 // Zell-Infos erst nach dem Test auf gedrehte allozieren 296 // bis nRotMax wegen nRotateDir Flag 297 298 for (nArrY=0; nArrY<nArrCount; nArrY++) 299 { 300 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 301 nY = pThisRowInfo->nRowNo; 302 pThisRowInfo->pCellInfo = new CellInfo[ nRotMax+1+2 ]; // vom Aufrufer zu loeschen ! 303 304 for (nArrX=0; nArrX<=nRotMax+2; nArrX++) // Zell-Infos vorbelegen 305 { 306 if (nArrX>0) 307 nX = nArrX-1; 308 else 309 nX = MAXCOL+1; // ungueltig 310 311 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 312 pInfo->bEmptyCellText = sal_True; 313 pInfo->pCell = NULL; 314 if (bPaintMarks) 315 pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX 316 && nY >= nBlockStartY && nY <= nBlockEndY ); 317 else 318 pInfo->bMarked = sal_False; 319 pInfo->nWidth = 0; 320 321 pInfo->nClipMark = SC_CLIPMARK_NONE; 322 pInfo->bMerged = sal_False; 323 pInfo->bHOverlapped = sal_False; 324 pInfo->bVOverlapped = sal_False; 325 pInfo->bAutoFilter = sal_False; 326 pInfo->bPushButton = sal_False; 327 pInfo->bPopupButton = false; 328 pInfo->bFilterActive = false; 329 pInfo->nRotateDir = SC_ROTDIR_NONE; 330 331 pInfo->bPrinted = sal_False; // view-intern 332 pInfo->bHideGrid = sal_False; // view-intern 333 pInfo->bEditEngine = sal_False; // view-intern 334 335 pInfo->pBackground = NULL; //! weglassen? 336 pInfo->pPatternAttr = NULL; 337 pInfo->pConditionSet= NULL; 338 339 pInfo->pLinesAttr = NULL; 340 pInfo->mpTLBRLine = NULL; 341 pInfo->mpBLTRLine = NULL; 342 343 pInfo->pShadowAttr = pDefShadow; 344 pInfo->pHShadowOrigin = NULL; 345 pInfo->pVShadowOrigin = NULL; 346 } 347 } 348 349 for (nArrX=nX2+3; nArrX<=nRotMax+2; nArrX++) // restliche Breiten eintragen 350 { 351 nX = nArrX-1; 352 if ( ValidCol(nX) ) 353 { 354 if (!ColHidden(nX, nTab)) 355 { 356 sal_uInt16 nThisWidth = (sal_uInt16) (GetColWidth( nX, nTab ) * nScaleX); 357 if (!nThisWidth) 358 nThisWidth = 1; 359 360 pRowInfo[0].pCellInfo[nArrX].nWidth = nThisWidth; 361 } 362 } 363 } 364 365 for (nArrX=0; nArrX<=nX2+2; nArrX++) // links & rechts + 1 366 { 367 nX = (nArrX>0) ? nArrX-1 : MAXCOL+1; // negativ -> ungueltig 368 369 if ( ValidCol(nX) ) 370 { 371 // #i58049#, #i57939# Hidden columns must be skipped here, or their attributes 372 // will disturb the output 373 374 // TODO: Optimize this loop. 375 if (!ColHidden(nX, nTab)) 376 { 377 sal_uInt16 nThisWidth = (sal_uInt16) (GetColWidth( nX, nTab ) * nScaleX); 378 if (!nThisWidth) 379 nThisWidth = 1; 380 381 pRowInfo[0].pCellInfo[nArrX].nWidth = nThisWidth; //! dies sollte reichen 382 383 ScColumn* pThisCol = &pTab[nTab]->aCol[nX]; // Spalten-Daten 384 385 nArrY = 1; 386 SCSIZE nUIndex; 387 bool bHiddenRow = true; 388 SCROW nHiddenEndRow = -1; 389 (void) pThisCol->Search( nY1, nUIndex ); 390 while ( nUIndex < pThisCol->nCount && 391 (nThisRow=pThisCol->pItems[nUIndex].nRow) <= nY2 ) 392 { 393 if (nThisRow > nHiddenEndRow) 394 bHiddenRow = RowHidden( nThisRow, nTab, nHiddenEndRow); 395 if ( !bHiddenRow ) 396 { 397 while ( pRowInfo[nArrY].nRowNo < nThisRow ) 398 ++nArrY; 399 DBG_ASSERT( pRowInfo[nArrY].nRowNo == nThisRow, "Zeile nicht gefunden in FillInfo" ); 400 401 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 402 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 403 pInfo->pCell = pThisCol->pItems[nUIndex].pCell; 404 if (pInfo->pCell->GetCellType() != CELLTYPE_NOTE) 405 { 406 pThisRowInfo->bEmptyText = sal_False; // Zeile nicht leer 407 pInfo->bEmptyCellText = sal_False; // Zelle nicht leer 408 } 409 ++nArrY; 410 } 411 ++nUIndex; 412 } 413 414 if (nX+1 >= nX1) // Attribute/Blockmarken ab nX1-1 415 { 416 ScAttrArray* pThisAttrArr = pThisCol->pAttrArray; // Attribute 417 418 nArrY = 0; 419 const ScPatternAttr* pPattern; 420 SCROW nCurRow=nY1; // einzelne Zeile 421 if (nCurRow>0) 422 --nCurRow; // oben 1 mehr 423 else 424 nArrY = 1; 425 nThisRow=nCurRow; // Ende des Bereichs 426 SCSIZE nIndex; 427 (void) pThisAttrArr->Search( nCurRow, nIndex ); 428 429 430 do 431 { 432 nThisRow=pThisAttrArr->pData[nIndex].nRow; // Ende des Bereichs 433 pPattern=pThisAttrArr->pData[nIndex].pPattern; 434 435 const SvxBrushItem* pBackground = (const SvxBrushItem*) 436 &pPattern->GetItem(ATTR_BACKGROUND); 437 const SvxBoxItem* pLinesAttr = (const SvxBoxItem*) 438 &pPattern->GetItem(ATTR_BORDER); 439 440 const SvxLineItem* pTLBRLine = static_cast< const SvxLineItem* >( 441 &pPattern->GetItem( ATTR_BORDER_TLBR ) ); 442 const SvxLineItem* pBLTRLine = static_cast< const SvxLineItem* >( 443 &pPattern->GetItem( ATTR_BORDER_BLTR ) ); 444 445 const SvxShadowItem* pShadowAttr = (const SvxShadowItem*) 446 &pPattern->GetItem(ATTR_SHADOW); 447 if (pShadowAttr != pDefShadow) 448 bAnyShadow = sal_True; 449 450 const ScMergeAttr* pMergeAttr = (const ScMergeAttr*) 451 &pPattern->GetItem(ATTR_MERGE); 452 sal_Bool bMerged = ( pMergeAttr != pDefMerge && *pMergeAttr != *pDefMerge ); 453 sal_uInt16 nOverlap = ((const ScMergeFlagAttr*) &pPattern->GetItemSet(). 454 Get(ATTR_MERGE_FLAG))->GetValue(); 455 sal_Bool bHOverlapped = ((nOverlap & SC_MF_HOR) != 0); 456 sal_Bool bVOverlapped = ((nOverlap & SC_MF_VER) != 0); 457 sal_Bool bAutoFilter = ((nOverlap & SC_MF_AUTO) != 0); 458 sal_Bool bPushButton = ((nOverlap & SC_MF_BUTTON) != 0); 459 sal_Bool bScenario = ((nOverlap & SC_MF_SCENARIO) != 0); 460 bool bPopupButton = ((nOverlap & SC_MF_BUTTON_POPUP) != 0); 461 bool bFilterActive = ((nOverlap & SC_MF_HIDDEN_MEMBER) != 0); 462 if (bMerged||bHOverlapped||bVOverlapped) 463 bAnyMerged = sal_True; // intern 464 465 sal_Bool bHidden, bHideFormula; 466 if (bTabProtect) 467 { 468 const ScProtectionAttr& rProtAttr = (const ScProtectionAttr&) 469 pPattern->GetItem(ATTR_PROTECTION); 470 bHidden = rProtAttr.GetHideCell(); 471 bHideFormula = rProtAttr.GetHideFormula(); 472 } 473 else 474 bHidden = bHideFormula = sal_False; 475 476 sal_uLong nConditional = ((const SfxUInt32Item&)pPattern-> 477 GetItem(ATTR_CONDITIONAL)).GetValue(); 478 const ScConditionalFormat* pCondForm = NULL; 479 if ( nConditional && pCondFormList ) 480 pCondForm = pCondFormList->GetFormat( nConditional ); 481 482 do 483 { 484 SCROW nLastHiddenRow = -1; 485 bool bRowHidden = RowHidden(nCurRow, nTab, nLastHiddenRow); 486 if ( nArrY==0 || !bRowHidden ) 487 { 488 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 489 if (pBackground != pDefBackground) // Spalten-HG == Standard ? 490 pThisRowInfo->bEmptyBack = sal_False; 491 if (bAutoFilter) 492 pThisRowInfo->bAutoFilter = sal_True; 493 if (bPushButton) 494 pThisRowInfo->bPushButton = sal_True; 495 496 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 497 pInfo->pBackground = pBackground; 498 pInfo->pPatternAttr = pPattern; 499 pInfo->bMerged = bMerged; 500 pInfo->bHOverlapped = bHOverlapped; 501 pInfo->bVOverlapped = bVOverlapped; 502 pInfo->bAutoFilter = bAutoFilter; 503 pInfo->bPushButton = bPushButton; 504 pInfo->bPopupButton = bPopupButton; 505 pInfo->bFilterActive = bFilterActive; 506 pInfo->pLinesAttr = pLinesAttr; 507 pInfo->mpTLBRLine = pTLBRLine; 508 pInfo->mpBLTRLine = pBLTRLine; 509 pInfo->pShadowAttr = pShadowAttr; 510 // nWidth wird nicht mehr einzeln gesetzt 511 512 sal_Bool bEmbed = sal_False; //bIsEmbedded && 513 nTab >= aEmbedRange.aStart.Tab() && 514 nTab <= aEmbedRange.aEnd.Tab() && 515 nX >= aEmbedRange.aStart.Col() && 516 nX <= aEmbedRange.aEnd.Col() && 517 nCurRow >= aEmbedRange.aStart.Row() && 518 nCurRow <= aEmbedRange.aEnd.Row(); 519 520 if (bScenario) 521 { 522 pInfo->pBackground = ScGlobal::GetButtonBrushItem(); 523 pThisRowInfo->bEmptyBack = sal_False; 524 } 525 else if (bEmbed) 526 { 527 pInfo->pBackground = ScGlobal::GetEmbeddedBrushItem(); 528 pThisRowInfo->bEmptyBack = sal_False; 529 } 530 531 if (bHidden || ( bFormulaMode && bHideFormula && pInfo->pCell 532 && pInfo->pCell->GetCellType() 533 == CELLTYPE_FORMULA )) 534 pInfo->bEmptyCellText = sal_True; 535 536 if ( pCondForm ) 537 { 538 String aStyle = pCondForm->GetCellStyle( pInfo->pCell, 539 ScAddress( nX, nCurRow, nTab ) ); 540 if (aStyle.Len()) 541 { 542 SfxStyleSheetBase* pStyleSheet = 543 pStlPool->Find( aStyle, SFX_STYLE_FAMILY_PARA ); 544 if ( pStyleSheet ) 545 { 546 //! Style-Sets cachen !!! 547 pInfo->pConditionSet = &pStyleSheet->GetItemSet(); 548 bAnyCondition = sal_True; 549 } 550 // if style is not there, treat like no condition 551 } 552 } 553 554 ++nArrY; 555 } 556 else if (bRowHidden && nLastHiddenRow >= 0) 557 { 558 nCurRow = nLastHiddenRow; 559 if (nCurRow > nThisRow) 560 nCurRow = nThisRow; 561 } 562 ++nCurRow; 563 } 564 while (nCurRow <= nThisRow && nCurRow <= nYExtra); 565 ++nIndex; 566 } 567 while ( nIndex < pThisAttrArr->nCount && nThisRow < nYExtra ); 568 569 570 if (pMarkData && pMarkData->IsMultiMarked()) 571 { 572 // Blockmarken 573 const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nX; 574 sal_Bool bThisMarked; 575 nArrY = 1; 576 nCurRow = nY1; // einzelne Zeile 577 nThisRow = nY1; // Ende des Bereichs 578 579 if ( pThisMarkArr->Search( nY1, nIndex ) ) 580 { 581 do 582 { 583 nThisRow=pThisMarkArr->pData[nIndex].nRow; // Ende des Bereichs 584 bThisMarked=pThisMarkArr->pData[nIndex].bMarked; 585 586 do 587 { 588 if ( !RowHidden( nCurRow,nTab ) ) 589 { 590 if ( bThisMarked ) 591 { 592 sal_Bool bSkip = bSkipMarks && 593 nX >= nBlockStartX && 594 nX <= nBlockEndX && 595 nCurRow >= nBlockStartY && 596 nCurRow <= nBlockEndY; 597 if (!bSkip) 598 { 599 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 600 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 601 pInfo->bMarked = sal_True; 602 } 603 } 604 ++nArrY; 605 } 606 ++nCurRow; 607 } 608 while (nCurRow <= nThisRow && nCurRow <= nY2); 609 ++nIndex; 610 } 611 while ( nIndex < pThisMarkArr->nCount && nThisRow < nY2 ); 612 } 613 } 614 } 615 else // vordere Spalten 616 { 617 for (nArrY=1; nArrY+1<nArrCount; nArrY++) 618 { 619 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 620 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 621 622 pInfo->nWidth = nThisWidth; //! oder nur 0 abfragen ?? 623 } 624 } 625 } 626 } 627 else 628 pRowInfo[0].pCellInfo[nArrX].nWidth = STD_COL_WIDTH; 629 // STD_COL_WIDTH ganz links und rechts wird fuer DrawExtraShadow gebraucht 630 } 631 632 //------------------------------------------------------------------------- 633 // bedingte Formatierung auswerten 634 635 if (bAnyCondition) 636 { 637 for (nArrY=0; nArrY<nArrCount; nArrY++) 638 { 639 for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr 640 { 641 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nArrX]; 642 const SfxItemSet* pCondSet = pInfo->pConditionSet; 643 if (pCondSet) 644 { 645 const SfxPoolItem* pItem; 646 647 // Hintergrund 648 if ( pCondSet->GetItemState( ATTR_BACKGROUND, sal_True, &pItem ) == SFX_ITEM_SET ) 649 { 650 pInfo->pBackground = (const SvxBrushItem*) pItem; 651 pRowInfo[nArrY].bEmptyBack = sal_False; 652 } 653 654 // Umrandung 655 if ( pCondSet->GetItemState( ATTR_BORDER, sal_True, &pItem ) == SFX_ITEM_SET ) 656 pInfo->pLinesAttr = (const SvxBoxItem*) pItem; 657 658 if ( pCondSet->GetItemState( ATTR_BORDER_TLBR, sal_True, &pItem ) == SFX_ITEM_SET ) 659 pInfo->mpTLBRLine = static_cast< const SvxLineItem* >( pItem ); 660 if ( pCondSet->GetItemState( ATTR_BORDER_BLTR, sal_True, &pItem ) == SFX_ITEM_SET ) 661 pInfo->mpBLTRLine = static_cast< const SvxLineItem* >( pItem ); 662 663 // Schatten 664 if ( pCondSet->GetItemState( ATTR_SHADOW, sal_True, &pItem ) == SFX_ITEM_SET ) 665 { 666 pInfo->pShadowAttr = (const SvxShadowItem*) pItem; 667 bAnyShadow = sal_True; 668 } 669 } 670 } 671 } 672 } 673 674 // bedingte Formatierung Ende 675 //------------------------------------------------------------------------- 676 677 // 678 // Daten von zusammengefassten Zellen anpassen 679 // 680 681 if (bAnyMerged) 682 { 683 for (nArrY=0; nArrY<nArrCount; nArrY++) 684 { 685 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 686 nSignedY = nArrY ? pThisRowInfo->nRowNo : ((SCsROW)nY1)-1; 687 688 for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr 689 { 690 SCsCOL nSignedX = ((SCsCOL) nArrX) - 1; 691 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX]; 692 693 if (pInfo->bMerged || pInfo->bHOverlapped || pInfo->bVOverlapped) 694 { 695 SCsCOL nStartX; 696 SCsROW nStartY; 697 SCsCOL nEndX; 698 SCsROW nEndY; 699 lcl_GetMergeRange( nSignedX,nSignedY, nArrY, this,pRowInfo, nX1,nY1,nX2,nY2,nTab, 700 nStartX,nStartY, nEndX,nEndY ); 701 const ScPatternAttr* pStartPattern = GetPattern( nStartX,nStartY,nTab ); 702 const SfxItemSet* pStartCond = GetCondResult( nStartX,nStartY,nTab ); 703 const SfxPoolItem* pItem; 704 705 // Hintergrund kopieren (oder in output.cxx) 706 707 if ( !pStartCond || pStartCond-> 708 GetItemState(ATTR_BACKGROUND,sal_True,&pItem) != SFX_ITEM_SET ) 709 pItem = &pStartPattern->GetItem(ATTR_BACKGROUND); 710 pInfo->pBackground = (const SvxBrushItem*) pItem; 711 pRowInfo[nArrY].bEmptyBack = sal_False; 712 713 // Schatten 714 715 if ( !pStartCond || pStartCond-> 716 GetItemState(ATTR_SHADOW,sal_True,&pItem) != SFX_ITEM_SET ) 717 pItem = &pStartPattern->GetItem(ATTR_SHADOW); 718 pInfo->pShadowAttr = (const SvxShadowItem*) pItem; 719 if (pInfo->pShadowAttr != pDefShadow) 720 bAnyShadow = sal_True; 721 722 // Blockmarken - wieder mit Original-Merge-Werten 723 724 sal_Bool bCellMarked = sal_False; 725 if (bPaintMarks) 726 bCellMarked = ( nStartX >= (SCsCOL) nBlockStartX 727 && nStartX <= (SCsCOL) nBlockEndX 728 && nStartY >= (SCsROW) nBlockStartY 729 && nStartY <= (SCsROW) nBlockEndY ); 730 if (pMarkData && pMarkData->IsMultiMarked() && !bCellMarked) 731 { 732 const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nStartX; 733 SCSIZE nIndex; 734 if ( pThisMarkArr->Search( nStartY, nIndex ) ) 735 bCellMarked=pThisMarkArr->pData[nIndex].bMarked; 736 } 737 738 pInfo->bMarked = bCellMarked; 739 } 740 } 741 } 742 } 743 744 if (bAnyShadow) // Schatten verteilen 745 { 746 for (nArrY=0; nArrY<nArrCount; nArrY++) 747 { 748 sal_Bool bTop = ( nArrY == 0 ); 749 sal_Bool bBottom = ( nArrY+1 == nArrCount ); 750 751 for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr 752 { 753 sal_Bool bLeft = ( nArrX == nX1 ); 754 sal_Bool bRight = ( nArrX == nX2+2 ); 755 756 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nArrX]; 757 const SvxShadowItem* pThisAttr = pInfo->pShadowAttr; 758 SvxShadowLocation eLoc = pThisAttr ? pThisAttr->GetLocation() : SVX_SHADOW_NONE; 759 if (eLoc != SVX_SHADOW_NONE) 760 { 761 // oder Test auf != eLoc 762 763 SCsCOL nDxPos = 1; 764 SCsCOL nDxNeg = -1; 765 766 while ( nArrX+nDxPos < nX2+2 && pRowInfo[0].pCellInfo[nArrX+nDxPos].nWidth == 0 ) 767 ++nDxPos; 768 while ( nArrX+nDxNeg > nX1 && pRowInfo[0].pCellInfo[nArrX+nDxNeg].nWidth == 0 ) 769 --nDxNeg; 770 771 sal_Bool bLeftDiff = !bLeft && 772 CELLINFO(nDxNeg,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE; 773 sal_Bool bRightDiff = !bRight && 774 CELLINFO(nDxPos,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE; 775 sal_Bool bTopDiff = !bTop && 776 CELLINFO(0,-1).pShadowAttr->GetLocation() == SVX_SHADOW_NONE; 777 sal_Bool bBottomDiff = !bBottom && 778 CELLINFO(0,1).pShadowAttr->GetLocation() == SVX_SHADOW_NONE; 779 780 if ( bLayoutRTL ) 781 { 782 switch (eLoc) 783 { 784 case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break; 785 case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break; 786 case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_TOPLEFT; break; 787 case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break; 788 default: 789 { 790 // added to avoid warnings 791 } 792 } 793 } 794 795 switch (eLoc) 796 { 797 case SVX_SHADOW_BOTTOMRIGHT: 798 if (bBottomDiff) 799 { 800 CELLINFO(0,1).pHShadowOrigin = pThisAttr; 801 CELLINFO(0,1).eHShadowPart = 802 bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ; 803 } 804 if (bRightDiff) 805 { 806 CELLINFO(1,0).pVShadowOrigin = pThisAttr; 807 CELLINFO(1,0).eVShadowPart = 808 bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT; 809 } 810 if (bBottomDiff && bRightDiff) 811 { 812 CELLINFO(1,1).pHShadowOrigin = pThisAttr; 813 CELLINFO(1,1).eHShadowPart = SC_SHADOW_CORNER; 814 } 815 break; 816 817 case SVX_SHADOW_BOTTOMLEFT: 818 if (bBottomDiff) 819 { 820 CELLINFO(0,1).pHShadowOrigin = pThisAttr; 821 CELLINFO(0,1).eHShadowPart = 822 bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ; 823 } 824 if (bLeftDiff) 825 { 826 CELLINFO(-1,0).pVShadowOrigin = pThisAttr; 827 CELLINFO(-1,0).eVShadowPart = 828 bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT; 829 } 830 if (bBottomDiff && bLeftDiff) 831 { 832 CELLINFO(-1,1).pHShadowOrigin = pThisAttr; 833 CELLINFO(-1,1).eHShadowPart = SC_SHADOW_CORNER; 834 } 835 break; 836 837 case SVX_SHADOW_TOPRIGHT: 838 if (bTopDiff) 839 { 840 CELLINFO(0,-1).pHShadowOrigin = pThisAttr; 841 CELLINFO(0,-1).eHShadowPart = 842 bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ; 843 } 844 if (bRightDiff) 845 { 846 CELLINFO(1,0).pVShadowOrigin = pThisAttr; 847 CELLINFO(1,0).eVShadowPart = 848 bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT; 849 } 850 if (bTopDiff && bRightDiff) 851 { 852 CELLINFO(1,-1).pHShadowOrigin = pThisAttr; 853 CELLINFO(1,-1).eHShadowPart = SC_SHADOW_CORNER; 854 } 855 break; 856 857 case SVX_SHADOW_TOPLEFT: 858 if (bTopDiff) 859 { 860 CELLINFO(0,-1).pHShadowOrigin = pThisAttr; 861 CELLINFO(0,-1).eHShadowPart = 862 bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ; 863 } 864 if (bLeftDiff) 865 { 866 CELLINFO(-1,0).pVShadowOrigin = pThisAttr; 867 CELLINFO(-1,0).eVShadowPart = 868 bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT; 869 } 870 if (bTopDiff && bLeftDiff) 871 { 872 CELLINFO(-1,-1).pHShadowOrigin = pThisAttr; 873 CELLINFO(-1,-1).eHShadowPart = SC_SHADOW_CORNER; 874 } 875 break; 876 877 default: 878 DBG_ERROR("falscher Shadow-Enum"); 879 } 880 } 881 } 882 } 883 } 884 885 rTabInfo.mnArrCount = sal::static_int_cast<sal_uInt16>(nArrCount); 886 rTabInfo.mbPageMode = bPageMode; 887 888 // ======================================================================== 889 // *** create the frame border array *** 890 891 // RowInfo structs are filled in the range [ 0 , nArrCount-1 ] 892 // each RowInfo contains CellInfo structs in the range [ nX1-1 , nX2+1 ] 893 894 size_t nColCount = nX2 - nX1 + 3; 895 size_t nRowCount = nArrCount; 896 897 svx::frame::Array& rArray = rTabInfo.maArray; 898 rArray.Initialize( nColCount, nRowCount ); 899 rArray.SetUseDiagDoubleClipping( false ); 900 901 for( size_t nRow = 0; nRow < nRowCount; ++nRow ) 902 { 903 sal_uInt16 nCellInfoY = static_cast< sal_uInt16 >( nRow ); 904 RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ]; 905 906 for( size_t nCol = 0; nCol < nColCount; ++nCol ) 907 { 908 sal_uInt16 nCellInfoX = static_cast< sal_uInt16 >( nCol + nX1 ); 909 const CellInfo& rInfo = rThisRowInfo.pCellInfo[ nCellInfoX ]; 910 911 const SvxBoxItem* pBox = rInfo.pLinesAttr; 912 const SvxLineItem* pTLBR = rInfo.mpTLBRLine; 913 const SvxLineItem* pBLTR = rInfo.mpBLTRLine; 914 915 size_t nFirstCol = nCol; 916 size_t nFirstRow = nRow; 917 918 // *** merged cells *** ------------------------------------------- 919 920 if( !rArray.IsMerged( nCol, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) ) 921 { 922 // *** insert merged range in svx::frame::Array *** 923 924 /* #i69369# top-left cell of a merged range may be located in 925 a hidden column or row. Use lcl_GetMergeRange() to find the 926 complete merged range, then calculate dimensions and 927 document position of the visible range. */ 928 929 // note: document columns are always one less than CellInfoX coords 930 // note: document rows must be looked up in RowInfo structs 931 932 // current column and row in document coordinates 933 SCCOL nCurrDocCol = static_cast< SCCOL >( nCellInfoX - 1 ); 934 SCROW nCurrDocRow = static_cast< SCROW >( (nCellInfoY > 0) ? rThisRowInfo.nRowNo : (nY1 - 1) ); 935 936 // find entire merged range in document, returns signed document coordinates 937 SCsCOL nFirstRealDocColS, nLastRealDocColS; 938 SCsROW nFirstRealDocRowS, nLastRealDocRowS; 939 lcl_GetMergeRange( static_cast< SCsCOL >( nCurrDocCol ), static_cast< SCsROW >( nCurrDocRow ), 940 nCellInfoY, this, pRowInfo, nX1,nY1,nX2,nY2,nTab, 941 nFirstRealDocColS, nFirstRealDocRowS, nLastRealDocColS, nLastRealDocRowS ); 942 943 // *complete* merged range in document coordinates 944 SCCOL nFirstRealDocCol = static_cast< SCCOL >( nFirstRealDocColS ); 945 SCROW nFirstRealDocRow = static_cast< SCROW >( nFirstRealDocRowS ); 946 SCCOL nLastRealDocCol = static_cast< SCCOL >( nLastRealDocColS ); 947 SCROW nLastRealDocRow = static_cast< SCROW >( nLastRealDocRowS ); 948 949 // first visible column (nX1-1 is first processed document column) 950 SCCOL nFirstDocCol = (nX1 > 0) ? ::std::max< SCCOL >( nFirstRealDocCol, nX1 - 1 ) : nFirstRealDocCol; 951 sal_uInt16 nFirstCellInfoX = static_cast< sal_uInt16 >( nFirstDocCol + 1 ); 952 nFirstCol = static_cast< size_t >( nFirstCellInfoX - nX1 ); 953 954 // last visible column (nX2+1 is last processed document column) 955 SCCOL nLastDocCol = (nX2 < MAXCOL) ? ::std::min< SCCOL >( nLastRealDocCol, nX2 + 1 ) : nLastRealDocCol; 956 sal_uInt16 nLastCellInfoX = static_cast< sal_uInt16 >( nLastDocCol + 1 ); 957 size_t nLastCol = static_cast< size_t >( nLastCellInfoX - nX1 ); 958 959 // first visible row 960 sal_uInt16 nFirstCellInfoY = nCellInfoY; 961 while( ((nFirstCellInfoY > 1) && (pRowInfo[ nFirstCellInfoY - 1 ].nRowNo >= nFirstRealDocRow)) || 962 ((nFirstCellInfoY == 1) && (static_cast< SCROW >( nY1 - 1 ) >= nFirstRealDocRow)) ) 963 --nFirstCellInfoY; 964 SCROW nFirstDocRow = (nFirstCellInfoY > 0) ? pRowInfo[ nFirstCellInfoY ].nRowNo : static_cast< SCROW >( nY1 - 1 ); 965 nFirstRow = static_cast< size_t >( nFirstCellInfoY ); 966 967 // last visible row 968 sal_uInt16 nLastCellInfoY = nCellInfoY; 969 while( (sal::static_int_cast<SCSIZE>(nLastCellInfoY + 1) < nArrCount) && 970 (pRowInfo[ nLastCellInfoY + 1 ].nRowNo <= nLastRealDocRow) ) 971 ++nLastCellInfoY; 972 SCROW nLastDocRow = (nLastCellInfoY > 0) ? pRowInfo[ nLastCellInfoY ].nRowNo : static_cast< SCROW >( nY1 - 1 ); 973 size_t nLastRow = static_cast< size_t >( nLastCellInfoY ); 974 975 // insert merged range 976 rArray.SetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow ); 977 978 // *** find additional size not included in svx::frame::Array *** 979 980 // additional space before first column 981 if( nFirstCol == 0 ) 982 { 983 long nSize = 0; 984 for( SCCOL nDocCol = nFirstRealDocCol; nDocCol < nFirstDocCol; ++nDocCol ) 985 nSize += std::max( static_cast< long >( GetColWidth( nDocCol, nTab ) * nScaleX ), 1L ); 986 rArray.SetAddMergedLeftSize( nCol, nRow, nSize ); 987 } 988 // additional space after last column 989 if( nLastCol + 1 == nColCount ) 990 { 991 long nSize = 0; 992 for( SCCOL nDocCol = nLastDocCol + 1; nDocCol <= nLastRealDocCol; ++nDocCol ) 993 nSize += std::max( static_cast< long >( GetColWidth( nDocCol, nTab ) * nScaleX ), 1L ); 994 rArray.SetAddMergedRightSize( nCol, nRow, nSize ); 995 } 996 // additional space above first row 997 if( nFirstRow == 0 ) 998 { 999 long nSize = 0; 1000 for( SCROW nDocRow = nFirstRealDocRow; nDocRow < nFirstDocRow; ++nDocRow ) 1001 nSize += std::max( static_cast< long >( GetRowHeight( nDocRow, nTab ) * nScaleY ), 1L ); 1002 rArray.SetAddMergedTopSize( nCol, nRow, nSize ); 1003 } 1004 // additional space beyond last row 1005 if( nLastRow + 1 == nRowCount ) 1006 { 1007 long nSize = 0; 1008 for( SCROW nDocRow = nLastDocRow + 1; nDocRow <= nLastRealDocRow; ++nDocRow ) 1009 nSize += std::max( static_cast< long >( GetRowHeight( nDocRow, nTab ) * nScaleY ), 1L ); 1010 rArray.SetAddMergedBottomSize( nCol, nRow, nSize ); 1011 } 1012 1013 // *** use line attributes from real origin cell *** 1014 1015 if( (nFirstRealDocCol != nCurrDocCol) || (nFirstRealDocRow != nCurrDocRow) ) 1016 { 1017 if( const ScPatternAttr* pPattern = GetPattern( nFirstRealDocCol, nFirstRealDocRow, nTab ) ) 1018 { 1019 const SfxItemSet* pCond = GetCondResult( nFirstRealDocCol, nFirstRealDocRow, nTab ); 1020 pBox = static_cast< const SvxBoxItem* >( &pPattern->GetItem( ATTR_BORDER, pCond ) ); 1021 pTLBR = static_cast< const SvxLineItem* >( &pPattern->GetItem( ATTR_BORDER_TLBR, pCond ) ); 1022 pBLTR = static_cast< const SvxLineItem* >( &pPattern->GetItem( ATTR_BORDER_BLTR, pCond ) ); 1023 } 1024 else 1025 { 1026 pBox = 0; 1027 pTLBR = pBLTR = 0; 1028 } 1029 } 1030 } 1031 1032 // *** borders *** ------------------------------------------------ 1033 1034 if( pBox ) 1035 { 1036 rArray.SetCellStyleLeft( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetLeft(), nScaleX ) ); 1037 rArray.SetCellStyleRight( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetRight(), nScaleX ) ); 1038 rArray.SetCellStyleTop( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetTop(), nScaleY ) ); 1039 rArray.SetCellStyleBottom( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetBottom(), nScaleY ) ); 1040 } 1041 1042 if( pTLBR ) 1043 rArray.SetCellStyleTLBR( nFirstCol, nFirstRow, svx::frame::Style( pTLBR->GetLine(), nScaleY ) ); 1044 if( rInfo.mpBLTRLine ) 1045 rArray.SetCellStyleBLTR( nFirstCol, nFirstRow, svx::frame::Style( pBLTR->GetLine(), nScaleY ) ); 1046 } 1047 } 1048 1049 /* Mirror the entire frame array. 1050 1st param = Mirror the vertical double line styles as well. 1051 2nd param = Do not swap diagonal lines. 1052 */ 1053 if( bLayoutRTL ) 1054 rArray.MirrorSelfX( true, false ); 1055 } 1056 1057 // ============================================================================ 1058 1059 ScTableInfo::ScTableInfo() : 1060 mpRowInfo( new RowInfo[ ROWINFO_MAX ] ), 1061 mbPageMode( false ) 1062 { 1063 for( sal_uInt16 nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx ) 1064 mpRowInfo[ nIdx ].pCellInfo = 0; 1065 } 1066 1067 ScTableInfo::~ScTableInfo() 1068 { 1069 for( sal_uInt16 nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx ) 1070 delete [] mpRowInfo[ nIdx ].pCellInfo; 1071 delete [] mpRowInfo; 1072 } 1073 1074 // ============================================================================ 1075 1076