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 #include "chart2uno.hxx" 32 #include "miscuno.hxx" 33 #include "document.hxx" 34 #include "unoguard.hxx" 35 #include "cell.hxx" 36 #include "chartpos.hxx" 37 #include "unonames.hxx" 38 #include "globstr.hrc" 39 #include "convuno.hxx" 40 #include "rangeutl.hxx" 41 #include "hints.hxx" 42 #include "unoreflist.hxx" 43 #include "compiler.hxx" 44 #include "reftokenhelper.hxx" 45 #include "chartlis.hxx" 46 47 #include <sfx2/objsh.hxx> 48 #include <tools/table.hxx> 49 50 #include <com/sun/star/beans/UnknownPropertyException.hpp> 51 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 52 #include <com/sun/star/table/XCellRange.hpp> 53 #include <com/sun/star/table/CellAddress.hpp> 54 #include <com/sun/star/text/XText.hpp> 55 #include <comphelper/extract.hxx> 56 #include <comphelper/processfactory.hxx> 57 58 #include <vector> 59 #include <list> 60 #include <rtl/math.hxx> 61 62 SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider", 63 "com.sun.star.chart2.data.DataProvider") 64 SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource", 65 "com.sun.star.chart2.data.DataSource") 66 SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence", 67 "com.sun.star.chart2.data.DataSequence") 68 #if USE_CHART2_EMPTYDATASEQUENCE 69 SC_SIMPLE_SERVICE_INFO( ScChart2EmptyDataSequence, "ScChart2EmptyDataSequence", 70 "com.sun.star.chart2.data.DataSequence") 71 #endif 72 73 using namespace ::com::sun::star; 74 using namespace ::formula; 75 using ::rtl::OUString; 76 using ::rtl::OUStringBuffer; 77 using ::com::sun::star::uno::Sequence; 78 using ::com::sun::star::uno::Reference; 79 using ::std::auto_ptr; 80 using ::std::vector; 81 using ::std::list; 82 using ::std::distance; 83 using ::std::unary_function; 84 using ::std::hash_set; 85 using ::boost::shared_ptr; 86 87 namespace 88 { 89 const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap() 90 { 91 static SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] = 92 { 93 {MAP_CHAR_LEN(SC_UNONAME_INCLUDEHIDDENCELLS), 0, &getBooleanCppuType(), 0, 0 }, 94 {0,0,0,0,0,0} 95 }; 96 return aDataProviderPropertyMap_Impl; 97 } 98 99 const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap() 100 { 101 static SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] = 102 { 103 {MAP_CHAR_LEN(SC_UNONAME_HIDDENVALUES), 0, &getCppuType((uno::Sequence<sal_Int32>*)0 ), 0, 0 }, 104 {MAP_CHAR_LEN(SC_UNONAME_ROLE), 0, &getCppuType((::com::sun::star::chart2::data::DataSequenceRole*)0), 0, 0 }, 105 {MAP_CHAR_LEN(SC_UNONAME_INCLUDEHIDDENCELLS), 0, &getBooleanCppuType(), 0, 0 }, 106 {0,0,0,0,0,0} 107 }; 108 return aDataSequencePropertyMap_Impl; 109 } 110 111 template< typename T > 112 ::com::sun::star::uno::Sequence< T > lcl_VectorToSequence( 113 const ::std::vector< T > & rCont ) 114 { 115 ::com::sun::star::uno::Sequence< T > aResult( rCont.size()); 116 ::std::copy( rCont.begin(), rCont.end(), aResult.getArray()); 117 return aResult; 118 } 119 120 struct lcl_appendTableNumber : public ::std::unary_function< SCTAB, void > 121 { 122 lcl_appendTableNumber( ::rtl::OUStringBuffer & rBuffer ) : 123 m_rBuffer( rBuffer ) 124 {} 125 void operator() ( SCTAB nTab ) 126 { 127 // there is no append with SCTAB or sal_Int16 128 m_rBuffer.append( static_cast< sal_Int32 >( nTab )); 129 m_rBuffer.append( sal_Unicode( ' ' )); 130 } 131 private: 132 ::rtl::OUStringBuffer & m_rBuffer; 133 }; 134 135 ::rtl::OUString lcl_createTableNumberList( const ::std::list< SCTAB > & rTableList ) 136 { 137 ::rtl::OUStringBuffer aBuffer; 138 ::std::for_each( rTableList.begin(), rTableList.end(), lcl_appendTableNumber( aBuffer )); 139 // remove last trailing ' ' 140 if( aBuffer.getLength() > 0 ) 141 aBuffer.setLength( aBuffer.getLength() - 1 ); 142 return aBuffer.makeStringAndClear(); 143 } 144 145 uno::Reference< frame::XModel > lcl_GetXModel( ScDocument * pDoc ) 146 { 147 uno::Reference< frame::XModel > xModel; 148 SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : 0 ); 149 if( pObjSh ) 150 xModel.set( pObjSh->GetModel()); 151 return xModel; 152 } 153 154 uno::Reference< sheet::XSpreadsheetDocument > lcl_GetSpreadSheetDocument( ScDocument * pDoc ) 155 { 156 return uno::Reference< sheet::XSpreadsheetDocument >( lcl_GetXModel( pDoc ), uno::UNO_QUERY ); 157 } 158 159 // ============================================================================ 160 161 namespace { 162 163 struct DeleteInstance : public unary_function<FormulaToken*, void> 164 { 165 void operator() (FormulaToken* p) const 166 { 167 delete p; 168 } 169 }; 170 171 } 172 173 struct TokenTable 174 { 175 SCROW mnRowCount; 176 SCCOL mnColCount; 177 vector<FormulaToken*> maTokens; 178 179 void init( SCCOL nColCount, SCROW nRowCount ) 180 { 181 mnColCount = nColCount; 182 mnRowCount = nRowCount; 183 maTokens.reserve(mnColCount*mnRowCount); 184 } 185 void clear() 186 { 187 for_each(maTokens.begin(), maTokens.end(), DeleteInstance()); 188 } 189 190 void push_back( FormulaToken* pToken ) 191 { 192 maTokens.push_back( pToken ); 193 DBG_ASSERT( maTokens.size()<= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too much tokens" ); 194 } 195 196 sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const 197 { 198 DBG_ASSERT( nCol<mnColCount, "wrong column index" ); 199 DBG_ASSERT( nRow<mnRowCount, "wrong row index" ); 200 sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow); 201 DBG_ASSERT( maTokens.size()>= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too few tokens" ); 202 return nRet; 203 } 204 205 vector<ScSharedTokenRef>* getColRanges(SCCOL nCol) const; 206 vector<ScSharedTokenRef>* getRowRanges(SCROW nRow) const; 207 vector<ScSharedTokenRef>* getAllRanges() const; 208 }; 209 210 vector<ScSharedTokenRef>* TokenTable::getColRanges(SCCOL nCol) const 211 { 212 if (nCol >= mnColCount) 213 return NULL; 214 if( mnRowCount<=0 ) 215 return NULL; 216 217 auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>); 218 sal_uInt32 nLast = getIndex(nCol, mnRowCount-1); 219 for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i) 220 { 221 FormulaToken* p = maTokens[i]; 222 if (!p) 223 continue; 224 225 ScSharedTokenRef pCopy(static_cast<ScToken*>(p->Clone())); 226 ScRefTokenHelper::join(*pTokens, pCopy); 227 } 228 return pTokens.release(); 229 } 230 231 vector<ScSharedTokenRef>* TokenTable::getRowRanges(SCROW nRow) const 232 { 233 if (nRow >= mnRowCount) 234 return NULL; 235 if( mnColCount<=0 ) 236 return NULL; 237 238 auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>); 239 sal_uInt32 nLast = getIndex(mnColCount-1, nRow); 240 for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount) 241 { 242 FormulaToken* p = maTokens[i]; 243 if (!p) 244 continue; 245 246 ScSharedTokenRef p2(static_cast<ScToken*>(p->Clone())); 247 ScRefTokenHelper::join(*pTokens, p2); 248 } 249 return pTokens.release(); 250 } 251 252 vector<ScSharedTokenRef>* TokenTable::getAllRanges() const 253 { 254 auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>); 255 sal_uInt32 nStop = mnColCount*mnRowCount; 256 for (sal_uInt32 i = 0; i < nStop; i++) 257 { 258 FormulaToken* p = maTokens[i]; 259 if (!p) 260 continue; 261 262 ScSharedTokenRef p2(static_cast<ScToken*>(p->Clone())); 263 ScRefTokenHelper::join(*pTokens, p2); 264 } 265 return pTokens.release(); 266 } 267 268 // ============================================================================ 269 270 class Chart2PositionMap 271 { 272 public: 273 Chart2PositionMap(SCCOL nColCount, SCROW nRowCount, 274 bool bFillRowHeader, bool bFillColumnHeader, Table& rCols, 275 ScDocument* pDoc ); 276 ~Chart2PositionMap(); 277 278 SCCOL getDataColCount() const { return mnDataColCount; } 279 SCROW getDataRowCount() const { return mnDataRowCount; } 280 281 vector<ScSharedTokenRef>* getLeftUpperCornerRanges() const; 282 vector<ScSharedTokenRef>* getAllColHeaderRanges() const; 283 vector<ScSharedTokenRef>* getAllRowHeaderRanges() const; 284 285 vector<ScSharedTokenRef>* getColHeaderRanges(SCCOL nChartCol) const; 286 vector<ScSharedTokenRef>* getRowHeaderRanges(SCROW nChartRow) const; 287 288 vector<ScSharedTokenRef>* getDataColRanges(SCCOL nCol) const; 289 vector<ScSharedTokenRef>* getDataRowRanges(SCROW nRow) const; 290 291 private: 292 SCCOL mnDataColCount; 293 SCROW mnDataRowCount; 294 295 TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount 296 TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount 297 TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount 298 TokenTable maData;//mnDataColCount*mnDataRowCount 299 }; 300 301 Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount, 302 bool bFillRowHeader, bool bFillColumnHeader, Table& rCols, ScDocument* pDoc) 303 { 304 // if bFillRowHeader is true, at least the first column serves as a row header. 305 // If more than one column is pure text all the first pure text columns are used as header. 306 // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header. 307 // If more than one row is pure text all the first pure text rows are used as header. 308 309 SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0; 310 SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0; 311 312 if( nHeaderColCount || nHeaderRowCount ) 313 { 314 const SCCOL nInitialHeaderColCount = nHeaderColCount; 315 //check whether there is more than one text column or row that should be added to the headers 316 SCROW nSmallestValueRowIndex = nAllRowCount; 317 bool bFoundValues = false; 318 bool bFoundAnything = false; 319 Table* pCol = static_cast<Table*>(rCols.First()); 320 for (SCCOL nCol = 0; !bFoundValues && nCol < nAllColCount; ++nCol) 321 { 322 if (pCol && nCol>=nHeaderColCount) 323 { 324 ScToken* pToken = static_cast<ScToken*>(pCol->First()); 325 for (SCROW nRow = 0; !bFoundValues && nRow < nSmallestValueRowIndex; ++nRow) 326 { 327 if (pToken && nRow>=nHeaderRowCount) 328 { 329 ScRange aRange; 330 bool bExternal = false; 331 StackVar eType = pToken->GetType(); 332 if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName ) 333 bExternal = true;//lllll todo correct? 334 ScSharedTokenRef pSharedToken(static_cast<ScToken*>(pToken->Clone())); 335 ScRefTokenHelper::getRangeFromToken(aRange, pSharedToken, bExternal ); 336 SCCOL nCol1=0, nCol2=0; 337 SCROW nRow1=0, nRow2=0; 338 SCTAB nTab1=0, nTab2=0; 339 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 340 if (pDoc && pDoc->HasValueData( nCol1, nRow1, nTab1 )) 341 { 342 bFoundValues = bFoundAnything = true; 343 nSmallestValueRowIndex = std::min( nSmallestValueRowIndex, nRow ); 344 } 345 if( !bFoundAnything ) 346 { 347 if (pDoc && pDoc->HasData( nCol1, nRow1, nTab1 ) ) 348 bFoundAnything = true; 349 } 350 } 351 pToken = static_cast<ScToken*>(pCol->Next()); 352 } 353 if(!bFoundValues && nHeaderColCount>0) 354 nHeaderColCount++; 355 } 356 pCol = static_cast<Table*>(rCols.Next()); 357 } 358 if( bFoundAnything ) 359 { 360 if(nHeaderRowCount>0) 361 { 362 if( bFoundValues ) 363 nHeaderRowCount = nSmallestValueRowIndex; 364 else if( nAllRowCount>1 ) 365 nHeaderRowCount = nAllRowCount-1; 366 } 367 } 368 else //if the cells are completely empty, just use single header rows and columns 369 nHeaderColCount = nInitialHeaderColCount; 370 } 371 372 mnDataColCount = nAllColCount - nHeaderColCount; 373 mnDataRowCount = nAllRowCount - nHeaderRowCount; 374 375 maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount); 376 maColHeaders.init(mnDataColCount,nHeaderRowCount); 377 maRowHeaders.init(nHeaderColCount,mnDataRowCount); 378 maData.init(mnDataColCount,mnDataRowCount); 379 380 Table* pCol = static_cast<Table*>(rCols.First()); 381 FormulaToken* pToken = static_cast<FormulaToken*>(pCol->First()); 382 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol) 383 { 384 if (pCol) 385 { 386 pToken = static_cast<FormulaToken*>(pCol->First()); 387 for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow) 388 { 389 if( nCol < nHeaderColCount ) 390 { 391 if( nRow < nHeaderRowCount ) 392 maLeftUpperCorner.push_back(pToken); 393 else 394 maRowHeaders.push_back(pToken); 395 } 396 else if( nRow < nHeaderRowCount ) 397 maColHeaders.push_back(pToken); 398 else 399 maData.push_back(pToken); 400 401 pToken = static_cast<FormulaToken*>(pCol->Next()); 402 } 403 } 404 pCol = static_cast<Table*>(rCols.Next()); 405 } 406 } 407 408 Chart2PositionMap::~Chart2PositionMap() 409 { 410 maLeftUpperCorner.clear(); 411 maColHeaders.clear(); 412 maRowHeaders.clear(); 413 maData.clear(); 414 } 415 416 vector<ScSharedTokenRef>* Chart2PositionMap::getLeftUpperCornerRanges() const 417 { 418 return maLeftUpperCorner.getAllRanges(); 419 } 420 vector<ScSharedTokenRef>* Chart2PositionMap::getAllColHeaderRanges() const 421 { 422 return maColHeaders.getAllRanges(); 423 } 424 vector<ScSharedTokenRef>* Chart2PositionMap::getAllRowHeaderRanges() const 425 { 426 return maRowHeaders.getAllRanges(); 427 } 428 vector<ScSharedTokenRef>* Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const 429 { 430 return maColHeaders.getColRanges( nCol); 431 } 432 vector<ScSharedTokenRef>* Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const 433 { 434 return maRowHeaders.getRowRanges( nRow); 435 } 436 437 vector<ScSharedTokenRef>* Chart2PositionMap::getDataColRanges(SCCOL nCol) const 438 { 439 return maData.getColRanges( nCol); 440 } 441 442 vector<ScSharedTokenRef>* Chart2PositionMap::getDataRowRanges(SCROW nRow) const 443 { 444 return maData.getRowRanges( nRow); 445 } 446 447 // ---------------------------------------------------------------------------- 448 449 /** 450 * Designed to be a drop-in replacement for ScChartPositioner, in order to 451 * handle external references. 452 */ 453 class Chart2Positioner 454 { 455 enum GlueType 456 { 457 GLUETYPE_NA, 458 GLUETYPE_NONE, 459 GLUETYPE_COLS, 460 GLUETYPE_ROWS, 461 GLUETYPE_BOTH 462 }; 463 464 public: 465 Chart2Positioner(ScDocument* pDoc, const vector<ScSharedTokenRef>& rRefTokens) : 466 mpRefTokens(new vector<ScSharedTokenRef>(rRefTokens)), 467 mpPositionMap(NULL), 468 meGlue(GLUETYPE_NA), 469 mpDoc(pDoc), 470 mbColHeaders(false), 471 mbRowHeaders(false), 472 mbDummyUpperLeft(false) 473 { 474 } 475 476 ~Chart2Positioner() 477 { 478 } 479 480 void setHeaders(bool bColHeaders, bool bRowHeaders) 481 { 482 mbColHeaders = bColHeaders; 483 mbRowHeaders = bRowHeaders; 484 } 485 486 bool hasColHeaders() const { return mbColHeaders; } 487 bool hasRowHeaders() const { return mbRowHeaders; } 488 489 Chart2PositionMap* getPositionMap() 490 { 491 createPositionMap(); 492 return mpPositionMap.get(); 493 } 494 495 private: 496 Chart2Positioner(); // disabled 497 498 void invalidateGlue(); 499 void glueState(); 500 void createPositionMap(); 501 502 private: 503 shared_ptr< vector<ScSharedTokenRef> > mpRefTokens; 504 auto_ptr<Chart2PositionMap> mpPositionMap; 505 GlueType meGlue; 506 SCCOL mnStartCol; 507 SCROW mnStartRow; 508 ScDocument* mpDoc; 509 bool mbColHeaders:1; 510 bool mbRowHeaders:1; 511 bool mbDummyUpperLeft:1; 512 }; 513 514 void Chart2Positioner::invalidateGlue() 515 { 516 meGlue = GLUETYPE_NA; 517 mpPositionMap.reset(NULL); 518 } 519 520 void Chart2Positioner::glueState() 521 { 522 if (meGlue != GLUETYPE_NA) 523 return; 524 525 mbDummyUpperLeft = false; 526 if (mpRefTokens->size() <= 1) 527 { 528 const ScSharedTokenRef& p = mpRefTokens->front(); 529 ScComplexRefData aData; 530 if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p)) 531 { 532 if (aData.Ref1.nTab == aData.Ref2.nTab) 533 meGlue = GLUETYPE_NONE; 534 else 535 meGlue = GLUETYPE_COLS; 536 mnStartCol = aData.Ref1.nCol; 537 mnStartRow = aData.Ref1.nRow; 538 } 539 else 540 { 541 invalidateGlue(); 542 mnStartCol = 0; 543 mnStartRow = 0; 544 } 545 return; 546 } 547 548 ScComplexRefData aData; 549 ScRefTokenHelper::getDoubleRefDataFromToken(aData, mpRefTokens->front()); 550 mnStartCol = aData.Ref1.nCol; 551 mnStartRow = aData.Ref1.nRow; 552 553 SCCOL nMaxCols = 0, nEndCol = 0; 554 SCROW nMaxRows = 0, nEndRow = 0; 555 for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end() 556 ; itr != itrEnd; ++itr) 557 { 558 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr); 559 SCCOLROW n1 = aData.Ref1.nCol; 560 SCCOLROW n2 = aData.Ref2.nCol; 561 if (n1 > MAXCOL) 562 n1 = MAXCOL; 563 if (n2 > MAXCOL) 564 n2 = MAXCOL; 565 SCCOLROW nTmp = n2 - n1 + 1; 566 if (n1 < mnStartCol) 567 mnStartCol = static_cast<SCCOL>(n1); 568 if (n2 > nEndCol) 569 nEndCol = static_cast<SCCOL>(n2); 570 if (nTmp > nMaxCols) 571 nMaxCols = static_cast<SCCOL>(nTmp); 572 573 n1 = aData.Ref1.nRow; 574 n2 = aData.Ref2.nRow; 575 if (n1 > MAXROW) 576 n1 = MAXROW; 577 if (n2 > MAXROW) 578 n2 = MAXROW; 579 nTmp = n2 - n1 + 1; 580 581 if (n1 < mnStartRow) 582 mnStartRow = static_cast<SCROW>(n1); 583 if (n2 > nEndRow) 584 nEndRow = static_cast<SCROW>(n2); 585 if (nTmp > nMaxRows) 586 nMaxRows = static_cast<SCROW>(nTmp); 587 } 588 589 // total column size ? 590 SCCOL nC = nEndCol - mnStartCol + 1; 591 if (nC == 1) 592 { 593 meGlue = GLUETYPE_ROWS; 594 return; 595 } 596 // total row size ? 597 SCROW nR = nEndRow - mnStartRow + 1; 598 if (nR == 1) 599 { 600 meGlue = GLUETYPE_COLS; 601 return; 602 } 603 // #i103540# prevent invalid vector size 604 if ((nC <= 0) || (nR <= 0)) 605 { 606 invalidateGlue(); 607 mnStartCol = 0; 608 mnStartRow = 0; 609 return; 610 } 611 sal_uInt32 nCR = static_cast<sal_uInt32>(nC*nR); 612 613 const sal_uInt8 nHole = 0; 614 const sal_uInt8 nOccu = 1; 615 const sal_uInt8 nFree = 2; 616 const sal_uInt8 nGlue = 3; 617 618 vector<sal_uInt8> aCellStates(nCR); 619 for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end(); 620 itr != itrEnd; ++itr) 621 { 622 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr); 623 SCCOL nCol1 = static_cast<SCCOL>(aData.Ref1.nCol) - mnStartCol; 624 SCCOL nCol2 = static_cast<SCCOL>(aData.Ref2.nCol) - mnStartCol; 625 SCROW nRow1 = static_cast<SCROW>(aData.Ref1.nRow) - mnStartRow; 626 SCROW nRow2 = static_cast<SCROW>(aData.Ref2.nRow) - mnStartRow; 627 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) 628 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) 629 { 630 size_t i = nCol*nR + nRow; 631 aCellStates[i] = nOccu; 632 } 633 } 634 bool bGlue = true; 635 636 size_t i = 0; 637 bool bGlueCols = false; 638 for (SCCOL nCol = 0; bGlue && nCol < nC; ++nCol) 639 { 640 for (SCROW nRow = 0; bGlue && nRow < nR; ++nRow) 641 { 642 i = nCol*nR + nRow; 643 if (aCellStates[i] == nOccu) 644 { 645 if (nRow > 0 && nRow > 0) 646 bGlue = false; 647 else 648 nRow = nR; 649 } 650 else 651 aCellStates[i] = nFree; 652 } 653 i = (nCol+1)*nR - 1; // index for the last cell in the column. 654 if (bGlue && (aCellStates[i] == nFree)) 655 { 656 aCellStates[i] = nGlue; 657 bGlueCols = true; 658 } 659 } 660 661 bool bGlueRows = false; 662 for (SCROW nRow = 0; bGlue && nRow < nR; ++nRow) 663 { 664 i = nRow; 665 for (SCCOL nCol = 0; bGlue && nCol < nC; ++nCol, i += nR) 666 { 667 if (aCellStates[i] == nOccu) 668 { 669 if (nCol > 0 && nRow > 0) 670 bGlue = false; 671 else 672 nCol = nC; 673 } 674 else 675 aCellStates[i] = nFree; 676 } 677 i = (nC-1)*nR + nRow; // index for the row position in the last column. 678 if (bGlue && aCellStates[i] == nFree) 679 { 680 aCellStates[i] = nGlue; 681 bGlueRows = true; 682 } 683 } 684 685 i = 1; 686 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i) 687 if (aCellStates[i] == nHole) 688 bGlue = false; 689 690 if (bGlue) 691 { 692 if (bGlueCols && bGlueRows) 693 meGlue = GLUETYPE_BOTH; 694 else if (bGlueRows) 695 meGlue = GLUETYPE_ROWS; 696 else 697 meGlue = GLUETYPE_COLS; 698 if (aCellStates.front() != nOccu) 699 mbDummyUpperLeft = true; 700 } 701 else 702 meGlue = GLUETYPE_NONE; 703 } 704 705 void Chart2Positioner::createPositionMap() 706 { 707 if (meGlue == GLUETYPE_NA && mpPositionMap.get()) 708 mpPositionMap.reset(NULL); 709 710 if (mpPositionMap.get()) 711 return; 712 713 glueState(); 714 715 bool bNoGlue = (meGlue == GLUETYPE_NONE); 716 auto_ptr<Table> pCols(new Table); 717 auto_ptr<FormulaToken> pNewAddress; 718 auto_ptr<Table> pNewRowTable(new Table); 719 Table* pCol = NULL; 720 SCROW nNoGlueRow = 0; 721 for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end(); 722 itr != itrEnd; ++itr) 723 { 724 const ScSharedTokenRef& pToken = *itr; 725 726 bool bExternal = ScRefTokenHelper::isExternalRef(pToken); 727 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0; 728 String aTabName = bExternal ? pToken->GetString() : String(); 729 730 ScComplexRefData aData; 731 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr); 732 const ScSingleRefData& s = aData.Ref1; 733 const ScSingleRefData& e = aData.Ref2; 734 SCCOL nCol1 = s.nCol, nCol2 = e.nCol; 735 SCROW nRow1 = s.nRow, nRow2 = e.nRow; 736 SCTAB nTab1 = s.nTab, nTab2 = e.nTab; 737 738 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab) 739 { 740 // What's this for ??? 741 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) | 742 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1)); 743 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol) 744 { 745 if (bNoGlue || meGlue == GLUETYPE_ROWS) 746 { 747 pCol = static_cast<Table*>(pCols->Get(nInsCol)); 748 if (!pCol) 749 { 750 pCol = pNewRowTable.get(); 751 pCols->Insert(nInsCol, pNewRowTable.release()); 752 pNewRowTable.reset(new Table); 753 } 754 } 755 else 756 { 757 if (pCols->Insert(nInsCol, pNewRowTable.get())) 758 { 759 pCol = pNewRowTable.release(); 760 pNewRowTable.reset(new Table); 761 } 762 else 763 pCol = static_cast<Table*>(pCols->Get(nInsCol)); 764 } 765 766 sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1); 767 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow) 768 { 769 ScSingleRefData aCellData; 770 aCellData.InitFlags(); 771 aCellData.SetFlag3D(true); 772 aCellData.SetColRel(false); 773 aCellData.SetRowRel(false); 774 aCellData.SetTabRel(false); 775 aCellData.nCol = nCol; 776 aCellData.nRow = nRow; 777 aCellData.nTab = nTab; 778 779 if (bExternal) 780 pNewAddress.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData)); 781 else 782 pNewAddress.reset(new ScSingleRefToken(aCellData)); 783 784 if (pCol->Insert(nInsRow, pNewAddress.get())) 785 pNewAddress.release(); // To prevent the instance from being destroyed. 786 } 787 } 788 } 789 nNoGlueRow += nRow2 - nRow1 + 1; 790 } 791 pNewAddress.reset(NULL); 792 pNewRowTable.reset(NULL); 793 794 bool bFillRowHeader = mbRowHeaders; 795 bool bFillColumnHeader = mbColHeaders; 796 797 SCSIZE nAllColCount = static_cast<SCSIZE>(pCols->Count()); 798 SCSIZE nAllRowCount = 0; 799 pCol = static_cast<Table*>(pCols->First()); 800 if (pCol) 801 { 802 if (mbDummyUpperLeft) 803 pCol->Insert(0, NULL); // Dummy fuer Beschriftung 804 nAllRowCount = static_cast<SCSIZE>(pCol->Count()); 805 } 806 807 if( nAllColCount!=0 && nAllRowCount!=0 ) 808 { 809 if (bNoGlue) 810 { 811 Table* pFirstCol = static_cast<Table*>(pCols->First()); 812 sal_uInt32 nCount = pFirstCol->Count(); 813 pFirstCol->First(); 814 for (sal_uInt32 n = 0; n < nCount; ++n, pFirstCol->Next()) 815 { 816 sal_uInt32 nKey = pFirstCol->GetCurKey(); 817 pCols->First(); 818 for (pCol = static_cast<Table*>(pCols->Next()); pCol; pCol = static_cast<Table*>(pCols->Next())) 819 pCol->Insert(nKey, NULL); 820 } 821 } 822 } 823 mpPositionMap.reset( 824 new Chart2PositionMap( 825 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount), 826 bFillRowHeader, bFillColumnHeader, *pCols, mpDoc)); 827 828 // Destroy all column instances. 829 for (pCol = static_cast<Table*>(pCols->First()); pCol; pCol = static_cast<Table*>(pCols->Next())) 830 delete pCol; 831 } 832 833 // ============================================================================ 834 835 /** 836 * Function object to create a range string from a token list. 837 */ 838 class Tokens2RangeString : public unary_function<ScSharedTokenRef, void> 839 { 840 public: 841 Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) : 842 mpRangeStr(new OUStringBuffer), 843 mpDoc(pDoc), 844 meGrammar(eGram), 845 mcRangeSep(cRangeSep), 846 mbFirst(true) 847 { 848 } 849 850 Tokens2RangeString(const Tokens2RangeString& r) : 851 mpRangeStr(r.mpRangeStr), 852 mpDoc(r.mpDoc), 853 meGrammar(r.meGrammar), 854 mcRangeSep(r.mcRangeSep), 855 mbFirst(r.mbFirst) 856 { 857 } 858 859 void operator() (const ScSharedTokenRef& rToken) 860 { 861 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0)); 862 aCompiler.SetGrammar(meGrammar); 863 String aStr; 864 aCompiler.CreateStringFromToken(aStr, rToken.get()); 865 if (mbFirst) 866 mbFirst = false; 867 else 868 mpRangeStr->append(mcRangeSep); 869 mpRangeStr->append(aStr); 870 } 871 872 void getString(OUString& rStr) 873 { 874 rStr = mpRangeStr->makeStringAndClear(); 875 } 876 877 private: 878 Tokens2RangeString(); // disabled 879 880 private: 881 shared_ptr<OUStringBuffer> mpRangeStr; 882 ScDocument* mpDoc; 883 FormulaGrammar::Grammar meGrammar; 884 sal_Unicode mcRangeSep; 885 bool mbFirst; 886 }; 887 888 /** 889 * Function object to convert a list of tokens into a string form suitable 890 * for ODF export. In ODF, a range is expressed as 891 * 892 * (start cell address):(end cell address) 893 * 894 * and each address doesn't include any '$' symbols. 895 */ 896 class Tokens2RangeStringXML : public unary_function<ScSharedTokenRef, void> 897 { 898 public: 899 Tokens2RangeStringXML(ScDocument* pDoc) : 900 mpRangeStr(new OUStringBuffer), 901 mpDoc(pDoc), 902 mcRangeSep(' '), 903 mcAddrSep(':'), 904 mbFirst(true) 905 { 906 } 907 908 Tokens2RangeStringXML(const Tokens2RangeStringXML& r) : 909 mpRangeStr(r.mpRangeStr), 910 mpDoc(r.mpDoc), 911 mcRangeSep(r.mcRangeSep), 912 mcAddrSep(r.mcAddrSep), 913 mbFirst(r.mbFirst) 914 { 915 } 916 917 void operator() (const ScSharedTokenRef& rToken) 918 { 919 if (mbFirst) 920 mbFirst = false; 921 else 922 mpRangeStr->append(mcRangeSep); 923 924 ScSharedTokenRef aStart, aEnd; 925 splitRangeToken(rToken, aStart, aEnd); 926 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0)); 927 aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH); 928 { 929 String aStr; 930 aCompiler.CreateStringFromToken(aStr, aStart.get()); 931 mpRangeStr->append(aStr); 932 } 933 mpRangeStr->append(mcAddrSep); 934 { 935 String aStr; 936 aCompiler.CreateStringFromToken(aStr, aEnd.get()); 937 mpRangeStr->append(aStr); 938 } 939 } 940 941 void getString(OUString& rStr) 942 { 943 rStr = mpRangeStr->makeStringAndClear(); 944 } 945 946 private: 947 Tokens2RangeStringXML(); // disabled 948 949 void splitRangeToken(const ScSharedTokenRef& pToken, ScSharedTokenRef& rStart, ScSharedTokenRef& rEnd) const 950 { 951 ScComplexRefData aData; 952 ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken); 953 bool bExternal = ScRefTokenHelper::isExternalRef(pToken); 954 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0; 955 String aTabName = bExternal ? pToken->GetString() : String(); 956 957 // In saving to XML, we don't prepend address with '$'. 958 setRelative(aData.Ref1); 959 setRelative(aData.Ref2); 960 961 // In XML, the end range must explicitly specify sheet name. 962 aData.Ref2.SetFlag3D(true); 963 964 if (bExternal) 965 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1)); 966 else 967 rStart.reset(new ScSingleRefToken(aData.Ref1)); 968 969 if (bExternal) 970 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2)); 971 else 972 rEnd.reset(new ScSingleRefToken(aData.Ref2)); 973 } 974 975 void setRelative(ScSingleRefData& rData) const 976 { 977 rData.SetColRel(true); 978 rData.SetRowRel(true); 979 rData.SetTabRel(true); 980 } 981 982 private: 983 shared_ptr<OUStringBuffer> mpRangeStr; 984 ScDocument* mpDoc; 985 sal_Unicode mcRangeSep; 986 sal_Unicode mcAddrSep; 987 bool mbFirst; 988 }; 989 990 void lcl_convertTokensToString(OUString& rStr, const vector<ScSharedTokenRef>& rTokens, ScDocument* pDoc) 991 { 992 const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0); 993 FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar(); 994 Tokens2RangeString func(pDoc, eGrammar, cRangeSep); 995 func = for_each(rTokens.begin(), rTokens.end(), func); 996 func.getString(rStr); 997 } 998 999 } // anonymous namespace 1000 1001 // DataProvider ============================================================== 1002 1003 ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc ) 1004 : m_pDocument( pDoc) 1005 , m_aPropSet(lcl_GetDataProviderPropertyMap()) 1006 , m_bIncludeHiddenCells( sal_True) 1007 { 1008 if ( m_pDocument ) 1009 m_pDocument->AddUnoObject( *this); 1010 } 1011 1012 ScChart2DataProvider::~ScChart2DataProvider() 1013 { 1014 if ( m_pDocument ) 1015 m_pDocument->RemoveUnoObject( *this); 1016 } 1017 1018 1019 void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint) 1020 { 1021 if ( rHint.ISA( SfxSimpleHint ) && 1022 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 1023 { 1024 m_pDocument = NULL; 1025 } 1026 } 1027 1028 ::sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments ) 1029 throw (uno::RuntimeException) 1030 { 1031 ScUnoGuard aGuard; 1032 if( ! m_pDocument ) 1033 return false; 1034 1035 rtl::OUString aRangeRepresentation; 1036 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i) 1037 { 1038 rtl::OUString sName(aArguments[i].Name); 1039 if (aArguments[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CellRangeRepresentation"))) 1040 { 1041 aArguments[i].Value >>= aRangeRepresentation; 1042 } 1043 } 1044 1045 vector<ScSharedTokenRef> aTokens; 1046 ScRefTokenHelper::compileRangeRepresentation(aTokens, aRangeRepresentation, m_pDocument, m_pDocument->GetGrammar()); 1047 return !aTokens.empty(); 1048 } 1049 1050 namespace 1051 { 1052 1053 Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens( 1054 auto_ptr< vector< ScSharedTokenRef > > pValueTokens, auto_ptr< vector< ScSharedTokenRef > > pLabelTokens, 1055 ScDocument* pDoc, const Reference< chart2::data::XDataProvider >& xDP, bool bIncludeHiddenCells ) 1056 { 1057 Reference< chart2::data::XLabeledDataSequence > xResult; 1058 bool bHasValues = pValueTokens.get() && !pValueTokens->empty(); 1059 bool bHasLabel = pLabelTokens.get() && !pLabelTokens->empty(); 1060 if( bHasValues || bHasLabel ) 1061 { 1062 try 1063 { 1064 Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); 1065 if ( xContext.is() ) 1066 { 1067 xResult.set( xContext->getServiceManager()->createInstanceWithContext( 1068 ::rtl::OUString::createFromAscii( "com.sun.star.chart2.data.LabeledDataSequence" ), 1069 xContext ), uno::UNO_QUERY_THROW ); 1070 } 1071 if ( bHasValues ) 1072 { 1073 Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, xDP, pValueTokens.release(), bIncludeHiddenCells ) ); 1074 xResult->setValues( xSeq ); 1075 } 1076 if ( bHasLabel ) 1077 { 1078 Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, xDP, pLabelTokens.release(), bIncludeHiddenCells ) ); 1079 xResult->setLabel( xLabelSeq ); 1080 } 1081 } 1082 catch( const uno::Exception& ) 1083 { 1084 } 1085 } 1086 return xResult; 1087 } 1088 1089 //---------------------------------------------------- 1090 /** 1091 * Check the current list of reference tokens, and add the upper left 1092 * corner of the minimum range that encloses all ranges if certain 1093 * conditions are met. 1094 * 1095 * @param rRefTokens list of reference tokens 1096 * 1097 * @return true if the corner was added, false otherwise. 1098 */ 1099 bool lcl_addUpperLeftCornerIfMissing(vector<ScSharedTokenRef>& rRefTokens, 1100 SCROW nCornerRowCount=1, SCCOL nCornerColumnCount=1) 1101 { 1102 using ::std::max; 1103 using ::std::min; 1104 1105 if (rRefTokens.empty()) 1106 return false; 1107 1108 SCCOL nMinCol = MAXCOLCOUNT; 1109 SCROW nMinRow = MAXROWCOUNT; 1110 SCCOL nMaxCol = 0; 1111 SCROW nMaxRow = 0; 1112 SCTAB nTab = 0; 1113 1114 sal_uInt16 nFileId = 0; 1115 String aExtTabName; 1116 bool bExternal = false; 1117 1118 vector<ScSharedTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end(); 1119 1120 // Get the first ref token. 1121 ScSharedTokenRef pToken = *itr; 1122 switch (pToken->GetType()) 1123 { 1124 case svSingleRef: 1125 { 1126 const ScSingleRefData& rData = pToken->GetSingleRef(); 1127 nMinCol = rData.nCol; 1128 nMinRow = rData.nRow; 1129 nMaxCol = rData.nCol; 1130 nMaxRow = rData.nRow; 1131 nTab = rData.nTab; 1132 } 1133 break; 1134 case svDoubleRef: 1135 { 1136 const ScComplexRefData& rData = pToken->GetDoubleRef(); 1137 nMinCol = min(rData.Ref1.nCol, rData.Ref2.nCol); 1138 nMinRow = min(rData.Ref1.nRow, rData.Ref2.nRow); 1139 nMaxCol = max(rData.Ref1.nCol, rData.Ref2.nCol); 1140 nMaxRow = max(rData.Ref1.nRow, rData.Ref2.nRow); 1141 nTab = rData.Ref1.nTab; 1142 } 1143 break; 1144 case svExternalSingleRef: 1145 { 1146 const ScSingleRefData& rData = pToken->GetSingleRef(); 1147 nMinCol = rData.nCol; 1148 nMinRow = rData.nRow; 1149 nMaxCol = rData.nCol; 1150 nMaxRow = rData.nRow; 1151 nTab = rData.nTab; 1152 nFileId = pToken->GetIndex(); 1153 aExtTabName = pToken->GetString(); 1154 bExternal = true; 1155 } 1156 break; 1157 case svExternalDoubleRef: 1158 { 1159 const ScComplexRefData& rData = pToken->GetDoubleRef(); 1160 nMinCol = min(rData.Ref1.nCol, rData.Ref2.nCol); 1161 nMinRow = min(rData.Ref1.nRow, rData.Ref2.nRow); 1162 nMaxCol = max(rData.Ref1.nCol, rData.Ref2.nCol); 1163 nMaxRow = max(rData.Ref1.nRow, rData.Ref2.nRow); 1164 nTab = rData.Ref1.nTab; 1165 nFileId = pToken->GetIndex(); 1166 aExtTabName = pToken->GetString(); 1167 bExternal = true; 1168 } 1169 break; 1170 default: 1171 ; 1172 } 1173 1174 // Determine the minimum range enclosing all data ranges. Also make sure 1175 // that they are all on the same table. 1176 1177 for (++itr; itr != itrEnd; ++itr) 1178 { 1179 pToken = *itr; 1180 switch (pToken->GetType()) 1181 { 1182 case svSingleRef: 1183 { 1184 const ScSingleRefData& rData = pToken->GetSingleRef(); 1185 1186 nMinCol = min(nMinCol, rData.nCol); 1187 nMinRow = min(nMinRow, rData.nRow); 1188 nMaxCol = max(nMaxCol, rData.nCol); 1189 nMaxRow = max(nMaxRow, rData.nRow); 1190 if (nTab != rData.nTab || bExternal) 1191 return false; 1192 } 1193 break; 1194 case svDoubleRef: 1195 { 1196 const ScComplexRefData& rData = pToken->GetDoubleRef(); 1197 1198 nMinCol = min(nMinCol, rData.Ref1.nCol); 1199 nMinCol = min(nMinCol, rData.Ref2.nCol); 1200 nMinRow = min(nMinRow, rData.Ref1.nRow); 1201 nMinRow = min(nMinRow, rData.Ref2.nRow); 1202 1203 nMaxCol = max(nMaxCol, rData.Ref1.nCol); 1204 nMaxCol = max(nMaxCol, rData.Ref2.nCol); 1205 nMaxRow = max(nMaxRow, rData.Ref1.nRow); 1206 nMaxRow = max(nMaxRow, rData.Ref2.nRow); 1207 1208 if (nTab != rData.Ref1.nTab || bExternal) 1209 return false; 1210 } 1211 break; 1212 case svExternalSingleRef: 1213 { 1214 if (!bExternal) 1215 return false; 1216 1217 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString()) 1218 return false; 1219 1220 const ScSingleRefData& rData = pToken->GetSingleRef(); 1221 1222 nMinCol = min(nMinCol, rData.nCol); 1223 nMinRow = min(nMinRow, rData.nRow); 1224 nMaxCol = max(nMaxCol, rData.nCol); 1225 nMaxRow = max(nMaxRow, rData.nRow); 1226 } 1227 break; 1228 case svExternalDoubleRef: 1229 { 1230 if (!bExternal) 1231 return false; 1232 1233 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString()) 1234 return false; 1235 1236 const ScComplexRefData& rData = pToken->GetDoubleRef(); 1237 1238 nMinCol = min(nMinCol, rData.Ref1.nCol); 1239 nMinCol = min(nMinCol, rData.Ref2.nCol); 1240 nMinRow = min(nMinRow, rData.Ref1.nRow); 1241 nMinRow = min(nMinRow, rData.Ref2.nRow); 1242 1243 nMaxCol = max(nMaxCol, rData.Ref1.nCol); 1244 nMaxCol = max(nMaxCol, rData.Ref2.nCol); 1245 nMaxRow = max(nMaxRow, rData.Ref1.nRow); 1246 nMaxRow = max(nMaxRow, rData.Ref2.nRow); 1247 } 1248 break; 1249 default: 1250 ; 1251 } 1252 } 1253 1254 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol || 1255 nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT || 1256 nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT) 1257 { 1258 // Invalid range. Bail out. 1259 return false; 1260 } 1261 1262 // Check if the following conditions are met: 1263 // 1264 // 1) The upper-left corner cell is not included. 1265 // 2) The three adjacent cells of that corner cell are included. 1266 1267 bool bRight = false, bBottom = false, bDiagonal = false; 1268 for (itr = rRefTokens.begin(); itr != itrEnd; ++itr) 1269 { 1270 pToken = *itr; 1271 switch (pToken->GetType()) 1272 { 1273 case svSingleRef: 1274 case svExternalSingleRef: 1275 { 1276 const ScSingleRefData& rData = pToken->GetSingleRef(); 1277 if (rData.nCol == nMinCol && rData.nRow == nMinRow) 1278 // The corner cell is contained. 1279 return false; 1280 1281 if (rData.nCol == nMinCol+nCornerColumnCount && rData.nRow == nMinRow) 1282 bRight = true; 1283 1284 if (rData.nCol == nMinCol && rData.nRow == nMinRow+nCornerRowCount) 1285 bBottom = true; 1286 1287 if (rData.nCol == nMinCol+nCornerColumnCount && rData.nRow == nMinRow+nCornerRowCount) 1288 bDiagonal = true; 1289 } 1290 break; 1291 case svDoubleRef: 1292 case svExternalDoubleRef: 1293 { 1294 const ScComplexRefData& rData = pToken->GetDoubleRef(); 1295 const ScSingleRefData& r1 = rData.Ref1; 1296 const ScSingleRefData& r2 = rData.Ref2; 1297 if (r1.nCol <= nMinCol && nMinCol <= r2.nCol && 1298 r1.nRow <= nMinRow && nMinRow <= r2.nRow) 1299 // The corner cell is contained. 1300 return false; 1301 1302 if (r1.nCol <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.nCol && 1303 r1.nRow <= nMinRow && nMinRow <= r2.nRow) 1304 bRight = true; 1305 1306 if (r1.nCol <= nMinCol && nMinCol <= r2.nCol && 1307 r1.nRow <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.nRow) 1308 bBottom = true; 1309 1310 if (r1.nCol <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.nCol && 1311 r1.nRow <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.nRow) 1312 bDiagonal = true; 1313 } 1314 break; 1315 default: 1316 ; 1317 } 1318 } 1319 1320 if (!bRight || !bBottom || !bDiagonal) 1321 // Not all the adjacent cells are included. Bail out. 1322 return false; 1323 1324 #if 0 // Do we really need to do this ??? 1325 if (rRefTokens.size() == 2) 1326 { 1327 // Make a simple rectangular range if possible. 1328 ScRange aRightPart(ScAddress(nMinCol+1, nMinRow, nTab), ScAddress(nMaxCol, nMaxRow, nTab)); 1329 ScRange aBottomPart(ScAddress(nMinCol, nMinRow+1, nTab), ScAddress(nMaxCol, nMaxRow, nTab)); 1330 vector<ScRange> aRanges; 1331 aRanges.reserve(2); 1332 aRanges.push_back(aRightPart); 1333 aRanges.push_back(aBottomPart); 1334 if (lcl_isRangeContained(rRefTokens, aRanges)) 1335 { 1336 // Consolidate them into a single rectangle. 1337 ScComplexRefData aData; 1338 aData.InitFlags(); 1339 aData.Ref1.SetFlag3D(true); 1340 aData.Ref1.SetColRel(false); 1341 aData.Ref1.SetRowRel(false); 1342 aData.Ref1.SetTabRel(false); 1343 aData.Ref2.SetColRel(false); 1344 aData.Ref2.SetRowRel(false); 1345 aData.Ref2.SetTabRel(false); 1346 aData.Ref1.nCol = nMinCol; 1347 aData.Ref1.nRow = nMinRow; 1348 aData.Ref1.nTab = nTab; 1349 aData.Ref2.nCol = nMaxCol; 1350 aData.Ref2.nRow = nMaxRow; 1351 aData.Ref2.nTab = nTab; 1352 vector<ScSharedTokenRef> aNewTokens; 1353 aNewTokens.reserve(1); 1354 if (bExternal) 1355 { 1356 ScSharedTokenRef p( 1357 new ScExternalDoubleRefToken(nFileId, aExtTabName, aData)); 1358 aNewTokens.push_back(p); 1359 } 1360 else 1361 { 1362 ScSharedTokenRef p(new ScDoubleRefToken(aData)); 1363 aNewTokens.push_back(p); 1364 } 1365 rRefTokens.swap(aNewTokens); 1366 return true; 1367 } 1368 } 1369 #endif 1370 1371 ScSingleRefData aData; 1372 aData.InitFlags(); 1373 aData.SetFlag3D(true); 1374 aData.SetColRel(false); 1375 aData.SetRowRel(false); 1376 aData.SetTabRel(false); 1377 aData.nCol = nMinCol; 1378 aData.nRow = nMinRow; 1379 aData.nTab = nTab; 1380 1381 if( nCornerRowCount==1 && nCornerColumnCount==1 ) 1382 { 1383 if (bExternal) 1384 { 1385 ScSharedTokenRef pCorner( 1386 new ScExternalSingleRefToken(nFileId, aExtTabName, aData)); 1387 ScRefTokenHelper::join(rRefTokens, pCorner); 1388 } 1389 else 1390 { 1391 ScSharedTokenRef pCorner(new ScSingleRefToken(aData)); 1392 ScRefTokenHelper::join(rRefTokens, pCorner); 1393 } 1394 } 1395 else 1396 { 1397 ScSingleRefData aDataEnd(aData); 1398 aDataEnd.nCol += (nCornerColumnCount-1); 1399 aDataEnd.nRow += (nCornerRowCount-1); 1400 ScComplexRefData r; 1401 r.Ref1=aData; 1402 r.Ref2=aDataEnd; 1403 if (bExternal) 1404 { 1405 ScSharedTokenRef pCorner( 1406 new ScExternalDoubleRefToken(nFileId, aExtTabName, r)); 1407 ScRefTokenHelper::join(rRefTokens, pCorner); 1408 } 1409 else 1410 { 1411 ScSharedTokenRef pCorner(new ScDoubleRefToken(r)); 1412 ScRefTokenHelper::join(rRefTokens, pCorner); 1413 } 1414 } 1415 1416 return true; 1417 } 1418 1419 } 1420 1421 uno::Reference< chart2::data::XDataSource> SAL_CALL 1422 ScChart2DataProvider::createDataSource( 1423 const uno::Sequence< beans::PropertyValue >& aArguments ) 1424 throw( lang::IllegalArgumentException, uno::RuntimeException) 1425 { 1426 ScUnoGuard aGuard; 1427 if ( ! m_pDocument ) 1428 throw uno::RuntimeException(); 1429 1430 uno::Reference< chart2::data::XDataSource> xResult; 1431 bool bLabel = true; 1432 bool bCategories = false; 1433 bool bOrientCol = true; 1434 ::rtl::OUString aRangeRepresentation; 1435 uno::Sequence< sal_Int32 > aSequenceMapping; 1436 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i) 1437 { 1438 rtl::OUString sName(aArguments[i].Name); 1439 if (aArguments[i].Name == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataRowSource"))) 1440 { 1441 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS; 1442 if( ! (aArguments[i].Value >>= eSource)) 1443 { 1444 sal_Int32 nSource(0); 1445 if( aArguments[i].Value >>= nSource ) 1446 eSource = (static_cast< chart::ChartDataRowSource >( nSource )); 1447 } 1448 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS); 1449 } 1450 else if (aArguments[i].Name == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FirstCellAsLabel"))) 1451 { 1452 bLabel = ::cppu::any2bool(aArguments[i].Value); 1453 } 1454 else if (aArguments[i].Name == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("HasCategories"))) 1455 { 1456 bCategories = ::cppu::any2bool(aArguments[i].Value); 1457 } 1458 else if (aArguments[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CellRangeRepresentation"))) 1459 { 1460 aArguments[i].Value >>= aRangeRepresentation; 1461 } 1462 else if (aArguments[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("SequenceMapping"))) 1463 { 1464 aArguments[i].Value >>= aSequenceMapping; 1465 } 1466 } 1467 1468 vector<ScSharedTokenRef> aRefTokens; 1469 ScRefTokenHelper::compileRangeRepresentation(aRefTokens, aRangeRepresentation, m_pDocument, m_pDocument->GetGrammar()); 1470 if (aRefTokens.empty()) 1471 // Invalid range representation. Bail out. 1472 throw lang::IllegalArgumentException(); 1473 1474 if (bLabel) 1475 lcl_addUpperLeftCornerIfMissing(aRefTokens); //#i90669# 1476 1477 bool bColHeaders = (bOrientCol ? bLabel : bCategories ); 1478 bool bRowHeaders = (bOrientCol ? bCategories : bLabel ); 1479 1480 Chart2Positioner aChPositioner(m_pDocument, aRefTokens); 1481 aChPositioner.setHeaders(bColHeaders, bRowHeaders); 1482 1483 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap(); 1484 if (!pChartMap) 1485 // No chart position map instance. Bail out. 1486 return xResult; 1487 1488 ScChart2DataSource* pDS = NULL; 1489 ::std::list< Reference< chart2::data::XLabeledDataSequence > > aSeqs; 1490 1491 // Fill Categories 1492 if( bCategories ) 1493 { 1494 auto_ptr< vector<ScSharedTokenRef> > pValueTokens(NULL); 1495 if (bOrientCol) 1496 pValueTokens.reset(pChartMap->getAllRowHeaderRanges()); 1497 else 1498 pValueTokens.reset(pChartMap->getAllColHeaderRanges()); 1499 1500 auto_ptr< vector<ScSharedTokenRef> > pLabelTokens(NULL); 1501 pLabelTokens.reset(pChartMap->getLeftUpperCornerRanges()); 1502 1503 Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens( 1504 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transfered! 1505 if ( xCategories.is() ) 1506 { 1507 aSeqs.push_back( xCategories ); 1508 } 1509 } 1510 1511 // Fill Serieses (values and label) 1512 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount(); 1513 for (sal_Int32 i = 0; i < nCount; ++i) 1514 { 1515 auto_ptr< vector<ScSharedTokenRef> > pValueTokens(NULL); 1516 auto_ptr< vector<ScSharedTokenRef> > pLabelTokens(NULL); 1517 if (bOrientCol) 1518 { 1519 pValueTokens.reset(pChartMap->getDataColRanges(static_cast<SCCOL>(i))); 1520 pLabelTokens.reset(pChartMap->getColHeaderRanges(static_cast<SCCOL>(i))); 1521 } 1522 else 1523 { 1524 pValueTokens.reset(pChartMap->getDataRowRanges(static_cast<SCROW>(i))); 1525 pLabelTokens.reset(pChartMap->getRowHeaderRanges(static_cast<SCROW>(i))); 1526 } 1527 Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens( 1528 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transfered! 1529 if ( xChartSeries.is() ) 1530 { 1531 aSeqs.push_back( xChartSeries ); 1532 } 1533 } 1534 1535 pDS = new ScChart2DataSource(m_pDocument); 1536 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aItr( aSeqs.begin() ); 1537 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aEndItr( aSeqs.end() ); 1538 1539 //reorder labeled sequences according to aSequenceMapping 1540 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVector; 1541 while(aItr != aEndItr) 1542 { 1543 aSeqVector.push_back(*aItr); 1544 ++aItr; 1545 } 1546 1547 ::std::map< sal_Int32, Reference< chart2::data::XLabeledDataSequence > > aSequenceMap; 1548 for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ ) 1549 { 1550 // note: assuming that the values in the sequence mapping are always non-negative 1551 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ) ); 1552 if( nOldIndex < aSeqVector.size() ) 1553 { 1554 pDS->AddLabeledSequence( aSeqVector[nOldIndex] ); 1555 aSeqVector[nOldIndex] = 0; 1556 } 1557 } 1558 1559 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorItr( aSeqVector.begin() ); 1560 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorEndItr( aSeqVector.end() ); 1561 while(aVectorItr != aVectorEndItr) 1562 { 1563 Reference< chart2::data::XLabeledDataSequence > xSeq( *aVectorItr ); 1564 if ( xSeq.is() ) 1565 { 1566 pDS->AddLabeledSequence( xSeq ); 1567 } 1568 ++aVectorItr; 1569 } 1570 1571 xResult.set( pDS ); 1572 return xResult; 1573 } 1574 1575 namespace 1576 { 1577 1578 /** 1579 * Function object to create a list of table numbers from a token list. 1580 */ 1581 class InsertTabNumber : public unary_function<ScSharedTokenRef, void> 1582 { 1583 public: 1584 InsertTabNumber() : 1585 mpTabNumList(new list<SCTAB>()) 1586 { 1587 } 1588 1589 InsertTabNumber(const InsertTabNumber& r) : 1590 mpTabNumList(r.mpTabNumList) 1591 { 1592 } 1593 1594 void operator() (const ScSharedTokenRef& pToken) const 1595 { 1596 if (!ScRefTokenHelper::isRef(pToken)) 1597 return; 1598 1599 const ScSingleRefData& r = pToken->GetSingleRef(); 1600 mpTabNumList->push_back(r.nTab); 1601 } 1602 1603 void getList(list<SCTAB>& rList) 1604 { 1605 mpTabNumList->swap(rList); 1606 } 1607 private: 1608 shared_ptr< list<SCTAB> > mpTabNumList; 1609 }; 1610 1611 class RangeAnalyzer 1612 { 1613 public: 1614 RangeAnalyzer(); 1615 void initRangeAnalyzer( const vector<ScSharedTokenRef>& rTokens ); 1616 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols, 1617 bool& rbRowSourceAmbiguous ) const; 1618 bool inSameSingleRow( RangeAnalyzer& rOther ); 1619 bool inSameSingleColumn( RangeAnalyzer& rOther ); 1620 SCROW getRowCount() { return mnRowCount; } 1621 SCCOL getColumnCount() { return mnColumnCount; } 1622 1623 private: 1624 bool mbEmpty; 1625 bool mbAmbiguous; 1626 SCROW mnRowCount; 1627 SCCOL mnColumnCount; 1628 1629 SCCOL mnStartColumn; 1630 SCROW mnStartRow; 1631 }; 1632 1633 RangeAnalyzer::RangeAnalyzer() 1634 : mbEmpty(true) 1635 , mbAmbiguous(false) 1636 , mnRowCount(0) 1637 , mnColumnCount(0) 1638 , mnStartColumn(-1) 1639 , mnStartRow(-1) 1640 { 1641 } 1642 1643 void RangeAnalyzer::initRangeAnalyzer( const vector<ScSharedTokenRef>& rTokens ) 1644 { 1645 mnRowCount=0; 1646 mnColumnCount=0; 1647 mnStartColumn = -1; 1648 mnStartRow = -1; 1649 mbAmbiguous=false; 1650 if( rTokens.empty() ) 1651 { 1652 mbEmpty=true; 1653 return; 1654 } 1655 mbEmpty=false; 1656 1657 vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end(); 1658 for (; itr != itrEnd ; ++itr) 1659 { 1660 ScSharedTokenRef aRefToken = *itr; 1661 StackVar eVar = aRefToken->GetType(); 1662 if (eVar == svDoubleRef || eVar == svExternalDoubleRef) 1663 { 1664 const ScComplexRefData& r = aRefToken->GetDoubleRef(); 1665 if (r.Ref1.nTab == r.Ref2.nTab) 1666 { 1667 mnColumnCount = std::max<SCCOL>( mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.nCol - r.Ref1.nCol)+1) ); 1668 mnRowCount = std::max<SCROW>( mnRowCount, static_cast<SCROW>(abs(r.Ref2.nRow - r.Ref1.nRow)+1) ); 1669 if( mnStartColumn == -1 ) 1670 { 1671 mnStartColumn = r.Ref1.nCol; 1672 mnStartRow = r.Ref1.nRow; 1673 } 1674 else 1675 { 1676 if( mnStartColumn != r.Ref1.nCol && mnStartRow != r.Ref1.nRow ) 1677 mbAmbiguous=true; 1678 } 1679 } 1680 else 1681 mbAmbiguous=true; 1682 } 1683 else if (eVar == svSingleRef || eVar == svExternalSingleRef) 1684 { 1685 const ScSingleRefData& r = aRefToken->GetSingleRef(); 1686 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1); 1687 mnRowCount = std::max<SCROW>( mnRowCount, 1); 1688 if( mnStartColumn == -1 ) 1689 { 1690 mnStartColumn = r.nCol; 1691 mnStartRow = r.nRow; 1692 } 1693 else 1694 { 1695 if( mnStartColumn != r.nCol && mnStartRow != r.nRow ) 1696 mbAmbiguous=true; 1697 } 1698 } 1699 else 1700 mbAmbiguous=true; 1701 } 1702 } 1703 1704 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows, 1705 sal_Int32& rnDataInCols, 1706 bool& rbRowSourceAmbiguous ) const 1707 { 1708 if(!mbEmpty && !mbAmbiguous) 1709 { 1710 if( mnRowCount==1 && mnColumnCount>1 ) 1711 ++rnDataInRows; 1712 else if( mnColumnCount==1 && mnRowCount>1 ) 1713 ++rnDataInCols; 1714 else if( mnRowCount>1 && mnColumnCount>1 ) 1715 rbRowSourceAmbiguous = true; 1716 } 1717 else if( !mbEmpty ) 1718 rbRowSourceAmbiguous = true; 1719 } 1720 1721 bool RangeAnalyzer::inSameSingleRow( RangeAnalyzer& rOther ) 1722 { 1723 if( mnStartRow==rOther.mnStartRow && 1724 mnRowCount==1 && rOther.mnRowCount==1 ) 1725 return true; 1726 return false; 1727 } 1728 1729 bool RangeAnalyzer::inSameSingleColumn( RangeAnalyzer& rOther ) 1730 { 1731 if( mnStartColumn==rOther.mnStartColumn && 1732 mnColumnCount==1 && rOther.mnColumnCount==1 ) 1733 return true; 1734 return false; 1735 } 1736 1737 } //end anonymous namespace 1738 1739 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments( 1740 const uno::Reference< chart2::data::XDataSource >& xDataSource ) 1741 throw (uno::RuntimeException) 1742 { 1743 ::std::vector< beans::PropertyValue > aResult; 1744 bool bRowSourceDetected = false; 1745 bool bFirstCellAsLabel = false; 1746 bool bHasCategories = false; 1747 ::rtl::OUString sRangeRep; 1748 1749 bool bHasCategoriesLabels = false; 1750 vector<ScSharedTokenRef> aAllCategoriesValuesTokens; 1751 vector<ScSharedTokenRef> aAllSeriesLabelTokens; 1752 1753 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS; 1754 1755 vector<ScSharedTokenRef> aAllTokens; 1756 1757 // parse given data source and collect infos 1758 { 1759 ScUnoGuard aGuard; 1760 DBG_ASSERT( m_pDocument, "No Document -> no detectArguments" ); 1761 if(!m_pDocument ||!xDataSource.is()) 1762 return lcl_VectorToSequence( aResult ); 1763 1764 sal_Int32 nDataInRows = 0; 1765 sal_Int32 nDataInCols = 0; 1766 bool bRowSourceAmbiguous = false; 1767 1768 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences()); 1769 const sal_Int32 nCount( aSequences.getLength()); 1770 RangeAnalyzer aPrevLabel,aPrevValues; 1771 for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx ) 1772 { 1773 Reference< chart2::data::XLabeledDataSequence > xLS(aSequences[nIdx]); 1774 if( xLS.is() ) 1775 { 1776 bool bThisIsCategories = false; 1777 if(!bHasCategories) 1778 { 1779 Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY ); 1780 ::rtl::OUString aRole; 1781 if( xSeqProp.is() && (xSeqProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Role"))) >>= aRole) && 1782 aRole.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("categories")) ) 1783 bThisIsCategories = bHasCategories = true; 1784 } 1785 1786 RangeAnalyzer aLabel,aValues; 1787 // label 1788 Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel()); 1789 if( xLabel.is()) 1790 { 1791 bFirstCellAsLabel = true; 1792 vector<ScSharedTokenRef> aTokens; 1793 ScRefTokenHelper::compileRangeRepresentation( aTokens, xLabel->getSourceRangeRepresentation(), m_pDocument, m_pDocument->GetGrammar() ); 1794 aLabel.initRangeAnalyzer(aTokens); 1795 vector<ScSharedTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end(); 1796 for (; itr != itrEnd; ++itr) 1797 { 1798 ScRefTokenHelper::join(aAllTokens, *itr); 1799 if(!bThisIsCategories) 1800 ScRefTokenHelper::join(aAllSeriesLabelTokens, *itr); 1801 } 1802 if(bThisIsCategories) 1803 bHasCategoriesLabels=true; 1804 } 1805 // values 1806 Reference< chart2::data::XDataSequence > xValues( xLS->getValues()); 1807 if( xValues.is()) 1808 { 1809 vector<ScSharedTokenRef> aTokens; 1810 ScRefTokenHelper::compileRangeRepresentation( aTokens, xValues->getSourceRangeRepresentation(), m_pDocument, m_pDocument->GetGrammar() ); 1811 aValues.initRangeAnalyzer(aTokens); 1812 vector<ScSharedTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end(); 1813 for (; itr != itrEnd; ++itr) 1814 { 1815 ScRefTokenHelper::join(aAllTokens, *itr); 1816 if(bThisIsCategories) 1817 ScRefTokenHelper::join(aAllCategoriesValuesTokens, *itr); 1818 } 1819 } 1820 //detect row source 1821 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available 1822 { 1823 if (!bRowSourceAmbiguous) 1824 { 1825 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous); 1826 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous); 1827 if (nDataInRows > 1 && nDataInCols > 1) 1828 bRowSourceAmbiguous = true; 1829 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols ) 1830 { 1831 if( aValues.inSameSingleColumn( aLabel ) ) 1832 nDataInCols++; 1833 else if( aValues.inSameSingleRow( aLabel ) ) 1834 nDataInRows++; 1835 else 1836 { 1837 //#i86188# also detect a single column split into rows correctly 1838 if( aValues.inSameSingleColumn( aPrevValues ) ) 1839 nDataInRows++; 1840 else if( aValues.inSameSingleRow( aPrevValues ) ) 1841 nDataInCols++; 1842 else if( aLabel.inSameSingleColumn( aPrevLabel ) ) 1843 nDataInRows++; 1844 else if( aLabel.inSameSingleRow( aPrevLabel ) ) 1845 nDataInCols++; 1846 } 1847 } 1848 } 1849 } 1850 aPrevValues=aValues; 1851 aPrevLabel=aLabel; 1852 } 1853 } 1854 1855 if (!bRowSourceAmbiguous) 1856 { 1857 bRowSourceDetected = true; 1858 eRowSource = ( nDataInRows > 0 1859 ? chart::ChartDataRowSource_ROWS 1860 : chart::ChartDataRowSource_COLUMNS ); 1861 } 1862 else 1863 { 1864 // set DataRowSource to the better of the two ambiguities 1865 eRowSource = ( nDataInRows > nDataInCols 1866 ? chart::ChartDataRowSource_ROWS 1867 : chart::ChartDataRowSource_COLUMNS ); 1868 } 1869 1870 } 1871 1872 // TableNumberList 1873 { 1874 list<SCTAB> aTableNumList; 1875 InsertTabNumber func; 1876 func = for_each(aAllTokens.begin(), aAllTokens.end(), func); 1877 func.getList(aTableNumList); 1878 aResult.push_back( 1879 beans::PropertyValue( ::rtl::OUString::createFromAscii("TableNumberList"), -1, 1880 uno::makeAny( lcl_createTableNumberList( aTableNumList ) ), 1881 beans::PropertyState_DIRECT_VALUE )); 1882 } 1883 1884 // DataRowSource (calculated before) 1885 if( bRowSourceDetected ) 1886 { 1887 aResult.push_back( 1888 beans::PropertyValue( ::rtl::OUString::createFromAscii("DataRowSource"), -1, 1889 uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE )); 1890 } 1891 1892 // HasCategories 1893 if( bRowSourceDetected ) 1894 { 1895 aResult.push_back( 1896 beans::PropertyValue( ::rtl::OUString::createFromAscii("HasCategories"), -1, 1897 uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE )); 1898 } 1899 1900 // FirstCellAsLabel 1901 if( bRowSourceDetected ) 1902 { 1903 aResult.push_back( 1904 beans::PropertyValue( ::rtl::OUString::createFromAscii("FirstCellAsLabel"), -1, 1905 uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE )); 1906 } 1907 1908 // Add the left upper corner to the range if it is missing. 1909 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels ) 1910 { 1911 RangeAnalyzer aTop,aLeft; 1912 if( eRowSource==chart::ChartDataRowSource_COLUMNS ) 1913 { 1914 aTop.initRangeAnalyzer(aAllSeriesLabelTokens); 1915 aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens); 1916 } 1917 else 1918 { 1919 aTop.initRangeAnalyzer(aAllCategoriesValuesTokens); 1920 aLeft.initRangeAnalyzer(aAllSeriesLabelTokens); 1921 } 1922 lcl_addUpperLeftCornerIfMissing(aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212# 1923 } 1924 1925 // Get range string. 1926 lcl_convertTokensToString(sRangeRep, aAllTokens, m_pDocument); 1927 1928 // add cell range property 1929 aResult.push_back( 1930 beans::PropertyValue( ::rtl::OUString::createFromAscii("CellRangeRepresentation"), -1, 1931 uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE )); 1932 1933 //Sequence Mapping 1934 bool bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ... 1935 if( bSequencesReordered && bRowSourceDetected ) 1936 { 1937 bool bDifferentIndexes = false; 1938 1939 std::vector< sal_Int32 > aSequenceMappingVector; 1940 1941 uno::Reference< chart2::data::XDataSource > xCompareDataSource; 1942 try 1943 { 1944 xCompareDataSource.set( this->createDataSource( lcl_VectorToSequence( aResult ) ) ); 1945 } 1946 catch( const lang::IllegalArgumentException & ) 1947 { 1948 // creation of data source to compare didn't work, so we cannot 1949 // create a sequence mapping 1950 } 1951 1952 if( xDataSource.is() && xCompareDataSource.is() ) 1953 { 1954 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aOldSequences( 1955 xCompareDataSource->getDataSequences() ); 1956 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences( 1957 xDataSource->getDataSequences()); 1958 1959 rtl::OUString aOldLabel; 1960 rtl::OUString aNewLabel; 1961 rtl::OUString aOldValues; 1962 rtl::OUString aNewValues; 1963 rtl::OUString aEmpty; 1964 1965 for( sal_Int32 nNewIndex = 0; nNewIndex < aNewSequences.getLength(); nNewIndex++ ) 1966 { 1967 uno::Reference< chart2::data::XLabeledDataSequence> xNew( aNewSequences[nNewIndex] ); 1968 for( sal_Int32 nOldIndex = 0; nOldIndex < aOldSequences.getLength(); nOldIndex++ ) 1969 { 1970 uno::Reference< chart2::data::XLabeledDataSequence> xOld( aOldSequences[nOldIndex] ); 1971 1972 if( xOld.is() && xNew.is() ) 1973 { 1974 aOldLabel = aNewLabel = aOldValues = aNewValues = aEmpty; 1975 if( xOld.is() && xOld->getLabel().is() ) 1976 aOldLabel = xOld->getLabel()->getSourceRangeRepresentation(); 1977 if( xNew.is() && xNew->getLabel().is() ) 1978 aNewLabel = xNew->getLabel()->getSourceRangeRepresentation(); 1979 if( xOld.is() && xOld->getValues().is() ) 1980 aOldValues = xOld->getValues()->getSourceRangeRepresentation(); 1981 if( xNew.is() && xNew->getValues().is() ) 1982 aNewValues = xNew->getValues()->getSourceRangeRepresentation(); 1983 1984 if( aOldLabel.equals(aNewLabel) 1985 && ( aOldValues.equals(aNewValues) ) ) 1986 { 1987 if( nOldIndex!=nNewIndex ) 1988 bDifferentIndexes = true; 1989 aSequenceMappingVector.push_back(nOldIndex); 1990 break; 1991 } 1992 } 1993 } 1994 } 1995 } 1996 1997 if( bDifferentIndexes && aSequenceMappingVector.size() ) 1998 { 1999 aResult.push_back( 2000 beans::PropertyValue( ::rtl::OUString::createFromAscii("SequenceMapping"), -1, 2001 uno::makeAny( lcl_VectorToSequence(aSequenceMappingVector) ) 2002 , beans::PropertyState_DIRECT_VALUE )); 2003 } 2004 } 2005 2006 return lcl_VectorToSequence( aResult ); 2007 } 2008 2009 ::sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const ::rtl::OUString& aRangeRepresentation ) 2010 throw (uno::RuntimeException) 2011 { 2012 ScUnoGuard aGuard; 2013 if( ! m_pDocument ) 2014 return false; 2015 2016 vector<ScSharedTokenRef> aTokens; 2017 ScRefTokenHelper::compileRangeRepresentation(aTokens, aRangeRepresentation, m_pDocument, m_pDocument->GetGrammar()); 2018 return !aTokens.empty(); 2019 } 2020 2021 uno::Reference< chart2::data::XDataSequence > SAL_CALL 2022 ScChart2DataProvider::createDataSequenceByRangeRepresentation( 2023 const ::rtl::OUString& aRangeRepresentation ) 2024 throw (lang::IllegalArgumentException, 2025 uno::RuntimeException) 2026 { 2027 ScUnoGuard aGuard; 2028 uno::Reference< chart2::data::XDataSequence > xResult; 2029 2030 DBG_ASSERT( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" ); 2031 if(!m_pDocument || (aRangeRepresentation.getLength() == 0)) 2032 return xResult; 2033 2034 // Note: the range representation must be in Calc A1 format. The import 2035 // filters use this method to pass data ranges, and they have no idea what 2036 // the current formula syntax is. In the future we should add another 2037 // method to allow the client code to directly pass tokens representing 2038 // ranges. 2039 2040 vector<ScSharedTokenRef> aRefTokens; 2041 ScRefTokenHelper::compileRangeRepresentation(aRefTokens, aRangeRepresentation, m_pDocument); 2042 if (aRefTokens.empty()) 2043 return xResult; 2044 2045 // ScChart2DataSequence manages the life cycle of pRefTokens. 2046 vector<ScSharedTokenRef>* pRefTokens = new vector<ScSharedTokenRef>(); 2047 pRefTokens->swap(aRefTokens); 2048 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells)); 2049 2050 return xResult; 2051 } 2052 2053 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection() 2054 throw (uno::RuntimeException) 2055 { 2056 uno::Reference< sheet::XRangeSelection > xResult; 2057 2058 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument )); 2059 if( xModel.is()) 2060 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY ); 2061 2062 return xResult; 2063 } 2064 2065 /*uno::Reference< util::XNumberFormatsSupplier > SAL_CALL ScChart2DataProvider::getNumberFormatsSupplier() 2066 throw (uno::RuntimeException) 2067 { 2068 return uno::Reference< util::XNumberFormatsSupplier >( lcl_GetXModel( m_pDocument ), uno::UNO_QUERY ); 2069 }*/ 2070 2071 // XRangeXMLConversion --------------------------------------------------- 2072 2073 rtl::OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const rtl::OUString& sRangeRepresentation ) 2074 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 2075 { 2076 OUString aRet; 2077 if (!m_pDocument) 2078 return aRet; 2079 2080 if (!sRangeRepresentation.getLength()) 2081 // Empty data range is allowed. 2082 return aRet; 2083 2084 vector<ScSharedTokenRef> aRefTokens; 2085 ScRefTokenHelper::compileRangeRepresentation(aRefTokens, sRangeRepresentation, m_pDocument, m_pDocument->GetGrammar()); 2086 if (aRefTokens.empty()) 2087 throw lang::IllegalArgumentException(); 2088 2089 Tokens2RangeStringXML converter(m_pDocument); 2090 converter = for_each(aRefTokens.begin(), aRefTokens.end(), converter); 2091 converter.getString(aRet); 2092 2093 return aRet; 2094 } 2095 2096 rtl::OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const rtl::OUString& sXMLRange ) 2097 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 2098 { 2099 const sal_Unicode cSep = ' '; 2100 const sal_Unicode cQuote = '\''; 2101 2102 if (!m_pDocument) 2103 { 2104 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document, 2105 // so the conversion has to take place directly with the strings, without looking up the sheets. 2106 2107 rtl::OUStringBuffer sRet; 2108 sal_Int32 nOffset = 0; 2109 while( nOffset >= 0 ) 2110 { 2111 rtl::OUString sToken; 2112 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote ); 2113 if( nOffset >= 0 ) 2114 { 2115 // convert one address (remove dots) 2116 2117 String aUIString(sToken); 2118 2119 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote ); 2120 if ( nIndex >= 0 && nIndex < aUIString.Len() - 1 && 2121 aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' ) 2122 aUIString.Erase( (xub_StrLen)nIndex + 1, 1 ); 2123 2124 if ( aUIString.GetChar(0) == (sal_Unicode) '.' ) 2125 aUIString.Erase( 0, 1 ); 2126 2127 if( sRet.getLength() ) 2128 sRet.append( (sal_Unicode) ';' ); 2129 sRet.append( aUIString ); 2130 } 2131 } 2132 2133 return sRet.makeStringAndClear(); 2134 } 2135 2136 OUString aRet; 2137 ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument); 2138 return aRet; 2139 } 2140 2141 // DataProvider XPropertySet ------------------------------------------------- 2142 2143 uno::Reference< beans::XPropertySetInfo> SAL_CALL 2144 ScChart2DataProvider::getPropertySetInfo() throw( uno::RuntimeException) 2145 { 2146 ScUnoGuard aGuard; 2147 static uno::Reference<beans::XPropertySetInfo> aRef = 2148 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() ); 2149 return aRef; 2150 } 2151 2152 2153 void SAL_CALL ScChart2DataProvider::setPropertyValue( 2154 const ::rtl::OUString& rPropertyName, const uno::Any& rValue) 2155 throw( beans::UnknownPropertyException, 2156 beans::PropertyVetoException, 2157 lang::IllegalArgumentException, 2158 lang::WrappedTargetException, uno::RuntimeException) 2159 { 2160 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 2161 { 2162 if ( !(rValue >>= m_bIncludeHiddenCells)) 2163 throw lang::IllegalArgumentException(); 2164 } 2165 else 2166 throw beans::UnknownPropertyException(); 2167 } 2168 2169 2170 uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue( 2171 const ::rtl::OUString& rPropertyName) 2172 throw( beans::UnknownPropertyException, 2173 lang::WrappedTargetException, uno::RuntimeException) 2174 { 2175 uno::Any aRet; 2176 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 2177 aRet <<= m_bIncludeHiddenCells; 2178 else 2179 throw beans::UnknownPropertyException(); 2180 return aRet; 2181 } 2182 2183 2184 void SAL_CALL ScChart2DataProvider::addPropertyChangeListener( 2185 const ::rtl::OUString& /*rPropertyName*/, 2186 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/) 2187 throw( beans::UnknownPropertyException, 2188 lang::WrappedTargetException, uno::RuntimeException) 2189 { 2190 OSL_ENSURE( false, "Not yet implemented" ); 2191 } 2192 2193 2194 void SAL_CALL ScChart2DataProvider::removePropertyChangeListener( 2195 const ::rtl::OUString& /*rPropertyName*/, 2196 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/) 2197 throw( beans::UnknownPropertyException, 2198 lang::WrappedTargetException, uno::RuntimeException) 2199 { 2200 OSL_ENSURE( false, "Not yet implemented" ); 2201 } 2202 2203 2204 void SAL_CALL ScChart2DataProvider::addVetoableChangeListener( 2205 const ::rtl::OUString& /*rPropertyName*/, 2206 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/) 2207 throw( beans::UnknownPropertyException, 2208 lang::WrappedTargetException, uno::RuntimeException) 2209 { 2210 OSL_ENSURE( false, "Not yet implemented" ); 2211 } 2212 2213 2214 void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener( 2215 const ::rtl::OUString& /*rPropertyName*/, 2216 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ ) 2217 throw( beans::UnknownPropertyException, 2218 lang::WrappedTargetException, uno::RuntimeException) 2219 { 2220 OSL_ENSURE( false, "Not yet implemented" ); 2221 } 2222 2223 // DataSource ================================================================ 2224 2225 ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc) 2226 : m_pDocument( pDoc) 2227 { 2228 if ( m_pDocument ) 2229 m_pDocument->AddUnoObject( *this); 2230 } 2231 2232 2233 ScChart2DataSource::~ScChart2DataSource() 2234 { 2235 if ( m_pDocument ) 2236 m_pDocument->RemoveUnoObject( *this); 2237 } 2238 2239 2240 void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint) 2241 { 2242 if ( rHint.ISA( SfxSimpleHint ) && 2243 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 2244 { 2245 m_pDocument = NULL; 2246 } 2247 } 2248 2249 2250 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL 2251 ScChart2DataSource::getDataSequences() throw ( uno::RuntimeException) 2252 { 2253 ScUnoGuard aGuard; 2254 2255 LabeledList::const_iterator aItr(m_aLabeledSequences.begin()); 2256 LabeledList::const_iterator aEndItr(m_aLabeledSequences.end()); 2257 2258 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aRet(m_aLabeledSequences.size()); 2259 2260 sal_Int32 i = 0; 2261 while (aItr != aEndItr) 2262 { 2263 aRet[i] = *aItr; 2264 ++i; 2265 ++aItr; 2266 } 2267 2268 return aRet; 2269 2270 /* typedef ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > tVec; 2271 tVec aVec; 2272 bool bSeries = false; 2273 // split into columns - FIXME: different if GlueState() is used 2274 for ( ScRangePtr p = m_xRanges->First(); p; p = m_xRanges->Next()) 2275 { 2276 for ( SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol) 2277 { 2278 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( 2279 new ScChart2LabeledDataSequence( m_pDocument)); 2280 if( xLabeledSeq.is()) 2281 { 2282 aVec.push_back( xLabeledSeq ); 2283 if( bSeries ) 2284 { 2285 ScRangeListRef aColRanges = new ScRangeList; 2286 // one single sheet selected assumed for now 2287 aColRanges->Append( ScRange( nCol, p->aStart.Row(), 2288 p->aStart.Tab(), nCol, p->aStart.Row(), 2289 p->aStart.Tab())); 2290 // TEST: add range two times, once as label, once as data 2291 // TODO: create pure Numerical and Text sequences if possible 2292 uno::Reference< chart2::data::XDataSequence > xLabel( 2293 new ScChart2DataSequence( m_pDocument, aColRanges)); 2294 2295 // set role 2296 uno::Reference< beans::XPropertySet > xProp( xLabel, uno::UNO_QUERY ); 2297 if( xProp.is()) 2298 xProp->setPropertyValue( 2299 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )), 2300 ::uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "label" )))); 2301 2302 xLabeledSeq->setLabel( xLabel ); 2303 } 2304 2305 ScRangeListRef aColRanges = new ScRangeList; 2306 2307 // one single sheet selected assumed for now 2308 aColRanges->Append( ScRange( nCol, p->aStart.Row() + 1, 2309 p->aStart.Tab(), nCol, p->aEnd.Row(), 2310 p->aStart.Tab())); 2311 uno::Reference< chart2::data::XDataSequence > xData( 2312 new ScChart2DataSequence( m_pDocument, aColRanges)); 2313 2314 // set role 2315 uno::Reference< beans::XPropertySet > xProp( xData, uno::UNO_QUERY ); 2316 if( xProp.is()) 2317 xProp->setPropertyValue( 2318 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )), 2319 ::uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "values" )))); 2320 2321 xLabeledSeq->setValues( xData ); 2322 2323 bSeries = true; 2324 } 2325 } 2326 } 2327 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aSequences( 2328 aVec.size()); 2329 uno::Reference< chart2::data::XLabeledDataSequence> * pArr = aSequences.getArray(); 2330 sal_Int32 j = 0; 2331 for ( tVec::const_iterator iSeq = aVec.begin(); iSeq != aVec.end(); 2332 ++iSeq, ++j) 2333 { 2334 pArr[j] = *iSeq; 2335 } 2336 return aSequences;*/ 2337 } 2338 2339 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew) 2340 { 2341 m_aLabeledSequences.push_back(xNew); 2342 } 2343 2344 2345 // DataSequence ============================================================== 2346 2347 ScChart2DataSequence::Item::Item() : 2348 mfValue(0.0), mbIsValue(false) 2349 { 2350 ::rtl::math::setNan(&mfValue); 2351 } 2352 2353 ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) : 2354 mrParent(rParent) 2355 { 2356 } 2357 2358 ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener() 2359 { 2360 } 2361 2362 void ScChart2DataSequence::HiddenRangeListener::notify() 2363 { 2364 mrParent.setDataChangedHint(true); 2365 } 2366 2367 ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc, 2368 const uno::Reference < chart2::data::XDataProvider >& xDP, 2369 vector<ScSharedTokenRef>* pTokens, 2370 bool bIncludeHiddenCells ) 2371 : m_bIncludeHiddenCells( bIncludeHiddenCells) 2372 , m_nObjectId( 0 ) 2373 , m_pDocument( pDoc) 2374 , m_pTokens(pTokens) 2375 , m_pRangeIndices(NULL) 2376 , m_pExtRefListener(NULL) 2377 , m_xDataProvider( xDP) 2378 , m_aPropSet(lcl_GetDataSequencePropertyMap()) 2379 , m_pHiddenListener(NULL) 2380 , m_pValueListener( NULL ) 2381 , m_bGotDataChangedHint(false) 2382 , m_bExtDataRebuildQueued(false) 2383 { 2384 DBG_ASSERT(pTokens, "reference token list is null"); 2385 2386 if ( m_pDocument ) 2387 { 2388 m_pDocument->AddUnoObject( *this); 2389 m_nObjectId = m_pDocument->GetNewUnoId(); 2390 } 2391 // FIXME: real implementation of identifier and it's mapping to ranges. 2392 // Reuse ScChartListener? 2393 2394 // BM: don't use names of named ranges but the UI range strings 2395 // String aStr; 2396 // rRangeList->Format( aStr, SCR_ABS_3D, m_pDocument ); 2397 // m_aIdentifier = ::rtl::OUString( aStr ); 2398 2399 // m_aIdentifier = ::rtl::OUString::createFromAscii( "ID_"); 2400 // static sal_Int32 nID = 0; 2401 // m_aIdentifier += ::rtl::OUString::valueOf( ++nID); 2402 } 2403 2404 ScChart2DataSequence::~ScChart2DataSequence() 2405 { 2406 if ( m_pDocument ) 2407 { 2408 m_pDocument->RemoveUnoObject( *this); 2409 if (m_pHiddenListener.get()) 2410 { 2411 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection(); 2412 if (pCLC) 2413 pCLC->EndListeningHiddenRange(m_pHiddenListener.get()); 2414 } 2415 StopListeningToAllExternalRefs(); 2416 } 2417 2418 delete m_pValueListener; 2419 } 2420 2421 void ScChart2DataSequence::RefChanged() 2422 { 2423 if( m_pValueListener && m_aValueListeners.Count() != 0 ) 2424 { 2425 m_pValueListener->EndListeningAll(); 2426 2427 if( m_pDocument ) 2428 { 2429 ScChartListenerCollection* pCLC = NULL; 2430 if (m_pHiddenListener.get()) 2431 { 2432 pCLC = m_pDocument->GetChartListenerCollection(); 2433 if (pCLC) 2434 pCLC->EndListeningHiddenRange(m_pHiddenListener.get()); 2435 } 2436 2437 vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end(); 2438 for (; itr != itrEnd; ++itr) 2439 { 2440 ScRange aRange; 2441 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr)) 2442 continue; 2443 2444 m_pDocument->StartListeningArea(aRange, m_pValueListener); 2445 if (pCLC) 2446 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get()); 2447 } 2448 } 2449 } 2450 } 2451 2452 void ScChart2DataSequence::BuildDataCache() 2453 { 2454 m_bExtDataRebuildQueued = false; 2455 2456 if (!m_aDataArray.empty()) 2457 return; 2458 2459 if (!m_pTokens.get()) 2460 { 2461 DBG_ERROR("m_pTokens == NULL! Something is wrong."); 2462 return; 2463 } 2464 2465 StopListeningToAllExternalRefs(); 2466 2467 ::std::list<sal_Int32> aHiddenValues; 2468 sal_Int32 nDataCount = 0; 2469 sal_Int32 nHiddenValueCount = 0; 2470 2471 for (vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end(); 2472 itr != itrEnd; ++itr) 2473 { 2474 if (ScRefTokenHelper::isExternalRef(*itr)) 2475 { 2476 nDataCount += FillCacheFromExternalRef(*itr); 2477 } 2478 else 2479 { 2480 ScRange aRange; 2481 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr)) 2482 continue; 2483 2484 SCCOL nLastCol = -1; 2485 SCROW nLastRow = -1; 2486 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab) 2487 { 2488 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol) 2489 { 2490 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow) 2491 { 2492 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nLastCol); 2493 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nLastRow); 2494 2495 if (bColHidden || bRowHidden) 2496 { 2497 // hidden cell 2498 ++nHiddenValueCount; 2499 aHiddenValues.push_back(nDataCount-1); 2500 2501 if( !m_bIncludeHiddenCells ) 2502 continue; 2503 } 2504 2505 m_aDataArray.push_back(Item()); 2506 Item& rItem = m_aDataArray.back(); 2507 ++nDataCount; 2508 2509 ScAddress aAdr(nCol, nRow, nTab); 2510 ScBaseCell* pCell = m_pDocument->GetCell(aAdr); 2511 if (!pCell) 2512 continue; 2513 2514 if (pCell->HasStringData()) 2515 rItem.maString = pCell->GetStringData(); 2516 else 2517 { 2518 String aStr; 2519 m_pDocument->GetString(nCol, nRow, nTab, aStr); 2520 rItem.maString = aStr; 2521 } 2522 2523 switch (pCell->GetCellType()) 2524 { 2525 case CELLTYPE_VALUE: 2526 rItem.mfValue = static_cast< ScValueCell*>(pCell)->GetValue(); 2527 rItem.mbIsValue = true; 2528 break; 2529 case CELLTYPE_FORMULA: 2530 { 2531 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); 2532 sal_uInt16 nErr = pFCell->GetErrCode(); 2533 if (nErr) 2534 break; 2535 2536 if (pFCell->HasValueData()) 2537 { 2538 rItem.mfValue = pFCell->GetValue(); 2539 rItem.mbIsValue = true; 2540 } 2541 } 2542 break; 2543 #if DBG_UTIL 2544 case CELLTYPE_DESTROYED: 2545 #endif 2546 case CELLTYPE_EDIT: 2547 case CELLTYPE_NONE: 2548 case CELLTYPE_NOTE: 2549 case CELLTYPE_STRING: 2550 case CELLTYPE_SYMBOLS: 2551 default: 2552 ; // do nothing 2553 } 2554 } 2555 } 2556 } 2557 } 2558 } 2559 2560 // convert the hidden cell list to sequence. 2561 m_aHiddenValues.realloc(nHiddenValueCount); 2562 sal_Int32* pArr = m_aHiddenValues.getArray(); 2563 ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end(); 2564 for (;itr != itrEnd; ++itr, ++pArr) 2565 *pArr = *itr; 2566 2567 // Clear the data series cache when the array is re-built. 2568 m_aMixedDataCache.realloc(0); 2569 } 2570 2571 void ScChart2DataSequence::RebuildDataCache() 2572 { 2573 if (!m_bExtDataRebuildQueued) 2574 { 2575 m_aDataArray.clear(); 2576 m_pDocument->BroadcastUno(ScHint(SC_HINT_DATACHANGED, ScAddress(), NULL)); 2577 m_bExtDataRebuildQueued = true; 2578 m_bGotDataChangedHint = true; 2579 } 2580 } 2581 2582 sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScSharedTokenRef& pToken) 2583 { 2584 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager(); 2585 ScRange aRange; 2586 if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken, true)) 2587 return 0; 2588 2589 sal_uInt16 nFileId = pToken->GetIndex(); 2590 const String& rTabName = pToken->GetString(); 2591 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, aRange, NULL); 2592 if (!pArray) 2593 // no external data exists for this range. 2594 return 0; 2595 2596 // Start listening for this external document. 2597 ExternalRefListener* pExtRefListener = GetExtRefListener(); 2598 pRefMgr->addLinkListener(nFileId, pExtRefListener); 2599 pExtRefListener->addFileId(nFileId); 2600 2601 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, rTabName, false, NULL); 2602 sal_Int32 nDataCount = 0; 2603 for (FormulaToken* p = pArray->First(); p; p = pArray->Next()) 2604 { 2605 // Cached external range is always represented as a single 2606 // matrix token, although that might change in the future when 2607 // we introduce a new token type to store multi-table range 2608 // data. 2609 2610 if (p->GetType() != svMatrix) 2611 { 2612 DBG_ERROR("Cached array is not a matrix token."); 2613 continue; 2614 } 2615 2616 const ScMatrix* pMat = static_cast<ScToken*>(p)->GetMatrix(); 2617 SCSIZE nCSize, nRSize; 2618 pMat->GetDimensions(nCSize, nRSize); 2619 for (SCSIZE nC = 0; nC < nCSize; ++nC) 2620 { 2621 for (SCSIZE nR = 0; nR < nRSize; ++nR) 2622 { 2623 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR)) 2624 { 2625 m_aDataArray.push_back(Item()); 2626 Item& rItem = m_aDataArray.back(); 2627 ++nDataCount; 2628 2629 rItem.mbIsValue = true; 2630 rItem.mfValue = pMat->GetDouble(nC, nR); 2631 2632 SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable(); 2633 if (pFormatter) 2634 { 2635 String aStr; 2636 const double fVal = rItem.mfValue; 2637 Color* pColor = NULL; 2638 sal_uInt32 nFmt = 0; 2639 if (pTable) 2640 { 2641 // Get the correct format index from the cache. 2642 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC); 2643 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR); 2644 pTable->getCell(nCol, nRow, &nFmt); 2645 } 2646 pFormatter->GetOutputString(fVal, nFmt, aStr, &pColor); 2647 rItem.maString = aStr; 2648 } 2649 } 2650 else if (pMat->IsString(nC, nR)) 2651 { 2652 m_aDataArray.push_back(Item()); 2653 Item& rItem = m_aDataArray.back(); 2654 ++nDataCount; 2655 2656 rItem.mbIsValue = false; 2657 rItem.maString = pMat->GetString(nC, nR); 2658 } 2659 } 2660 } 2661 } 2662 return nDataCount; 2663 } 2664 2665 void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges) 2666 { 2667 if (!m_pRangeIndices.get()) 2668 return; 2669 2670 sal_uInt32 nCount = rRanges.Count(); 2671 for (sal_uInt32 i = 0; i < nCount; ++i) 2672 { 2673 ScSharedTokenRef pToken; 2674 ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i)); 2675 DBG_ASSERT(pRange, "range object is NULL."); 2676 2677 ScRefTokenHelper::getTokenFromRange(pToken, *pRange); 2678 sal_uInt32 nOrigPos = (*m_pRangeIndices)[i]; 2679 (*m_pTokens)[nOrigPos] = pToken; 2680 } 2681 2682 RefChanged(); 2683 2684 // any change of the range address is broadcast to value (modify) listeners 2685 if ( m_aValueListeners.Count() ) 2686 m_bGotDataChangedHint = true; 2687 } 2688 2689 ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener() 2690 { 2691 if (!m_pExtRefListener.get()) 2692 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument)); 2693 2694 return m_pExtRefListener.get(); 2695 } 2696 2697 void ScChart2DataSequence::StopListeningToAllExternalRefs() 2698 { 2699 if (!m_pExtRefListener.get()) 2700 return; 2701 2702 const hash_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds(); 2703 hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end(); 2704 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager(); 2705 for (; itr != itrEnd; ++itr) 2706 pRefMgr->removeLinkListener(*itr, m_pExtRefListener.get()); 2707 2708 m_pExtRefListener.reset(NULL); 2709 } 2710 2711 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r) 2712 { 2713 if (!m_pDocument) 2714 { 2715 DBG_ERROR("document instance is NULL!?"); 2716 return; 2717 } 2718 2719 list<Item> aDataArray(r.m_aDataArray); 2720 m_aDataArray.swap(aDataArray); 2721 2722 m_aHiddenValues = r.m_aHiddenValues; 2723 m_aRole = r.m_aRole; 2724 2725 if (r.m_pRangeIndices.get()) 2726 m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices)); 2727 2728 if (r.m_pExtRefListener.get()) 2729 { 2730 // Re-register all external files that the old instance was 2731 // listening to. 2732 2733 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager(); 2734 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument)); 2735 const hash_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds(); 2736 hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end(); 2737 for (; itr != itrEnd; ++itr) 2738 { 2739 pRefMgr->addLinkListener(*itr, m_pExtRefListener.get()); 2740 m_pExtRefListener->addFileId(*itr); 2741 } 2742 } 2743 } 2744 2745 void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint) 2746 { 2747 if ( rHint.ISA( SfxSimpleHint ) ) 2748 { 2749 sal_uLong nId = static_cast<const SfxSimpleHint&>(rHint).GetId(); 2750 if ( nId ==SFX_HINT_DYING ) 2751 { 2752 m_pDocument = NULL; 2753 } 2754 else if ( nId == SFX_HINT_DATACHANGED ) 2755 { 2756 // delayed broadcast as in ScCellRangesBase 2757 2758 if ( m_bGotDataChangedHint && m_pDocument ) 2759 { 2760 m_aDataArray.clear(); 2761 lang::EventObject aEvent; 2762 aEvent.Source.set((cppu::OWeakObject*)this); 2763 2764 if( m_pDocument ) 2765 { 2766 for ( sal_uInt16 n=0; n<m_aValueListeners.Count(); n++ ) 2767 m_pDocument->AddUnoListenerCall( *m_aValueListeners[n], aEvent ); 2768 } 2769 2770 m_bGotDataChangedHint = false; 2771 } 2772 } 2773 else if ( nId == SC_HINT_CALCALL ) 2774 { 2775 // broadcast from DoHardRecalc - set m_bGotDataChangedHint 2776 // (SFX_HINT_DATACHANGED follows separately) 2777 2778 if ( m_aValueListeners.Count() ) 2779 m_bGotDataChangedHint = true; 2780 } 2781 } 2782 else if ( rHint.ISA( ScUpdateRefHint ) ) 2783 { 2784 // Create a range list from the token list, have the range list 2785 // updated, and bring the change back to the token list. 2786 2787 ScRangeList aRanges; 2788 m_pRangeIndices.reset(new vector<sal_uInt32>()); 2789 vector<ScSharedTokenRef>::const_iterator itrBeg = m_pTokens->begin(), itrEnd = m_pTokens->end(); 2790 for (vector<ScSharedTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr) 2791 { 2792 if (!ScRefTokenHelper::isExternalRef(*itr)) 2793 { 2794 ScRange aRange; 2795 ScRefTokenHelper::getRangeFromToken(aRange, *itr); 2796 aRanges.Append(aRange); 2797 sal_uInt32 nPos = distance(itrBeg, itr); 2798 m_pRangeIndices->push_back(nPos); 2799 } 2800 } 2801 2802 DBG_ASSERT(m_pRangeIndices->size() == static_cast<size_t>(aRanges.Count()), 2803 "range list and range index list have different sizes."); 2804 2805 auto_ptr<ScRangeList> pUndoRanges; 2806 if ( m_pDocument->HasUnoRefUndo() ) 2807 pUndoRanges.reset(new ScRangeList(aRanges)); 2808 2809 const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint; 2810 bool bChanged = aRanges.UpdateReference( 2811 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz()); 2812 2813 if (bChanged) 2814 { 2815 DBG_ASSERT(m_pRangeIndices->size() == static_cast<size_t>(aRanges.Count()), 2816 "range list and range index list have different sizes after the reference update."); 2817 2818 // Bring the change back from the range list to the token list. 2819 UpdateTokensFromRanges(aRanges); 2820 2821 if (pUndoRanges.get()) 2822 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges); 2823 } 2824 } 2825 else if ( rHint.ISA( ScUnoRefUndoHint ) ) 2826 { 2827 const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint); 2828 2829 do 2830 { 2831 if (rUndoHint.GetObjectId() != m_nObjectId) 2832 break; 2833 2834 // The hint object provides the old ranges. Restore the old state 2835 // from these ranges. 2836 2837 if (!m_pRangeIndices.get() || m_pRangeIndices->empty()) 2838 { 2839 DBG_ERROR(" faulty range indices"); 2840 break; 2841 } 2842 2843 const ScRangeList& rRanges = rUndoHint.GetRanges(); 2844 2845 sal_uInt32 nCount = rRanges.Count(); 2846 if (nCount != m_pRangeIndices->size()) 2847 { 2848 DBG_ERROR("range count and range index count differ."); 2849 break; 2850 } 2851 2852 UpdateTokensFromRanges(rRanges); 2853 } 2854 while (false); 2855 } 2856 } 2857 2858 2859 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint ) 2860 { 2861 if ( m_pDocument && pHint && pHint->ISA( SfxSimpleHint ) && 2862 ((const SfxSimpleHint*)pHint)->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING) ) 2863 { 2864 // This may be called several times for a single change, if several formulas 2865 // in the range are notified. So only a flag is set that is checked when 2866 // SFX_HINT_DATACHANGED is received. 2867 2868 setDataChangedHint(true); 2869 } 2870 return 0; 2871 } 2872 2873 // ---------------------------------------------------------------------------- 2874 2875 ScChart2DataSequence::ExternalRefListener::ExternalRefListener( 2876 ScChart2DataSequence& rParent, ScDocument* pDoc) : 2877 ScExternalRefManager::LinkListener(), 2878 mrParent(rParent), 2879 mpDoc(pDoc) 2880 { 2881 } 2882 2883 ScChart2DataSequence::ExternalRefListener::~ExternalRefListener() 2884 { 2885 if (!mpDoc || mpDoc->IsInDtorClear()) 2886 // The document is being destroyed. Do nothing. 2887 return; 2888 2889 // Make sure to remove all pointers to this object. 2890 mpDoc->GetExternalRefManager()->removeLinkListener(this); 2891 } 2892 2893 void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) 2894 { 2895 switch (eType) 2896 { 2897 case ScExternalRefManager::LINK_MODIFIED: 2898 { 2899 if (maFileIds.count(nFileId)) 2900 // We are listening to this external document. 2901 mrParent.RebuildDataCache(); 2902 } 2903 break; 2904 case ScExternalRefManager::LINK_BROKEN: 2905 removeFileId(nFileId); 2906 break; 2907 } 2908 } 2909 2910 void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId) 2911 { 2912 maFileIds.insert(nFileId); 2913 } 2914 2915 void ScChart2DataSequence::ExternalRefListener::removeFileId(sal_uInt16 nFileId) 2916 { 2917 maFileIds.erase(nFileId); 2918 } 2919 2920 const hash_set<sal_uInt16>& ScChart2DataSequence::ExternalRefListener::getAllFileIds() 2921 { 2922 return maFileIds; 2923 } 2924 2925 // ---------------------------------------------------------------------------- 2926 2927 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData() 2928 throw ( uno::RuntimeException) 2929 { 2930 ScUnoGuard aGuard; 2931 if ( !m_pDocument) 2932 throw uno::RuntimeException(); 2933 2934 BuildDataCache(); 2935 2936 if (!m_aMixedDataCache.getLength()) 2937 { 2938 // Build a cache for the 1st time... 2939 2940 sal_Int32 nCount = m_aDataArray.size(); 2941 m_aMixedDataCache.realloc(nCount); 2942 uno::Any* pArr = m_aMixedDataCache.getArray(); 2943 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end(); 2944 for (; itr != itrEnd; ++itr, ++pArr) 2945 { 2946 if (itr->mbIsValue) 2947 *pArr <<= itr->mfValue; 2948 else 2949 *pArr <<= itr->maString; 2950 } 2951 } 2952 return m_aMixedDataCache; 2953 } 2954 2955 // XNumericalDataSequence -------------------------------------------------- 2956 2957 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData() 2958 throw ( uno::RuntimeException) 2959 { 2960 ScUnoGuard aGuard; 2961 if ( !m_pDocument) 2962 throw uno::RuntimeException(); 2963 2964 BuildDataCache(); 2965 2966 double fNAN; 2967 ::rtl::math::setNan(&fNAN); 2968 2969 sal_Int32 nCount = m_aDataArray.size(); 2970 uno::Sequence<double> aSeq(nCount); 2971 double* pArr = aSeq.getArray(); 2972 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end(); 2973 for (; itr != itrEnd; ++itr, ++pArr) 2974 *pArr = itr->mbIsValue ? itr->mfValue : fNAN; 2975 2976 return aSeq; 2977 } 2978 2979 // XTextualDataSequence -------------------------------------------------- 2980 2981 uno::Sequence< rtl::OUString > SAL_CALL ScChart2DataSequence::getTextualData( ) throw (uno::RuntimeException) 2982 { 2983 ScUnoGuard aGuard; 2984 if ( !m_pDocument) 2985 throw uno::RuntimeException(); 2986 2987 BuildDataCache(); 2988 2989 sal_Int32 nCount = m_aDataArray.size(); 2990 uno::Sequence<rtl::OUString> aSeq(nCount); 2991 rtl::OUString* pArr = aSeq.getArray(); 2992 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end(); 2993 for (; itr != itrEnd; ++itr, ++pArr) 2994 *pArr = itr->maString; 2995 2996 return aSeq; 2997 } 2998 2999 ::rtl::OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation() 3000 throw ( uno::RuntimeException) 3001 { 3002 ScUnoGuard aGuard; 3003 OUString aStr; 3004 DBG_ASSERT( m_pDocument, "No Document -> no SourceRangeRepresentation" ); 3005 if (m_pDocument && m_pTokens.get()) 3006 lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument); 3007 3008 return aStr; 3009 } 3010 3011 namespace { 3012 3013 /** 3014 * This function object is used to accumulatively count the numbers of 3015 * columns and rows in all reference tokens. 3016 */ 3017 class AccumulateRangeSize : public unary_function<ScSharedTokenRef, void> 3018 { 3019 public: 3020 AccumulateRangeSize() : 3021 mnCols(0), mnRows(0) {} 3022 3023 AccumulateRangeSize(const AccumulateRangeSize& r) : 3024 mnCols(r.mnCols), mnRows(r.mnRows) {} 3025 3026 void operator() (const ScSharedTokenRef& pToken) 3027 { 3028 ScRange r; 3029 bool bExternal = ScRefTokenHelper::isExternalRef(pToken); 3030 ScRefTokenHelper::getRangeFromToken(r, pToken, bExternal); 3031 r.Justify(); 3032 mnCols += r.aEnd.Col() - r.aStart.Col() + 1; 3033 mnRows += r.aEnd.Row() - r.aStart.Row() + 1; 3034 } 3035 3036 SCCOL getCols() const { return mnCols; } 3037 SCROW getRows() const { return mnRows; } 3038 private: 3039 SCCOL mnCols; 3040 SCROW mnRows; 3041 }; 3042 3043 /** 3044 * This function object is used to generate label strings from a list of 3045 * reference tokens. 3046 */ 3047 class GenerateLabelStrings : public unary_function<ScSharedTokenRef, void> 3048 { 3049 public: 3050 GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) : 3051 mpLabels(new Sequence<OUString>(nSize)), 3052 meOrigin(eOrigin), 3053 mnCount(0), 3054 mbColumn(bColumn) {} 3055 3056 GenerateLabelStrings(const GenerateLabelStrings& r) : 3057 mpLabels(r.mpLabels), 3058 meOrigin(r.meOrigin), 3059 mnCount(r.mnCount), 3060 mbColumn(r.mbColumn) {} 3061 3062 void operator() (const ScSharedTokenRef& pToken) 3063 { 3064 bool bExternal = ScRefTokenHelper::isExternalRef(pToken); 3065 ScRange aRange; 3066 ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal); 3067 OUString* pArr = mpLabels->getArray(); 3068 if (mbColumn) 3069 { 3070 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol) 3071 { 3072 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE) 3073 { 3074 String aString = ScGlobal::GetRscString(STR_COLUMN); 3075 aString += ' '; 3076 ScAddress aPos( nCol, 0, 0 ); 3077 String aColStr; 3078 aPos.Format( aColStr, SCA_VALID_COL, NULL ); 3079 aString += aColStr; 3080 pArr[mnCount] = aString; 3081 } 3082 else //only indices for categories 3083 pArr[mnCount] = String::CreateFromInt32( mnCount+1 ); 3084 ++mnCount; 3085 } 3086 } 3087 else 3088 { 3089 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow) 3090 { 3091 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE) 3092 { 3093 String aString = ScGlobal::GetRscString(STR_ROW); 3094 aString += ' '; 3095 aString += String::CreateFromInt32( nRow+1 ); 3096 pArr[mnCount] = aString; 3097 } 3098 else //only indices for categories 3099 pArr[mnCount] = String::CreateFromInt32( mnCount+1 ); 3100 ++mnCount; 3101 } 3102 } 3103 } 3104 3105 Sequence<OUString> getLabels() const { return *mpLabels; } 3106 3107 private: 3108 GenerateLabelStrings(); // disabled 3109 3110 shared_ptr< Sequence<OUString> > mpLabels; 3111 chart2::data::LabelOrigin meOrigin; 3112 sal_Int32 mnCount; 3113 bool mbColumn; 3114 }; 3115 3116 } 3117 3118 uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin) 3119 throw (uno::RuntimeException) 3120 { 3121 ScUnoGuard aGuard; 3122 if ( !m_pDocument) 3123 throw uno::RuntimeException(); 3124 3125 if (!m_pTokens.get()) 3126 return Sequence<OUString>(); 3127 3128 // Determine the total size of all ranges. 3129 AccumulateRangeSize func; 3130 func = for_each(m_pTokens->begin(), m_pTokens->end(), func); 3131 SCCOL nCols = func.getCols(); 3132 SCROW nRows = func.getRows(); 3133 3134 // Detemine whether this is column-major or row-major. 3135 bool bColumn = true; 3136 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) || 3137 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE)) 3138 { 3139 if (nRows > nCols) 3140 { 3141 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) 3142 bColumn = true; 3143 else 3144 bColumn = false; 3145 } 3146 else if (nCols > nRows) 3147 { 3148 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) 3149 bColumn = false; 3150 else 3151 bColumn = true; 3152 } 3153 else 3154 return Sequence<OUString>(); 3155 } 3156 3157 // Generate label strings based on the info so far. 3158 sal_Int32 nCount = bColumn ? nCols : nRows; 3159 GenerateLabelStrings genLabels(nCount, eOrigin, bColumn); 3160 genLabels = for_each(m_pTokens->begin(), m_pTokens->end(), genLabels); 3161 Sequence<OUString> aSeq = genLabels.getLabels(); 3162 3163 return aSeq; 3164 } 3165 3166 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex ) 3167 throw (lang::IndexOutOfBoundsException, 3168 uno::RuntimeException) 3169 { 3170 // index -1 means a heuristic value for the entire sequence 3171 bool bGetSeriesFormat = (nIndex == -1); 3172 sal_Int32 nResult = 0; 3173 3174 ScUnoGuard aGuard; 3175 if ( !m_pDocument || !m_pTokens.get()) 3176 return nResult; 3177 3178 sal_Int32 nCount = 0; 3179 bool bFound = false; 3180 ScRangePtr p; 3181 3182 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( lcl_GetSpreadSheetDocument( m_pDocument )); 3183 if (!xSpreadDoc.is()) 3184 return nResult; 3185 3186 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); 3187 if (!xIndex.is()) 3188 return nResult; 3189 3190 ScRangeList aRanges; 3191 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens); 3192 uno::Reference< table::XCellRange > xSheet; 3193 for ( p = aRanges.First(); p && !bFound; p = aRanges.Next()) 3194 { 3195 // TODO: use DocIter? 3196 table::CellAddress aStart, aEnd; 3197 ScUnoConversion::FillApiAddress( aStart, p->aStart ); 3198 ScUnoConversion::FillApiAddress( aEnd, p->aEnd ); 3199 for ( sal_Int16 nSheet = aStart.Sheet; nSheet <= aEnd.Sheet && !bFound; ++nSheet) 3200 { 3201 xSheet.set(xIndex->getByIndex(nSheet), uno::UNO_QUERY); 3202 for ( sal_Int32 nCol = aStart.Column; nCol <= aEnd.Column && !bFound; ++nCol) 3203 { 3204 for ( sal_Int32 nRow = aStart.Row; nRow <= aEnd.Row && !bFound; ++nRow) 3205 { 3206 if( bGetSeriesFormat ) 3207 { 3208 // TODO: use nicer heuristic 3209 // return format of first non-empty cell 3210 uno::Reference< text::XText > xText( 3211 xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY); 3212 if (xText.is() && xText->getString().getLength()) 3213 { 3214 uno::Reference< beans::XPropertySet > xProp(xText, uno::UNO_QUERY); 3215 if( xProp.is()) 3216 xProp->getPropertyValue( 3217 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult; 3218 bFound = true; 3219 break; 3220 } 3221 } 3222 else if( nCount == nIndex ) 3223 { 3224 uno::Reference< beans::XPropertySet > xProp( 3225 xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY); 3226 if( xProp.is()) 3227 xProp->getPropertyValue( 3228 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult; 3229 bFound = true; 3230 break; 3231 } 3232 ++nCount; 3233 } 3234 } 3235 } 3236 } 3237 3238 return nResult; 3239 } 3240 3241 // XCloneable ================================================================ 3242 3243 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone() 3244 throw (uno::RuntimeException) 3245 { 3246 ScUnoGuard aGuard; 3247 3248 auto_ptr< vector<ScSharedTokenRef> > pTokensNew; 3249 if (m_pTokens.get()) 3250 { 3251 // Clone tokens. 3252 pTokensNew.reset(new vector<ScSharedTokenRef>); 3253 pTokensNew->reserve(m_pTokens->size()); 3254 vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end(); 3255 for (; itr != itrEnd; ++itr) 3256 { 3257 ScSharedTokenRef p(static_cast<ScToken*>((*itr)->Clone())); 3258 pTokensNew->push_back(p); 3259 } 3260 } 3261 3262 auto_ptr<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, m_xDataProvider, pTokensNew.release(), m_bIncludeHiddenCells)); 3263 p->CopyData(*this); 3264 Reference< util::XCloneable > xClone(p.release()); 3265 3266 return xClone; 3267 } 3268 3269 // XModifyBroadcaster ======================================================== 3270 3271 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) 3272 throw (uno::RuntimeException) 3273 { 3274 // like ScCellRangesBase::addModifyListener 3275 ScUnoGuard aGuard; 3276 if (!m_pTokens.get() || m_pTokens->empty()) 3277 return; 3278 3279 ScRangeList aRanges; 3280 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens); 3281 uno::Reference<util::XModifyListener> *pObj = 3282 new uno::Reference<util::XModifyListener>( aListener ); 3283 m_aValueListeners.Insert( pObj, m_aValueListeners.Count() ); 3284 3285 if ( m_aValueListeners.Count() == 1 ) 3286 { 3287 if (!m_pValueListener) 3288 m_pValueListener = new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ); 3289 3290 if (!m_pHiddenListener.get()) 3291 m_pHiddenListener.reset(new HiddenRangeListener(*this)); 3292 3293 if( m_pDocument ) 3294 { 3295 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection(); 3296 vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end(); 3297 for (; itr != itrEnd; ++itr) 3298 { 3299 ScRange aRange; 3300 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr)) 3301 continue; 3302 3303 m_pDocument->StartListeningArea( aRange, m_pValueListener ); 3304 if (pCLC) 3305 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get()); 3306 } 3307 } 3308 3309 acquire(); // don't lose this object (one ref for all listeners) 3310 } 3311 } 3312 3313 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) 3314 throw (uno::RuntimeException) 3315 { 3316 // like ScCellRangesBase::removeModifyListener 3317 3318 ScUnoGuard aGuard; 3319 if (!m_pTokens.get() || m_pTokens->empty()) 3320 return; 3321 3322 acquire(); // in case the listeners have the last ref - released below 3323 3324 sal_uInt16 nCount = m_aValueListeners.Count(); 3325 for ( sal_uInt16 n=nCount; n--; ) 3326 { 3327 uno::Reference<util::XModifyListener> *pObj = m_aValueListeners[n]; 3328 if ( *pObj == aListener ) 3329 { 3330 m_aValueListeners.DeleteAndDestroy( n ); 3331 3332 if ( m_aValueListeners.Count() == 0 ) 3333 { 3334 if (m_pValueListener) 3335 m_pValueListener->EndListeningAll(); 3336 3337 if (m_pHiddenListener.get() && m_pDocument) 3338 { 3339 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection(); 3340 if (pCLC) 3341 pCLC->EndListeningHiddenRange(m_pHiddenListener.get()); 3342 } 3343 3344 release(); // release the ref for the listeners 3345 } 3346 3347 break; 3348 } 3349 } 3350 3351 release(); // might delete this object 3352 } 3353 3354 // DataSequence XPropertySet ------------------------------------------------- 3355 3356 uno::Reference< beans::XPropertySetInfo> SAL_CALL 3357 ScChart2DataSequence::getPropertySetInfo() throw( uno::RuntimeException) 3358 { 3359 ScUnoGuard aGuard; 3360 static uno::Reference<beans::XPropertySetInfo> aRef = 3361 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() ); 3362 return aRef; 3363 } 3364 3365 3366 void SAL_CALL ScChart2DataSequence::setPropertyValue( 3367 const ::rtl::OUString& rPropertyName, const uno::Any& rValue) 3368 throw( beans::UnknownPropertyException, 3369 beans::PropertyVetoException, 3370 lang::IllegalArgumentException, 3371 lang::WrappedTargetException, uno::RuntimeException) 3372 { 3373 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_ROLE))) 3374 { 3375 if ( !(rValue >>= m_aRole)) 3376 throw lang::IllegalArgumentException(); 3377 } 3378 else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 3379 { 3380 sal_Bool bOldValue = m_bIncludeHiddenCells; 3381 if ( !(rValue >>= m_bIncludeHiddenCells)) 3382 throw lang::IllegalArgumentException(); 3383 if( bOldValue != m_bIncludeHiddenCells ) 3384 m_aDataArray.clear();//data array is dirty now 3385 } 3386 else 3387 throw beans::UnknownPropertyException(); 3388 // TODO: support optional properties 3389 } 3390 3391 3392 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue( 3393 const ::rtl::OUString& rPropertyName) 3394 throw( beans::UnknownPropertyException, 3395 lang::WrappedTargetException, uno::RuntimeException) 3396 { 3397 uno::Any aRet; 3398 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_ROLE))) 3399 aRet <<= m_aRole; 3400 else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 3401 aRet <<= m_bIncludeHiddenCells; 3402 else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SC_UNONAME_HIDDENVALUES))) 3403 { 3404 // This property is read-only thus cannot be set externally via 3405 // setPropertyValue(...). 3406 BuildDataCache(); 3407 aRet <<= m_aHiddenValues; 3408 } 3409 else 3410 throw beans::UnknownPropertyException(); 3411 // TODO: support optional properties 3412 return aRet; 3413 } 3414 3415 3416 void SAL_CALL ScChart2DataSequence::addPropertyChangeListener( 3417 const ::rtl::OUString& /*rPropertyName*/, 3418 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/) 3419 throw( beans::UnknownPropertyException, 3420 lang::WrappedTargetException, uno::RuntimeException) 3421 { 3422 // FIXME: real implementation 3423 // throw uno::RuntimeException(); 3424 OSL_ENSURE( false, "Not yet implemented" ); 3425 } 3426 3427 3428 void SAL_CALL ScChart2DataSequence::removePropertyChangeListener( 3429 const ::rtl::OUString& /*rPropertyName*/, 3430 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/) 3431 throw( beans::UnknownPropertyException, 3432 lang::WrappedTargetException, uno::RuntimeException) 3433 { 3434 // FIXME: real implementation 3435 // throw uno::RuntimeException(); 3436 OSL_ENSURE( false, "Not yet implemented" ); 3437 } 3438 3439 3440 void SAL_CALL ScChart2DataSequence::addVetoableChangeListener( 3441 const ::rtl::OUString& /*rPropertyName*/, 3442 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/) 3443 throw( beans::UnknownPropertyException, 3444 lang::WrappedTargetException, uno::RuntimeException) 3445 { 3446 // FIXME: real implementation 3447 // throw uno::RuntimeException(); 3448 OSL_ENSURE( false, "Not yet implemented" ); 3449 } 3450 3451 3452 void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener( 3453 const ::rtl::OUString& /*rPropertyName*/, 3454 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/) 3455 throw( beans::UnknownPropertyException, 3456 lang::WrappedTargetException, uno::RuntimeException) 3457 { 3458 // FIXME: real implementation 3459 // throw uno::RuntimeException(); 3460 OSL_ENSURE( false, "Not yet implemented" ); 3461 } 3462 3463 void ScChart2DataSequence::setDataChangedHint(bool b) 3464 { 3465 m_bGotDataChangedHint = b; 3466 } 3467 3468 // XUnoTunnel 3469 3470 // sal_Int64 SAL_CALL ScChart2DataSequence::getSomething( 3471 // const uno::Sequence<sal_Int8 >& rId ) throw(uno::RuntimeException) 3472 // { 3473 // if ( rId.getLength() == 16 && 3474 // 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), 3475 // rId.getConstArray(), 16 ) ) 3476 // { 3477 // return (sal_Int64)this; 3478 // } 3479 // return 0; 3480 // } 3481 3482 // // static 3483 // const uno::Sequence<sal_Int8>& ScChart2DataSequence::getUnoTunnelId() 3484 // { 3485 // static uno::Sequence<sal_Int8> * pSeq = 0; 3486 // if( !pSeq ) 3487 // { 3488 // osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 3489 // if( !pSeq ) 3490 // { 3491 // static uno::Sequence< sal_Int8 > aSeq( 16 ); 3492 // rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); 3493 // pSeq = &aSeq; 3494 // } 3495 // } 3496 // return *pSeq; 3497 // } 3498 3499 // // static 3500 // ScChart2DataSequence* ScChart2DataSequence::getImplementation( const uno::Reference<uno::XInterface> xObj ) 3501 // { 3502 // ScChart2DataSequence* pRet = NULL; 3503 // uno::Reference<lang::XUnoTunnel> xUT( xObj, uno::UNO_QUERY ); 3504 // if (xUT.is()) 3505 // pRet = (ScChart2DataSequence*) xUT->getSomething( getUnoTunnelId() ); 3506 // return pRet; 3507 // } 3508 3509 #if USE_CHART2_EMPTYDATASEQUENCE 3510 // DataSequence ============================================================== 3511 3512 ScChart2EmptyDataSequence::ScChart2EmptyDataSequence( ScDocument* pDoc, 3513 const uno::Reference < chart2::data::XDataProvider >& xDP, 3514 const ScRangeListRef& rRangeList, 3515 sal_Bool bColumn) 3516 : m_bIncludeHiddenCells( sal_True) 3517 , m_xRanges( rRangeList) 3518 , m_pDocument( pDoc) 3519 , m_xDataProvider( xDP) 3520 , m_aPropSet(lcl_GetDataSequencePropertyMap()) 3521 , m_bColumn(bColumn) 3522 { 3523 if ( m_pDocument ) 3524 m_pDocument->AddUnoObject( *this); 3525 // FIXME: real implementation of identifier and it's mapping to ranges. 3526 // Reuse ScChartListener? 3527 3528 // BM: don't use names of named ranges but the UI range strings 3529 // String aStr; 3530 // rRangeList->Format( aStr, SCR_ABS_3D, m_pDocument ); 3531 // m_aIdentifier = ::rtl::OUString( aStr ); 3532 3533 // m_aIdentifier = ::rtl::OUString::createFromAscii( "ID_"); 3534 // static sal_Int32 nID = 0; 3535 // m_aIdentifier += ::rtl::OUString::valueOf( ++nID); 3536 } 3537 3538 3539 ScChart2EmptyDataSequence::~ScChart2EmptyDataSequence() 3540 { 3541 if ( m_pDocument ) 3542 m_pDocument->RemoveUnoObject( *this); 3543 } 3544 3545 3546 void ScChart2EmptyDataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint) 3547 { 3548 if ( rHint.ISA( SfxSimpleHint ) && 3549 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 3550 { 3551 m_pDocument = NULL; 3552 } 3553 } 3554 3555 3556 uno::Sequence< uno::Any> SAL_CALL ScChart2EmptyDataSequence::getData() 3557 throw ( uno::RuntimeException) 3558 { 3559 ScUnoGuard aGuard; 3560 if ( !m_pDocument) 3561 throw uno::RuntimeException(); 3562 return uno::Sequence< uno::Any>(); 3563 } 3564 3565 // XTextualDataSequence -------------------------------------------------- 3566 3567 uno::Sequence< rtl::OUString > SAL_CALL ScChart2EmptyDataSequence::getTextualData( ) throw (uno::RuntimeException) 3568 { 3569 ScUnoGuard aGuard; 3570 if ( !m_pDocument) 3571 throw uno::RuntimeException(); 3572 3573 sal_Int32 nCount = 0; 3574 ScRangePtr p; 3575 3576 DBG_ASSERT(m_xRanges->Count() == 1, "not handled count of ranges"); 3577 3578 for ( p = m_xRanges->First(); p; p = m_xRanges->Next()) 3579 { 3580 p->Justify(); 3581 // TODO: handle overlaping ranges? 3582 nCount += m_bColumn ? p->aEnd.Col() - p->aStart.Col() + 1 : p->aEnd.Row() - p->aStart.Row() + 1; 3583 } 3584 uno::Sequence< rtl::OUString > aSeq( nCount); 3585 rtl::OUString* pArr = aSeq.getArray(); 3586 nCount = 0; 3587 for ( p = m_xRanges->First(); p; p = m_xRanges->Next()) 3588 { 3589 if (m_bColumn) 3590 { 3591 for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol) 3592 { 3593 String aString = ScGlobal::GetRscString(STR_COLUMN); 3594 aString += ' '; 3595 ScAddress aPos( nCol, 0, 0 ); 3596 String aColStr; 3597 aPos.Format( aColStr, SCA_VALID_COL, NULL ); 3598 aString += aColStr; 3599 pArr[nCount] = aString; 3600 ++nCount; 3601 } 3602 } 3603 else 3604 { 3605 for (sal_Int32 nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow) 3606 { 3607 String aString = ScGlobal::GetRscString(STR_ROW); 3608 aString += ' '; 3609 aString += String::CreateFromInt32( nRow+1 ); 3610 pArr[nCount] = aString; 3611 ++nCount; 3612 } 3613 } 3614 } 3615 return aSeq; 3616 } 3617 3618 ::rtl::OUString SAL_CALL ScChart2EmptyDataSequence::getSourceRangeRepresentation() 3619 throw ( uno::RuntimeException) 3620 { 3621 ScUnoGuard aGuard; 3622 String aStr; 3623 DBG_ASSERT( m_pDocument, "No Document -> no SourceRangeRepresentation" ); 3624 if( m_pDocument ) 3625 m_xRanges->Format( aStr, SCR_ABS_3D, m_pDocument, m_pDocument->GetAddressConvention() ); 3626 return aStr; 3627 } 3628 3629 uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2EmptyDataSequence::generateLabel(chart2::data::LabelOrigin /*nOrigin*/) 3630 throw (uno::RuntimeException) 3631 { 3632 ScUnoGuard aGuard; 3633 uno::Sequence< ::rtl::OUString > aRet; 3634 return aRet; 3635 } 3636 3637 ::sal_Int32 SAL_CALL ScChart2EmptyDataSequence::getNumberFormatKeyByIndex( ::sal_Int32 /*nIndex*/ ) 3638 throw (lang::IndexOutOfBoundsException, 3639 uno::RuntimeException) 3640 { 3641 sal_Int32 nResult = 0; 3642 3643 ScUnoGuard aGuard; 3644 if ( !m_pDocument) 3645 return nResult; 3646 3647 return nResult; 3648 } 3649 3650 // XCloneable ================================================================ 3651 3652 uno::Reference< util::XCloneable > SAL_CALL ScChart2EmptyDataSequence::createClone() 3653 throw (uno::RuntimeException) 3654 { 3655 ScUnoGuard aGuard; 3656 if (m_xDataProvider.is()) 3657 { 3658 // copy properties 3659 uno::Reference < util::XCloneable > xClone(new ScChart2EmptyDataSequence(m_pDocument, m_xDataProvider, new ScRangeList(*m_xRanges), m_bColumn)); 3660 uno::Reference< beans::XPropertySet > xProp( xClone, uno::UNO_QUERY ); 3661 if( xProp.is()) 3662 { 3663 xProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_ROLE )), 3664 uno::makeAny( m_aRole )); 3665 xProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS )), 3666 uno::makeAny( m_bIncludeHiddenCells )); 3667 } 3668 return xClone; 3669 } 3670 return uno::Reference< util::XCloneable >(); 3671 } 3672 3673 // XModifyBroadcaster ======================================================== 3674 3675 void SAL_CALL ScChart2EmptyDataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& /*aListener*/ ) 3676 throw (uno::RuntimeException) 3677 { 3678 // TODO: Implement 3679 } 3680 3681 void SAL_CALL ScChart2EmptyDataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& /*aListener*/ ) 3682 throw (uno::RuntimeException) 3683 { 3684 // TODO: Implement 3685 } 3686 3687 // DataSequence XPropertySet ------------------------------------------------- 3688 3689 uno::Reference< beans::XPropertySetInfo> SAL_CALL 3690 ScChart2EmptyDataSequence::getPropertySetInfo() throw( uno::RuntimeException) 3691 { 3692 ScUnoGuard aGuard; 3693 static uno::Reference<beans::XPropertySetInfo> aRef = 3694 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() ); 3695 return aRef; 3696 } 3697 3698 3699 void SAL_CALL ScChart2EmptyDataSequence::setPropertyValue( 3700 const ::rtl::OUString& rPropertyName, const uno::Any& rValue) 3701 throw( beans::UnknownPropertyException, 3702 beans::PropertyVetoException, 3703 lang::IllegalArgumentException, 3704 lang::WrappedTargetException, uno::RuntimeException) 3705 { 3706 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_ROLE))) 3707 { 3708 if ( !(rValue >>= m_aRole)) 3709 throw lang::IllegalArgumentException(); 3710 } 3711 else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 3712 { 3713 if ( !(rValue >>= m_bIncludeHiddenCells)) 3714 throw lang::IllegalArgumentException(); 3715 } 3716 else 3717 throw beans::UnknownPropertyException(); 3718 // TODO: support optional properties 3719 } 3720 3721 3722 uno::Any SAL_CALL ScChart2EmptyDataSequence::getPropertyValue( 3723 const ::rtl::OUString& rPropertyName) 3724 throw( beans::UnknownPropertyException, 3725 lang::WrappedTargetException, uno::RuntimeException) 3726 { 3727 uno::Any aRet; 3728 if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_ROLE))) 3729 aRet <<= m_aRole; 3730 else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_INCLUDEHIDDENCELLS))) 3731 aRet <<= m_bIncludeHiddenCells; 3732 else 3733 throw beans::UnknownPropertyException(); 3734 // TODO: support optional properties 3735 return aRet; 3736 } 3737 3738 3739 void SAL_CALL ScChart2EmptyDataSequence::addPropertyChangeListener( 3740 const ::rtl::OUString& /*rPropertyName*/, 3741 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/) 3742 throw( beans::UnknownPropertyException, 3743 lang::WrappedTargetException, uno::RuntimeException) 3744 { 3745 // FIXME: real implementation 3746 // throw uno::RuntimeException(); 3747 OSL_ENSURE( false, "Not yet implemented" ); 3748 } 3749 3750 3751 void SAL_CALL ScChart2EmptyDataSequence::removePropertyChangeListener( 3752 const ::rtl::OUString& /*rPropertyName*/, 3753 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/) 3754 throw( beans::UnknownPropertyException, 3755 lang::WrappedTargetException, uno::RuntimeException) 3756 { 3757 // FIXME: real implementation 3758 // throw uno::RuntimeException(); 3759 OSL_ENSURE( false, "Not yet implemented" ); 3760 } 3761 3762 3763 void SAL_CALL ScChart2EmptyDataSequence::addVetoableChangeListener( 3764 const ::rtl::OUString& /*rPropertyName*/, 3765 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/) 3766 throw( beans::UnknownPropertyException, 3767 lang::WrappedTargetException, uno::RuntimeException) 3768 { 3769 // FIXME: real implementation 3770 // throw uno::RuntimeException(); 3771 OSL_ENSURE( false, "Not yet implemented" ); 3772 } 3773 3774 3775 void SAL_CALL ScChart2EmptyDataSequence::removeVetoableChangeListener( 3776 const ::rtl::OUString& /*rPropertyName*/, 3777 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ ) 3778 throw( beans::UnknownPropertyException, 3779 lang::WrappedTargetException, uno::RuntimeException) 3780 { 3781 // FIXME: real implementation 3782 // throw uno::RuntimeException(); 3783 OSL_ENSURE( false, "Not yet implemented" ); 3784 } 3785 3786 // XUnoTunnel 3787 3788 // sal_Int64 SAL_CALL ScChart2EmptyDataSequence::getSomething( 3789 // const uno::Sequence<sal_Int8 >& rId ) throw(uno::RuntimeException) 3790 // { 3791 // if ( rId.getLength() == 16 && 3792 // 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), 3793 // rId.getConstArray(), 16 ) ) 3794 // { 3795 // return (sal_Int64)this; 3796 // } 3797 // return 0; 3798 // } 3799 3800 // // static 3801 // const uno::Sequence<sal_Int8>& ScChart2EmptyDataSequence::getUnoTunnelId() 3802 // { 3803 // static uno::Sequence<sal_Int8> * pSeq = 0; 3804 // if( !pSeq ) 3805 // { 3806 // osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 3807 // if( !pSeq ) 3808 // { 3809 // static uno::Sequence< sal_Int8 > aSeq( 16 ); 3810 // rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); 3811 // pSeq = &aSeq; 3812 // } 3813 // } 3814 // return *pSeq; 3815 // } 3816 3817 // // static 3818 // ScChart2DataSequence* ScChart2EmptyDataSequence::getImplementation( const uno::Reference<uno::XInterface> xObj ) 3819 // { 3820 // ScChart2DataSequence* pRet = NULL; 3821 // uno::Reference<lang::XUnoTunnel> xUT( xObj, uno::UNO_QUERY ); 3822 // if (xUT.is()) 3823 // pRet = (ScChart2EmptyDataSequence*) xUT->getSomething( getUnoTunnelId() ); 3824 // return pRet; 3825 // } 3826 #endif 3827