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 <svl/intitem.hxx> 33 #include <svl/zforlist.hxx> 34 #include <float.h> // DBL_MIN 35 36 #include "chartarr.hxx" 37 #include "document.hxx" 38 #include "rechead.hxx" 39 #include "globstr.hrc" 40 #include "cell.hxx" 41 #include "docoptio.hxx" 42 43 #include <vector> 44 45 using ::std::vector; 46 47 // ----------------------------------------------------------------------- 48 49 ScMemChart::ScMemChart(short nCols, short nRows) 50 { 51 nRowCnt = nRows; 52 nColCnt = nCols; 53 pData = new double[nColCnt * nRowCnt]; 54 55 if (pData) 56 { 57 double *pFill = pData; 58 59 for (short i = 0; i < nColCnt; i++) 60 for (short j = 0; j < nRowCnt; j++) 61 *(pFill ++) = 0.0; 62 } 63 64 pColText = new String[nColCnt]; 65 pRowText = new String[nRowCnt]; 66 } 67 68 ScMemChart::~ScMemChart() 69 { 70 delete[] pRowText; 71 delete[] pColText; 72 delete[] pData; 73 } 74 75 // ----------------------------------------------------------------------- 76 77 ScChartArray::ScChartArray( ScDocument* pDoc, SCTAB nTab, 78 SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP, 79 const String& rChartName ) : 80 aName( rChartName ), 81 pDocument( pDoc ), 82 aPositioner(pDoc, nTab, nStartColP, nStartRowP, nEndColP, nEndRowP), 83 bValid( sal_True ) 84 { 85 } 86 87 ScChartArray::ScChartArray( ScDocument* pDoc, const ScRangeListRef& rRangeList, 88 const String& rChartName ) : 89 aName( rChartName ), 90 pDocument( pDoc ), 91 aPositioner(pDoc, rRangeList), 92 bValid( sal_True ) 93 { 94 } 95 96 ScChartArray::ScChartArray( const ScChartArray& rArr ) : 97 ScDataObject(), 98 aName(rArr.aName), 99 pDocument(rArr.pDocument), 100 aPositioner(rArr.aPositioner), 101 bValid(rArr.bValid) 102 { 103 } 104 105 ScChartArray::~ScChartArray() 106 { 107 } 108 109 ScDataObject* ScChartArray::Clone() const 110 { 111 return new ScChartArray(*this); 112 } 113 114 sal_Bool ScChartArray::operator==(const ScChartArray& rCmp) const 115 { 116 return aPositioner == rCmp.aPositioner 117 && aName == rCmp.aName; 118 } 119 120 #ifdef _MSC_VER 121 #pragma optimize("",off) 122 #endif 123 124 ScMemChart* ScChartArray::CreateMemChart() 125 { 126 ScRangeListRef aRangeListRef(GetRangeList()); 127 sal_uLong nCount = aRangeListRef->Count(); 128 if ( nCount > 1 ) 129 return CreateMemChartMulti(); 130 else if ( nCount == 1 ) 131 { 132 ScRange* pR = aRangeListRef->First(); 133 if ( pR->aStart.Tab() != pR->aEnd.Tab() ) 134 return CreateMemChartMulti(); 135 else 136 return CreateMemChartSingle(); 137 } 138 else 139 return CreateMemChartMulti(); // kann 0 Range besser ab als Single 140 } 141 142 ScMemChart* ScChartArray::CreateMemChartSingle() 143 { 144 SCSIZE nCol; 145 SCSIZE nRow; 146 147 // 148 // wirkliche Groesse (ohne versteckte Zeilen/Spalten) 149 // 150 151 SCCOL nColAdd = HasRowHeaders() ? 1 : 0; 152 SCROW nRowAdd = HasColHeaders() ? 1 : 0; 153 154 SCCOL nCol1; 155 SCROW nRow1; 156 SCTAB nTab1; 157 SCCOL nCol2; 158 SCROW nRow2; 159 SCTAB nTab2; 160 ScRangeListRef aRangeListRef(GetRangeList()); 161 aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 162 163 SCCOL nStrCol = nCol1; // fuer Beschriftung merken 164 SCROW nStrRow = nRow1; 165 // Skip hidden columns. 166 // TODO: make use of last column value once implemented. 167 SCCOL nLastCol = -1; 168 while (pDocument->ColHidden(nCol1, nTab1, nLastCol)) 169 ++nCol1; 170 171 // Skip hidden rows. 172 SCROW nLastRow = -1; 173 if (pDocument->RowHidden(nRow1, nTab1, nLastRow)) 174 nRow1 = nLastRow + 1; 175 176 // falls alles hidden ist, bleibt die Beschriftung am Anfang 177 if ( nCol1 <= nCol2 ) 178 { 179 nStrCol = nCol1; 180 nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd ); 181 } 182 if ( nRow1 <= nRow2 ) 183 { 184 nStrRow = nRow1; 185 nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd ); 186 } 187 188 SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 ); 189 vector<SCCOL> aCols; 190 aCols.reserve(nTotalCols); 191 for (SCSIZE i=0; i<nTotalCols; i++) 192 { 193 SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i); 194 if (!pDocument->ColHidden(nThisCol, nTab1, nLastCol)) 195 aCols.push_back(nThisCol); 196 } 197 SCSIZE nColCount = aCols.size(); 198 199 SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 ); 200 vector<SCROW> aRows; 201 aRows.reserve(nTotalRows); 202 if (nRow1 <= nRow2) 203 { 204 // Get all visible rows between nRow1 and nRow2. 205 SCROW nThisRow = nRow1; 206 while (nThisRow <= nRow2) 207 { 208 if (pDocument->RowHidden(nThisRow, nTab1, nLastRow)) 209 nThisRow = nLastRow; 210 else 211 aRows.push_back(nThisRow); 212 ++nThisRow; 213 } 214 } 215 SCSIZE nRowCount = aRows.size(); 216 217 // May happen at least with more than 32k rows. 218 if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX) 219 { 220 nColCount = 0; 221 nRowCount = 0; 222 } 223 224 sal_Bool bValidData = sal_True; 225 if ( !nColCount ) 226 { 227 bValidData = sal_False; 228 nColCount = 1; 229 aCols.push_back(nStrCol); 230 } 231 if ( !nRowCount ) 232 { 233 bValidData = sal_False; 234 nRowCount = 1; 235 aRows.push_back(nStrRow); 236 } 237 238 // 239 // Daten 240 // 241 242 ScMemChart* pMemChart = new ScMemChart( 243 static_cast<short>(nColCount), static_cast<short>(nRowCount) ); 244 if (pMemChart) 245 { 246 // SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 247 // pMemChart->SetNumberFormatter( pFormatter ); 248 if ( bValidData ) 249 { 250 sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown(); 251 ScBaseCell* pCell; 252 for (nCol=0; nCol<nColCount; nCol++) 253 { 254 for (nRow=0; nRow<nRowCount; nRow++) 255 { 256 double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen 257 258 pDocument->GetCell( aCols[nCol], aRows[nRow], nTab1, pCell ); 259 if (pCell) 260 { 261 CellType eType = pCell->GetCellType(); 262 if (eType == CELLTYPE_VALUE) 263 { 264 nVal = ((ScValueCell*)pCell)->GetValue(); 265 if ( bCalcAsShown && nVal != 0.0 ) 266 { 267 sal_uInt32 nFormat; 268 pDocument->GetNumberFormat( aCols[nCol], 269 aRows[nRow], nTab1, nFormat ); 270 nVal = pDocument->RoundValueAsShown( nVal, nFormat ); 271 } 272 } 273 else if (eType == CELLTYPE_FORMULA) 274 { 275 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 276 if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() ) 277 nVal = pFCell->GetValue(); 278 } 279 } 280 pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal); 281 } 282 } 283 } 284 else 285 { 286 //! Flag, dass Daten ungueltig ?? 287 288 for (nCol=0; nCol<nColCount; nCol++) 289 for (nRow=0; nRow<nRowCount; nRow++) 290 pMemChart->SetData( static_cast<short>(nCol), static_cast<short>(nRow), DBL_MIN ); 291 } 292 293 // 294 // Spalten-Header 295 // 296 297 for (nCol=0; nCol<nColCount; nCol++) 298 { 299 String aString, aColStr; 300 if (HasColHeaders()) 301 pDocument->GetString( aCols[nCol], nStrRow, nTab1, aString ); 302 if ( !aString.Len() ) 303 { 304 aString = ScGlobal::GetRscString(STR_COLUMN); 305 aString += ' '; 306 // aString += String::CreateFromInt32( pCols[nCol]+1 ); 307 ScAddress aPos( aCols[ nCol ], 0, 0 ); 308 aPos.Format( aColStr, SCA_VALID_COL, NULL ); 309 aString += aColStr; 310 } 311 pMemChart->SetColText( static_cast<short>(nCol), aString); 312 313 // sal_uLong nNumberAttr = (nTotalRows ? pDocument->GetNumberFormat( 314 // ScAddress( pCols[nCol], nRow1, nTab1)) : 0); 315 // pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr ); 316 } 317 318 // 319 // Zeilen-Header 320 // 321 322 for (nRow=0; nRow<nRowCount; nRow++) 323 { 324 String aString; 325 if (HasRowHeaders()) 326 { 327 ScAddress aAddr( nStrCol, aRows[nRow], nTab1 ); 328 pDocument->GetString( nStrCol, aRows[nRow], nTab1, aString ); 329 } 330 if ( !aString.Len() ) 331 { 332 aString = ScGlobal::GetRscString(STR_ROW); 333 aString += ' '; 334 aString += String::CreateFromInt32( aRows[nRow]+1 ); 335 } 336 pMemChart->SetRowText( static_cast<short>(nRow), aString); 337 338 // sal_uLong nNumberAttr = (nTotalCols ? pDocument->GetNumberFormat( 339 // ScAddress( nCol1, pRows[nRow], nTab1)) : 0); 340 // pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr ); 341 } 342 343 // 344 // Titel 345 // 346 347 // pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE)); 348 // pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE)); 349 // pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE)); 350 // pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE)); 351 // pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE)); 352 353 // 354 // Zahlen-Typ 355 // 356 357 // sal_uLong nNumberAttr = (nTotalCols && nTotalRows ? 358 // pDocument->GetNumberFormat( ScAddress( nCol1, nRow1, nTab1)) : 359 // 0); 360 // if (pFormatter) 361 // pMemChart->SetDataType(pFormatter->GetType( nNumberAttr )); 362 363 // 364 // Parameter-Strings 365 // 366 367 // SetExtraStrings( *pMemChart ); 368 } 369 370 return pMemChart; 371 } 372 373 ScMemChart* ScChartArray::CreateMemChartMulti() 374 { 375 SCSIZE nColCount = GetPositionMap()->GetColCount(); 376 SCSIZE nRowCount = GetPositionMap()->GetRowCount(); 377 378 SCSIZE nCol = 0; 379 SCSIZE nRow = 0; 380 381 // May happen at least with more than 32k rows. 382 if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX) 383 { 384 nColCount = 0; 385 nRowCount = 0; 386 } 387 388 sal_Bool bValidData = sal_True; 389 if ( !nColCount ) 390 { 391 bValidData = sal_False; 392 nColCount = 1; 393 } 394 if ( !nRowCount ) 395 { 396 bValidData = sal_False; 397 nRowCount = 1; 398 } 399 400 // 401 // Daten 402 // 403 404 ScMemChart* pMemChart = new ScMemChart( 405 static_cast<short>(nColCount), static_cast<short>(nRowCount) ); 406 if (pMemChart) 407 { 408 // pMemChart->SetNumberFormatter( pDocument->GetFormatTable() ); 409 sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown(); 410 sal_uLong nIndex = 0; 411 if (bValidData) 412 { 413 for ( nCol = 0; nCol < nColCount; nCol++ ) 414 { 415 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ ) 416 { 417 double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen 418 const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex ); 419 if ( pPos ) 420 { // sonst: Luecke 421 ScBaseCell* pCell = pDocument->GetCell( *pPos ); 422 if (pCell) 423 { 424 CellType eType = pCell->GetCellType(); 425 if (eType == CELLTYPE_VALUE) 426 { 427 nVal = ((ScValueCell*)pCell)->GetValue(); 428 if ( bCalcAsShown && nVal != 0.0 ) 429 { 430 sal_uLong nFormat = pDocument->GetNumberFormat( *pPos ); 431 nVal = pDocument->RoundValueAsShown( nVal, nFormat ); 432 } 433 } 434 else if (eType == CELLTYPE_FORMULA) 435 { 436 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 437 if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() ) 438 nVal = pFCell->GetValue(); 439 } 440 } 441 } 442 pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal); 443 } 444 } 445 } 446 else 447 { 448 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ ) 449 { 450 double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen 451 const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex ); 452 if ( pPos ) 453 { // sonst: Luecke 454 ScBaseCell* pCell = pDocument->GetCell( *pPos ); 455 if (pCell) 456 { 457 CellType eType = pCell->GetCellType(); 458 if (eType == CELLTYPE_VALUE) 459 { 460 nVal = ((ScValueCell*)pCell)->GetValue(); 461 if ( bCalcAsShown && nVal != 0.0 ) 462 { 463 sal_uLong nFormat = pDocument->GetNumberFormat( *pPos ); 464 nVal = pDocument->RoundValueAsShown( nVal, nFormat ); 465 } 466 } 467 else if (eType == CELLTYPE_FORMULA) 468 { 469 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 470 if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() ) 471 nVal = pFCell->GetValue(); 472 } 473 } 474 } 475 pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal); 476 } 477 } 478 479 //2do: Beschriftung bei Luecken 480 481 // 482 // Spalten-Header 483 // 484 485 SCCOL nPosCol = 0; 486 for ( nCol = 0; nCol < nColCount; nCol++ ) 487 { 488 String aString, aColStr; 489 const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) ); 490 if ( HasColHeaders() && pPos ) 491 pDocument->GetString( 492 pPos->Col(), pPos->Row(), pPos->Tab(), aString ); 493 if ( !aString.Len() ) 494 { 495 aString = ScGlobal::GetRscString(STR_COLUMN); 496 aString += ' '; 497 if ( pPos ) 498 nPosCol = pPos->Col() + 1; 499 else 500 nPosCol++; 501 ScAddress aPos( nPosCol - 1, 0, 0 ); 502 aPos.Format( aColStr, SCA_VALID_COL, NULL ); 503 // aString += String::CreateFromInt32( nPosCol ); 504 aString += aColStr; 505 } 506 pMemChart->SetColText( static_cast<short>(nCol), aString); 507 508 // sal_uLong nNumberAttr = 0; 509 // pPos = GetPositionMap()->GetPosition( nCol, 0 ); 510 // if ( pPos ) 511 // nNumberAttr = pDocument->GetNumberFormat( *pPos ); 512 // pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr ); 513 } 514 515 // 516 // Zeilen-Header 517 // 518 519 SCROW nPosRow = 0; 520 for ( nRow = 0; nRow < nRowCount; nRow++ ) 521 { 522 String aString; 523 const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow ); 524 if ( HasRowHeaders() && pPos ) 525 { 526 pDocument->GetString( 527 pPos->Col(), pPos->Row(), pPos->Tab(), aString ); 528 } 529 if ( !aString.Len() ) 530 { 531 aString = ScGlobal::GetRscString(STR_ROW); 532 aString += ' '; 533 if ( pPos ) 534 nPosRow = pPos->Row() + 1; 535 else 536 nPosRow++; 537 aString += String::CreateFromInt32( nPosRow ); 538 } 539 pMemChart->SetRowText( static_cast<short>(nRow), aString); 540 541 // sal_uLong nNumberAttr = 0; 542 // pPos = GetPositionMap()->GetPosition( 0, nRow ); 543 // if ( pPos ) 544 // nNumberAttr = pDocument->GetNumberFormat( *pPos ); 545 // pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr ); 546 } 547 548 // 549 // Titel 550 // 551 552 // pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE)); 553 // pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE)); 554 // pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE)); 555 // pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE)); 556 // pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE)); 557 558 // 559 // Zahlen-Typ 560 // 561 562 // SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 563 // if (pFormatter) 564 // { 565 // sal_uLong nIndex = 0; 566 // sal_uLong nCount = GetPositionMap()->GetCount(); 567 // const ScAddress* pPos; 568 // do 569 // { 570 // pPos = GetPositionMap()->GetPosition( nIndex ); 571 // } while ( !pPos && ++nIndex < nCount ); 572 // sal_uLong nFormat = ( pPos ? pDocument->GetNumberFormat( *pPos ) : 0 ); 573 // pMemChart->SetDataType( pFormatter->GetType( nFormat ) ); 574 // } 575 576 // 577 // Parameter-Strings 578 // 579 580 // SetExtraStrings( *pMemChart ); 581 } 582 583 return pMemChart; 584 } 585 586 #ifdef _MSC_VER 587 #pragma optimize("",on) 588 #endif 589 590 591 // 592 // Collection 593 // 594 595 ScDataObject* ScChartCollection::Clone() const 596 { 597 return new ScChartCollection(*this); 598 } 599 600 sal_Bool ScChartCollection::operator==(const ScChartCollection& rCmp) const 601 { 602 if (nCount != rCmp.nCount) 603 return sal_False; 604 605 for (sal_uInt16 i=0; i<nCount; i++) 606 if (!((*(const ScChartArray*)pItems[i]) == (*(const ScChartArray*)rCmp.pItems[i]))) 607 return sal_False; 608 609 return sal_True; 610 } 611 612