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