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