1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 #include <memory> 28 #include <algorithm> 29 30 #include <com/sun/star/chart/ChartDataRowSource.hpp> 31 #include <com/sun/star/chart2/data/LabelOrigin.hpp> 32 #include <cppuhelper/interfacecontainer.hxx> 33 #include <vos/mutex.hxx> 34 #include <osl/mutex.hxx> 35 #include <vcl/svapp.hxx> 36 #include <svl/zforlist.hxx> // SvNumberFormatter 37 #include <svtools/chartprettypainter.hxx> 38 39 #include <tools/link.hxx> 40 41 #include <XMLRangeHelper.hxx> 42 #include <unochart.hxx> 43 #include <swtable.hxx> 44 #include <unoprnms.hxx> 45 #include <unomap.hxx> 46 #include <unomid.h> 47 #include <unocrsr.hxx> 48 #include <unotbl.hxx> 49 #include <doc.hxx> 50 #include <frmfmt.hxx> 51 #include <docsh.hxx> 52 #include <ndole.hxx> 53 #include <swtable.hxx> 54 #include <swtypes.hxx> 55 #ifndef _UNOCORE_HRC 56 #include <unocore.hrc> 57 #endif 58 59 #include <docary.hxx> 60 61 #define SN_DATA_PROVIDER "com.sun.star.chart2.data.DataProvider" 62 #define SN_DATA_SOURCE "com.sun.star.chart2.data.DataSource" 63 #define SN_DATA_SEQUENCE "com.sun.star.chart2.data.DataSequence" 64 #define SN_LABELED_DATA_SEQUENCE "com.sun.star.chart2.data.LabeledDataSequence" 65 66 #define DIRECTION_DONT_KNOW -1 67 #define DIRECTION_HAS_ERROR -2 68 #define DIRECTION_COLS 0 69 #define DIRECTION_ROWS 1 70 71 using namespace ::com::sun::star; 72 using ::rtl::OUString; 73 74 // from unotbl.cxx 75 extern void lcl_GetCellPosition( const String &rCellName, sal_Int32 &rColumn, sal_Int32 &rRow); 76 extern String lcl_GetCellName( sal_Int32 nColumn, sal_Int32 nRow ); 77 extern int lcl_CompareCellsByColFirst( const String &rCellName1, const String &rCellName2 ); 78 extern int lcl_CompareCellsByRowFirst( const String &rCellName1, const String &rCellName2 ); 79 extern int lcl_CompareCellRanges( 80 const String &rRange1StartCell, const String &rRange1EndCell, 81 const String &rRange2StartCell, const String &rRange2EndCell, 82 sal_Bool bCmpColsFirst ); 83 extern void lcl_NormalizeRange( String &rCell1, String &rCell2 ); 84 85 ////////////////////////////////////////////////////////////////////// 86 87 //static 88 void SwChartHelper::DoUpdateAllCharts( SwDoc* pDoc ) 89 { 90 if (!pDoc) 91 return; 92 93 uno::Reference< frame::XModel > xRes; 94 95 SwOLENode *pONd; 96 SwStartNode *pStNd; 97 SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); 98 while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) 99 { 100 aIdx++; 101 if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) && 102 ChartPrettyPainter::IsChart( pONd->GetOLEObj().GetObject() ) ) 103 { 104 // Load the object and set modified 105 106 uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); 107 if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) 108 { 109 try 110 { 111 uno::Reference< util::XModifiable > xModif( xIP->getComponent(), uno::UNO_QUERY_THROW ); 112 xModif->setModified( sal_True ); 113 } 114 catch ( uno::Exception& ) 115 { 116 } 117 118 } 119 } 120 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); 121 } 122 } 123 124 ////////////////////////////////////////////////////////////////////// 125 126 SwChartLockController_Helper::SwChartLockController_Helper( SwDoc *pDocument ) : 127 pDoc( pDocument ) 128 { 129 aUnlockTimer.SetTimeout( 1500 ); 130 aUnlockTimer.SetTimeoutHdl( LINK( this, SwChartLockController_Helper, DoUnlockAllCharts )); 131 } 132 133 134 SwChartLockController_Helper::~SwChartLockController_Helper() 135 { 136 if (pDoc) // still connected? 137 Disconnect(); 138 } 139 140 141 void SwChartLockController_Helper::StartOrContinueLocking() 142 { 143 if (!bIsLocked) 144 LockAllCharts(); 145 aUnlockTimer.Start(); // start or continue time of locking 146 } 147 148 149 void SwChartLockController_Helper::Disconnect() 150 { 151 aUnlockTimer.Stop(); 152 UnlockAllCharts(); 153 pDoc = 0; 154 } 155 156 157 void SwChartLockController_Helper::LockUnlockAllCharts( sal_Bool bLock ) 158 { 159 if (!pDoc) 160 return; 161 162 const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts(); 163 for( sal_uInt16 n = 0; n < rTblFmts.Count(); ++n ) 164 { 165 SwTable* pTmpTbl; 166 const SwTableNode* pTblNd; 167 SwFrmFmt* pFmt = rTblFmts[ n ]; 168 169 if( 0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) && 170 0 != ( pTblNd = pTmpTbl->GetTableNode() ) && 171 pTblNd->GetNodes().IsDocNodes() ) 172 { 173 uno::Reference< frame::XModel > xRes; 174 175 String aName( pTmpTbl->GetFrmFmt()->GetName() ); 176 SwOLENode *pONd; 177 SwStartNode *pStNd; 178 SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); 179 while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) 180 { 181 aIdx++; 182 if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) && 183 pONd->GetChartTblName().Len() > 0 /* is chart object? */) 184 { 185 uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); 186 if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) 187 { 188 xRes = uno::Reference < frame::XModel >( xIP->getComponent(), uno::UNO_QUERY ); 189 if (xRes.is()) 190 { 191 if (bLock) 192 xRes->lockControllers(); 193 else 194 xRes->unlockControllers(); 195 } 196 } 197 } 198 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); 199 } 200 } 201 } 202 203 bIsLocked = bLock; 204 } 205 206 207 IMPL_LINK( SwChartLockController_Helper, DoUnlockAllCharts, Timer *, /*pTimer*/ ) 208 { 209 UnlockAllCharts(); 210 return 0; 211 } 212 213 214 ////////////////////////////////////////////////////////////////////// 215 216 static osl::Mutex & GetChartMutex() 217 { 218 static osl::Mutex aMutex; 219 return aMutex; 220 } 221 222 223 static void LaunchModifiedEvent( 224 ::cppu::OInterfaceContainerHelper &rICH, 225 const uno::Reference< uno::XInterface > &rxI ) 226 { 227 lang::EventObject aEvtObj( rxI ); 228 cppu::OInterfaceIteratorHelper aIt( rICH ); 229 while (aIt.hasMoreElements()) 230 { 231 uno::Reference< util::XModifyListener > xRef( aIt.next(), uno::UNO_QUERY ); 232 if (xRef.is()) 233 xRef->modified( aEvtObj ); 234 } 235 } 236 237 ////////////////////////////////////////////////////////////////////// 238 239 // rCellRangeName needs to be of one of the following formats: 240 // - e.g. "A2:E5" or 241 // - e.g. "Table1.A2:E5" 242 sal_Bool FillRangeDescriptor( 243 SwRangeDescriptor &rDesc, 244 const String &rCellRangeName ) 245 { 246 xub_StrLen nToken = STRING_NOTFOUND == rCellRangeName.Search('.') ? 0 : 1; 247 String aCellRangeNoTableName( rCellRangeName.GetToken( nToken, '.' ) ); 248 String aTLName( aCellRangeNoTableName.GetToken(0, ':') ); // name of top left cell 249 String aBRName( aCellRangeNoTableName.GetToken(1, ':') ); // name of bottom right cell 250 if(!aTLName.Len() || !aBRName.Len()) 251 return sal_False; 252 253 rDesc.nTop = rDesc.nLeft = rDesc.nBottom = rDesc.nRight = -1; 254 lcl_GetCellPosition( aTLName, rDesc.nLeft, rDesc.nTop ); 255 lcl_GetCellPosition( aBRName, rDesc.nRight, rDesc.nBottom ); 256 rDesc.Normalize(); 257 DBG_ASSERT( rDesc.nTop != -1 && 258 rDesc.nLeft != -1 && 259 rDesc.nBottom != -1 && 260 rDesc.nRight != -1, 261 "failed to get range descriptor" ); 262 DBG_ASSERT( rDesc.nTop <= rDesc.nBottom && rDesc.nLeft <= rDesc.nRight, 263 "invalid range descriptor"); 264 return sal_True; 265 } 266 267 268 static String GetCellRangeName( SwFrmFmt &rTblFmt, SwUnoCrsr &rTblCrsr ) 269 { 270 String aRes; 271 272 //!! see also SwXTextTableCursor::getRangeName 273 274 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(&rTblCrsr); 275 if (!pUnoTblCrsr) 276 return String(); 277 pUnoTblCrsr->MakeBoxSels(); 278 279 const SwStartNode* pStart; 280 const SwTableBox* pStartBox = 0; 281 const SwTableBox* pEndBox = 0; 282 283 pStart = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 284 if (pStart) 285 { 286 const SwTable* pTable = SwTable::FindTable( &rTblFmt ); 287 pEndBox = pTable->GetTblBox( pStart->GetIndex()); 288 aRes = pEndBox->GetName(); 289 290 if(pUnoTblCrsr->HasMark()) 291 { 292 pStart = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 293 pStartBox = pTable->GetTblBox( pStart->GetIndex()); 294 } 295 DBG_ASSERT( pStartBox, "start box not found" ); 296 DBG_ASSERT( pEndBox, "end box not found" ); 297 // need to switch start and end? 298 if (*pUnoTblCrsr->GetPoint() < *pUnoTblCrsr->GetMark()) 299 { 300 const SwTableBox* pTmpBox = pStartBox; 301 pStartBox = pEndBox; 302 pEndBox = pTmpBox; 303 } 304 305 aRes = pStartBox->GetName(); 306 aRes += (sal_Unicode)':'; 307 if (pEndBox) 308 aRes += pEndBox->GetName(); 309 else 310 aRes += pStartBox->GetName(); 311 } 312 313 return aRes; 314 } 315 316 317 static String GetRangeRepFromTableAndCells( const String &rTableName, 318 const String &rStartCell, const String &rEndCell, 319 sal_Bool bForceEndCellName ) 320 { 321 DBG_ASSERT( rTableName.Len(), "table name missing" ); 322 DBG_ASSERT( rStartCell.Len(), "cell name missing" ); 323 String aRes( rTableName ); 324 aRes += (sal_Unicode) '.'; 325 aRes += rStartCell; 326 327 if (rEndCell.Len()) 328 { 329 aRes += (sal_Unicode) ':'; 330 aRes += rEndCell; 331 } 332 else if (bForceEndCellName) 333 { 334 aRes += (sal_Unicode) ':'; 335 aRes += rStartCell; 336 } 337 338 return aRes; 339 } 340 341 342 static sal_Bool GetTableAndCellsFromRangeRep( 343 const OUString &rRangeRepresentation, 344 String &rTblName, 345 String &rStartCell, 346 String &rEndCell, 347 sal_Bool bSortStartEndCells = sal_True ) 348 { 349 // parse range representation for table name and cell/range names 350 // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2" 351 String aTblName; // table name 352 OUString aRange; // cell range 353 String aStartCell; // name of top left cell 354 String aEndCell; // name of bottom right cell 355 sal_Int32 nIdx = rRangeRepresentation.indexOf( '.' ); 356 if (nIdx >= 0) 357 { 358 aTblName = rRangeRepresentation.copy( 0, nIdx ); 359 aRange = rRangeRepresentation.copy( nIdx + 1 ); 360 sal_Int32 nPos = aRange.indexOf( ':' ); 361 if (nPos >= 0) // a cell-range like "Table1.A2:D4" 362 { 363 aStartCell = aRange.copy( 0, nPos ); 364 aEndCell = aRange.copy( nPos + 1 ); 365 366 // need to switch start and end cell ? 367 // (does not check for normalization here) 368 if (bSortStartEndCells && 1 == lcl_CompareCellsByColFirst( aStartCell, aEndCell )) 369 { 370 String aTmp( aStartCell ); 371 aStartCell = aEndCell; 372 aEndCell = aTmp; 373 } 374 } 375 else // a single cell like in "Table1.B3" 376 { 377 aStartCell = aEndCell = aRange; 378 } 379 } 380 381 sal_Bool bSuccess = aTblName.Len() != 0 && 382 aStartCell.Len() != 0 && aEndCell.Len() != 0; 383 if (bSuccess) 384 { 385 rTblName = aTblName; 386 rStartCell = aStartCell; 387 rEndCell = aEndCell; 388 } 389 return bSuccess; 390 } 391 392 393 static void GetTableByName( const SwDoc &rDoc, const String &rTableName, 394 SwFrmFmt **ppTblFmt, SwTable **ppTable) 395 { 396 SwFrmFmt *pTblFmt = NULL; 397 398 // find frame format of table 399 //! see SwXTextTables::getByName 400 sal_uInt16 nCount = rDoc.GetTblFrmFmtCount(sal_True); 401 for (sal_uInt16 i = 0; i < nCount && !pTblFmt; ++i) 402 { 403 SwFrmFmt& rTblFmt = rDoc.GetTblFrmFmt(i, sal_True); 404 if(rTableName == rTblFmt.GetName()) 405 pTblFmt = &rTblFmt; 406 } 407 408 if (ppTblFmt) 409 *ppTblFmt = pTblFmt; 410 411 if (ppTable) 412 *ppTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; 413 } 414 415 416 static void GetFormatAndCreateCursorFromRangeRep( 417 const SwDoc *pDoc, 418 const OUString &rRangeRepresentation, // must be a single range (i.e. so called sub-range) 419 SwFrmFmt **ppTblFmt, // will be set to the table format of the table used in the range representation 420 SwUnoCrsr **ppUnoCrsr ) // will be set to cursor spanning the cell range 421 // (cursor will be created!) 422 { 423 String aTblName; // table name 424 String aStartCell; // name of top left cell 425 String aEndCell; // name of bottom right cell 426 sal_Bool bNamesFound = GetTableAndCellsFromRangeRep( rRangeRepresentation, 427 aTblName, aStartCell, aEndCell ); 428 429 if (!bNamesFound) 430 { 431 if (ppTblFmt) 432 *ppTblFmt = NULL; 433 if (ppUnoCrsr) 434 *ppUnoCrsr = NULL; 435 } 436 else 437 { 438 SwFrmFmt *pTblFmt = NULL; 439 440 // is the correct table format already provided? 441 if (*ppTblFmt != NULL && (*ppTblFmt)->GetName() == aTblName) 442 pTblFmt = *ppTblFmt; 443 else if (ppTblFmt) 444 GetTableByName( *pDoc, aTblName, &pTblFmt, NULL ); 445 446 if (ppTblFmt) 447 *ppTblFmt = pTblFmt; 448 449 if (ppUnoCrsr != NULL) 450 { 451 *ppUnoCrsr = NULL; // default result in case of failure 452 453 SwTable *pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; 454 // create new SwUnoCrsr spanning the specified range 455 //! see also SwXTextTable::GetRangeByName 456 // --> OD 2007-08-03 #i80314# 457 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)> 458 const SwTableBox* pTLBox = 459 pTable ? pTable->GetTblBox( aStartCell, true ) : 0; 460 // <-- 461 if(pTLBox) 462 { 463 // hier muessen die Actions aufgehoben werden 464 UnoActionRemoveContext aRemoveContext(pTblFmt->GetDoc()); 465 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 466 SwPosition aPos(*pSttNd); 467 // set cursor to top left box of range 468 SwUnoCrsr* pUnoCrsr = pTblFmt->GetDoc()->CreateUnoCrsr(aPos, sal_True); 469 pUnoCrsr->Move( fnMoveForward, fnGoNode ); 470 pUnoCrsr->SetRemainInSection( sal_False ); 471 // --> OD 2007-08-03 #i80314# 472 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)> 473 const SwTableBox* pBRBox = pTable->GetTblBox( aEndCell, true ); 474 // <-- 475 if(pBRBox) 476 { 477 pUnoCrsr->SetMark(); 478 pUnoCrsr->GetPoint()->nNode = *pBRBox->GetSttNd(); 479 pUnoCrsr->Move( fnMoveForward, fnGoNode ); 480 SwUnoTableCrsr* pCrsr = 481 dynamic_cast<SwUnoTableCrsr*>(pUnoCrsr); 482 pCrsr->MakeBoxSels(); 483 484 if (ppUnoCrsr) 485 *ppUnoCrsr = pCrsr; 486 } 487 else 488 { 489 delete pUnoCrsr; 490 } 491 } 492 } 493 } 494 } 495 496 497 static sal_Bool GetSubranges( const OUString &rRangeRepresentation, 498 uno::Sequence< OUString > &rSubRanges, sal_Bool bNormalize ) 499 { 500 sal_Bool bRes = sal_True; 501 String aRangesStr( rRangeRepresentation ); 502 xub_StrLen nLen = aRangesStr.GetTokenCount( ';' ); 503 uno::Sequence< OUString > aRanges( nLen ); 504 505 sal_Int32 nCnt = 0; 506 if (nLen != 0) 507 { 508 OUString *pRanges = aRanges.getArray(); 509 String aFirstTable; 510 for ( xub_StrLen i = 0; i < nLen && bRes; ++i) 511 { 512 String aRange( aRangesStr.GetToken( i, ';' ) ); 513 if (aRange.Len()) 514 { 515 pRanges[nCnt] = aRange; 516 517 String aTableName, aStartCell, aEndCell; 518 bRes &= GetTableAndCellsFromRangeRep( aRange, 519 aTableName, aStartCell, aEndCell ); 520 521 if (bNormalize) 522 { 523 lcl_NormalizeRange( aStartCell, aEndCell ); 524 pRanges[nCnt] = GetRangeRepFromTableAndCells( aTableName, 525 aStartCell, aEndCell, sal_True ); 526 } 527 528 // make sure to use only a single table 529 if (nCnt == 0) 530 aFirstTable = aTableName; 531 else 532 bRes &= aFirstTable == aTableName; 533 534 ++nCnt; 535 } 536 } 537 } 538 aRanges.realloc( nCnt ); 539 540 rSubRanges = aRanges; 541 return bRes; 542 } 543 544 545 static void SortSubranges( uno::Sequence< OUString > &rSubRanges, sal_Bool bCmpByColumn ) 546 { 547 sal_Int32 nLen = rSubRanges.getLength(); 548 OUString *pSubRanges = rSubRanges.getArray(); 549 550 String aSmallestTblName; 551 String aSmallestStartCell; 552 String aSmallestEndCell; 553 554 for (sal_Int32 i = 0; i < nLen; ++i) 555 { 556 sal_Int32 nIdxOfSmallest = i; 557 GetTableAndCellsFromRangeRep( pSubRanges[nIdxOfSmallest], 558 aSmallestTblName, aSmallestStartCell, aSmallestEndCell ); 559 if (aSmallestEndCell.Len() == 0) 560 aSmallestEndCell = aSmallestStartCell; 561 562 for (sal_Int32 k = i+1; k < nLen; ++k) 563 { 564 // get cell names for sub range 565 String aTblName; 566 String aStartCell; 567 String aEndCell; 568 GetTableAndCellsFromRangeRep( pSubRanges[k], 569 aTblName, aStartCell, aEndCell ); 570 if (aEndCell.Len() == 0) 571 aEndCell = aStartCell; 572 573 // compare cell ranges ( is the new one smaller? ) 574 if (-1 == lcl_CompareCellRanges( aStartCell, aEndCell, 575 aSmallestStartCell, aSmallestEndCell, bCmpByColumn )) 576 { 577 nIdxOfSmallest = k; 578 aSmallestTblName = aTblName; 579 aSmallestStartCell = aStartCell; 580 aSmallestEndCell = aEndCell; 581 } 582 } 583 584 // move smallest element to the start of the not sorted area 585 OUString aTmp( pSubRanges[ nIdxOfSmallest ] ); 586 pSubRanges[ nIdxOfSmallest ] = pSubRanges[ i ]; 587 pSubRanges[ i ] = aTmp; 588 } 589 } 590 591 ////////////////////////////////////////////////////////////////////// 592 593 SwChartDataProvider::SwChartDataProvider( const SwDoc* pSwDoc ) : 594 aEvtListeners( GetChartMutex() ), 595 pDoc( pSwDoc ) 596 { 597 bDisposed = sal_False; 598 } 599 600 601 SwChartDataProvider::~SwChartDataProvider() 602 { 603 } 604 605 uno::Reference< chart2::data::XDataSource > SwChartDataProvider::Impl_createDataSource( 606 const uno::Sequence< beans::PropertyValue >& rArguments, sal_Bool bTestOnly ) 607 throw (lang::IllegalArgumentException, uno::RuntimeException) 608 { 609 vos::OGuard aGuard( Application::GetSolarMutex() ); 610 if (bDisposed) 611 throw lang::DisposedException(); 612 613 uno::Reference< chart2::data::XDataSource > xRes; 614 615 if (!pDoc) 616 throw uno::RuntimeException(); 617 618 // get arguments 619 OUString aRangeRepresentation; 620 uno::Sequence< sal_Int32 > aSequenceMapping; 621 sal_Bool bFirstIsLabel = sal_False; 622 sal_Bool bDtaSrcIsColumns = sal_True; // true : DataSource will be sequence of columns 623 // false: DataSource will be sequence of rows 624 OUString aChartOleObjectName;//work around wrong writer ranges ( see Issue 58464 ) 625 sal_Int32 nArgs = rArguments.getLength(); 626 DBG_ASSERT( nArgs != 0, "no properties provided" ); 627 if (nArgs == 0) 628 return xRes; 629 const beans::PropertyValue *pArg = rArguments.getConstArray(); 630 for (sal_Int32 i = 0; i < nArgs; ++i) 631 { 632 if (pArg[i].Name.equalsAscii( "DataRowSource" )) 633 { 634 chart::ChartDataRowSource eSource; 635 if (!(pArg[i].Value >>= eSource)) 636 { 637 sal_Int32 nTmp = 0; 638 if (!(pArg[i].Value >>= nTmp)) 639 throw lang::IllegalArgumentException(); 640 eSource = static_cast< chart::ChartDataRowSource >( nTmp ); 641 } 642 bDtaSrcIsColumns = eSource == chart::ChartDataRowSource_COLUMNS; 643 } 644 else if (pArg[i].Name.equalsAscii( "FirstCellAsLabel" )) 645 { 646 if (!(pArg[i].Value >>= bFirstIsLabel)) 647 throw lang::IllegalArgumentException(); 648 } 649 else if (pArg[i].Name.equalsAscii( "CellRangeRepresentation" )) 650 { 651 if (!(pArg[i].Value >>= aRangeRepresentation)) 652 throw lang::IllegalArgumentException(); 653 } 654 else if (pArg[i].Name.equalsAscii( "SequenceMapping" )) 655 { 656 if (!(pArg[i].Value >>= aSequenceMapping)) 657 throw lang::IllegalArgumentException(); 658 } 659 else if (pArg[i].Name.equalsAscii( "ChartOleObjectName" )) 660 { 661 if (!(pArg[i].Value >>= aChartOleObjectName)) 662 throw lang::IllegalArgumentException(); 663 } 664 } 665 666 uno::Sequence< OUString > aSubRanges; 667 // get sub-ranges and check that they all are from the very same table 668 sal_Bool bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True ); 669 670 if (!bOk && pDoc && aChartOleObjectName.getLength() ) 671 { 672 //try to correct the range here 673 //work around wrong writer ranges ( see Issue 58464 ) 674 String aChartTableName; 675 676 const SwNodes& rNodes = pDoc->GetNodes(); 677 for( sal_uLong nN = rNodes.Count(); nN--; ) 678 { 679 SwNodePtr pNode = rNodes[nN]; 680 if( !pNode ) 681 continue; 682 const SwOLENode* pOleNode = pNode->GetOLENode(); 683 if( !pOleNode ) 684 continue; 685 const SwOLEObj& rOObj = pOleNode->GetOLEObj(); 686 if( aChartOleObjectName.equals( rOObj.GetCurrentPersistName() ) ) 687 { 688 aChartTableName = pOleNode->GetChartTblName(); 689 break; 690 } 691 } 692 693 if( aChartTableName.Len() ) 694 { 695 //the wrong range is still shifted one row down 696 //thus the first row is missing and an invalid row at the end is added. 697 //Therefore we need to shift the range one row up 698 SwRangeDescriptor aDesc; 699 if (aRangeRepresentation.getLength() == 0) 700 return xRes; // we cant handle this thus returning an empty references 701 aRangeRepresentation = aRangeRepresentation.copy( 1 ); // get rid of '.' to have only the cell range left 702 FillRangeDescriptor( aDesc, aRangeRepresentation ); 703 aDesc.Normalize(); 704 if (aDesc.nTop <= 0) // no chance to shift the range one row up? 705 return xRes; // we cant handle this thus returning an empty references 706 aDesc.nTop -= 1; 707 aDesc.nBottom -= 1; 708 709 String aNewStartCell( lcl_GetCellName( aDesc.nLeft, aDesc.nTop ) ); 710 String aNewEndCell( lcl_GetCellName( aDesc.nRight, aDesc.nBottom ) ); 711 aRangeRepresentation = GetRangeRepFromTableAndCells( 712 aChartTableName, aNewStartCell, aNewEndCell, sal_True ); 713 bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True ); 714 } 715 } 716 if (!bOk) // different tables used, or incorrect range specifiers 717 throw lang::IllegalArgumentException(); 718 719 SortSubranges( aSubRanges, bDtaSrcIsColumns ); 720 const OUString *pSubRanges = aSubRanges.getConstArray(); 721 #if OSL_DEBUG_LEVEL > 1 722 { 723 sal_Int32 nSR = aSubRanges.getLength(); 724 OUString *pSR = aSubRanges.getArray(); 725 OUString aRg; 726 for (sal_Int32 i = 0; i < nSR; ++i) 727 { 728 aRg = pSR[i]; 729 } 730 } 731 #endif 732 733 // get table format for that single table from above 734 SwFrmFmt *pTblFmt = 0; // pointer to table format 735 SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist 736 std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr 737 if (aSubRanges.getLength() > 0) 738 GetFormatAndCreateCursorFromRangeRep( pDoc, pSubRanges[0], &pTblFmt, &pUnoCrsr ); 739 if (!pTblFmt || !pUnoCrsr) 740 throw lang::IllegalArgumentException(); 741 742 if(pTblFmt) 743 { 744 SwTable* pTable = SwTable::FindTable( pTblFmt ); 745 if(pTable->IsTblComplex()) 746 return xRes; // we cant handle this thus returning an empty references 747 else 748 { 749 // get a character map in the size of the table to mark 750 // all the ranges to use in 751 sal_Int32 nRows = pTable->GetTabLines().Count(); 752 sal_Int32 nCols = pTable->GetTabLines().GetObject(0)->GetTabBoxes().Count(); 753 std::vector< std::vector< sal_Char > > aMap( nRows ); 754 for (sal_Int32 i = 0; i < nRows; ++i) 755 aMap[i].resize( nCols ); 756 757 // iterate over subranges and mark used cells in above map 758 //!! by proceeding this way we automatically get rid of 759 //!! multiple listed or overlapping cell ranges which should 760 //!! just be ignored silently 761 sal_Int32 nSubRanges = aSubRanges.getLength(); 762 for (sal_Int32 i = 0; i < nSubRanges; ++i) 763 { 764 String aTblName, aStartCell, aEndCell; 765 sal_Bool bOk2 = GetTableAndCellsFromRangeRep( 766 pSubRanges[i], aTblName, aStartCell, aEndCell ); 767 (void) bOk2; 768 DBG_ASSERT( bOk2, "failed to get table and start/end cells" ); 769 770 sal_Int32 nStartRow, nStartCol, nEndRow, nEndCol; 771 lcl_GetCellPosition( aStartCell, nStartCol, nStartRow ); 772 lcl_GetCellPosition( aEndCell, nEndCol, nEndRow ); 773 DBG_ASSERT( nStartRow <= nEndRow && nStartCol <= nEndCol, 774 "cell range not normalized"); 775 776 // test if the ranges span more than the available cells 777 if( nStartRow < 0 || nEndRow >= nRows || 778 nStartCol < 0 || nEndCol >= nCols ) 779 { 780 throw lang::IllegalArgumentException(); 781 } 782 for (sal_Int32 k1 = nStartRow; k1 <= nEndRow; ++k1) 783 { 784 for (sal_Int32 k2 = nStartCol; k2 <= nEndCol; ++k2) 785 aMap[k1][k2] = 'x'; 786 } 787 } 788 789 // 790 // find label and data sequences to use 791 // 792 sal_Int32 oi; // outer index (slower changing index) 793 sal_Int32 ii; // inner index (faster changing index) 794 sal_Int32 oiEnd = bDtaSrcIsColumns ? nCols : nRows; 795 sal_Int32 iiEnd = bDtaSrcIsColumns ? nRows : nCols; 796 std::vector< sal_Int32 > aLabelIdx( oiEnd ); 797 std::vector< sal_Int32 > aDataStartIdx( oiEnd ); 798 std::vector< sal_Int32 > aDataLen( oiEnd ); 799 for (oi = 0; oi < oiEnd; ++oi) 800 { 801 aLabelIdx[oi] = -1; 802 aDataStartIdx[oi] = -1; 803 aDataLen[oi] = 0; 804 } 805 // 806 for (oi = 0; oi < oiEnd; ++oi) 807 { 808 ii = 0; 809 while (ii < iiEnd) 810 { 811 sal_Char &rChar = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii]; 812 813 // label should be used but is not yet found? 814 if (rChar == 'x' && bFirstIsLabel && aLabelIdx[oi] == -1) 815 { 816 aLabelIdx[oi] = ii; 817 rChar = 'L'; // setting a different char for labels here 818 // makes the test for the data sequence below 819 // easier 820 } 821 822 // find data sequence 823 if (rChar == 'x' && aDataStartIdx[oi] == -1) 824 { 825 aDataStartIdx[oi] = ii; 826 827 // get length of data sequence 828 sal_Int32 nL = 0; 829 sal_Char c; 830 while (ii< iiEnd && 'x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) 831 { 832 ++nL; ++ii; 833 } 834 aDataLen[oi] = nL; 835 836 // check that there is no other seperate sequence of data 837 // to be found because that is not supported 838 while (ii < iiEnd) 839 { 840 if ('x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) 841 throw lang::IllegalArgumentException(); 842 ++ii; 843 } 844 } 845 else 846 ++ii; 847 } 848 } 849 850 // make some other consistency checks while calculating 851 // the number of XLabeledDataSequence to build: 852 // - labels should always be used or not at all 853 // - the data sequences should have equal non-zero length 854 sal_Int32 nNumLDS = 0; 855 if (oiEnd > 0) 856 { 857 sal_Int32 nFirstSeqLen = 0; 858 sal_Int32 nFirstSeqLabelIdx = -1; 859 for (oi = 0; oi < oiEnd; ++oi) 860 { 861 sal_Bool bFirstFound = sal_False; 862 // row/col used at all? 863 if (aDataStartIdx[oi] != -1 && 864 (!bFirstIsLabel || aLabelIdx[oi] != -1)) 865 { 866 ++nNumLDS; 867 if (!bFirstFound) 868 { 869 nFirstSeqLen = aDataLen[oi]; 870 nFirstSeqLabelIdx = aLabelIdx[oi]; 871 bFirstFound = sal_True; 872 } 873 else 874 { 875 if (nFirstSeqLen != aDataLen[oi] || 876 nFirstSeqLabelIdx != aLabelIdx[oi]) 877 throw lang::IllegalArgumentException(); 878 } 879 } 880 } 881 } 882 if (nNumLDS == 0) 883 throw lang::IllegalArgumentException(); 884 885 // now we should have all necessary data to build a proper DataSource 886 // thus if we came this far there should be no further problem 887 if (bTestOnly) 888 return xRes; // have createDataSourcePossible return true 889 890 // create data source from found label and data sequences 891 uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aLabelSeqs( nNumLDS ); 892 uno::Reference< chart2::data::XDataSequence > *pLabelSeqs = aLabelSeqs.getArray(); 893 uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aDataSeqs( nNumLDS ); 894 uno::Reference< chart2::data::XDataSequence > *pDataSeqs = aDataSeqs.getArray(); 895 sal_Int32 nSeqsIdx = 0; 896 for (oi = 0; oi < oiEnd; ++oi) 897 { 898 // row/col not used? (see if-statement above where nNumLDS was counted) 899 if (!(aDataStartIdx[oi] != -1 && 900 (!bFirstIsLabel || aLabelIdx[oi] != -1))) 901 continue; 902 903 // get cell ranges for label and data 904 // 905 SwRangeDescriptor aLabelDesc; 906 SwRangeDescriptor aDataDesc; 907 if (bDtaSrcIsColumns) // use columns 908 { 909 aLabelDesc.nTop = aLabelIdx[oi]; 910 aLabelDesc.nLeft = oi; 911 aLabelDesc.nBottom = aLabelDesc.nTop; 912 aLabelDesc.nRight = oi; 913 914 aDataDesc.nTop = aDataStartIdx[oi]; 915 aDataDesc.nLeft = oi; 916 aDataDesc.nBottom = aDataDesc.nTop + aDataLen[oi] - 1; 917 aDataDesc.nRight = oi; 918 } 919 else // use rows 920 { 921 aLabelDesc.nTop = oi; 922 aLabelDesc.nLeft = aLabelIdx[oi]; 923 aLabelDesc.nBottom = oi; 924 aLabelDesc.nRight = aLabelDesc.nLeft; 925 926 aDataDesc.nTop = oi; 927 aDataDesc.nLeft = aDataStartIdx[oi]; 928 aDataDesc.nBottom = oi; 929 aDataDesc.nRight = aDataDesc.nLeft + aDataLen[oi] - 1; 930 } 931 String aBaseName( pTblFmt->GetName() ); 932 aBaseName += '.'; 933 // 934 String aLabelRange; 935 if (aLabelIdx[oi] != -1) 936 { 937 aLabelRange += aBaseName; 938 aLabelRange += lcl_GetCellName( aLabelDesc.nLeft, aLabelDesc.nTop ); 939 aLabelRange += ':'; 940 aLabelRange += lcl_GetCellName( aLabelDesc.nRight, aLabelDesc.nBottom ); 941 } 942 // 943 String aDataRange; 944 if (aDataStartIdx[oi] != -1) 945 { 946 aDataRange += aBaseName; 947 aDataRange += lcl_GetCellName( aDataDesc.nLeft, aDataDesc.nTop ); 948 aDataRange += ':'; 949 aDataRange += lcl_GetCellName( aDataDesc.nRight, aDataDesc.nBottom ); 950 } 951 952 // get cursors spanning the cell ranges for label and data 953 SwUnoCrsr *pLabelUnoCrsr = 0; 954 SwUnoCrsr *pDataUnoCrsr = 0; 955 GetFormatAndCreateCursorFromRangeRep( pDoc, aLabelRange, &pTblFmt, &pLabelUnoCrsr); 956 GetFormatAndCreateCursorFromRangeRep( pDoc, aDataRange, &pTblFmt, &pDataUnoCrsr); 957 958 // create XDataSequence's from cursors 959 if (pLabelUnoCrsr) 960 pLabelSeqs[ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pLabelUnoCrsr ); 961 DBG_ASSERT( pDataUnoCrsr, "pointer to data sequence missing" ); 962 if (pDataUnoCrsr) 963 pDataSeqs [ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pDataUnoCrsr ); 964 if (pLabelUnoCrsr || pDataUnoCrsr) 965 ++nSeqsIdx; 966 } 967 DBG_ASSERT( nSeqsIdx == nNumLDS, 968 "mismatch between sequence size and num,ber of entries" ); 969 970 // build data source from data and label sequences 971 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLDS( nNumLDS ); 972 uno::Reference< chart2::data::XLabeledDataSequence > *pLDS = aLDS.getArray(); 973 for (sal_Int32 i = 0; i < nNumLDS; ++i) 974 { 975 SwChartLabeledDataSequence *pLabeledDtaSeq = new SwChartLabeledDataSequence; 976 pLabeledDtaSeq->setLabel( pLabelSeqs[i] ); 977 pLabeledDtaSeq->setValues( pDataSeqs[i] ); 978 pLDS[i] = pLabeledDtaSeq; 979 } 980 981 // apply 'SequenceMapping' if it was provided 982 sal_Int32 nSequenceMappingLen = aSequenceMapping.getLength(); 983 if (nSequenceMappingLen) 984 { 985 sal_Int32 *pSequenceMapping = aSequenceMapping.getArray(); 986 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aOld_LDS( aLDS ); 987 uno::Reference< chart2::data::XLabeledDataSequence > *pOld_LDS = aOld_LDS.getArray(); 988 989 sal_Int32 nNewCnt = 0; 990 for (sal_Int32 i = 0; i < nSequenceMappingLen; ++i) 991 { 992 // check that index to be used is valid 993 // and has not yet been used 994 sal_Int32 nIdx = pSequenceMapping[i]; 995 if (0 <= nIdx && nIdx < nNumLDS && pOld_LDS[nIdx].is()) 996 { 997 pLDS[nNewCnt++] = pOld_LDS[nIdx]; 998 999 // mark index as being used already (avoids duplicate entries) 1000 pOld_LDS[nIdx].clear(); 1001 } 1002 } 1003 // add not yet used 'old' sequences to new one 1004 for (sal_Int32 i = 0; i < nNumLDS; ++i) 1005 { 1006 #if OSL_DEBUG_LEVEL > 1 1007 if (!pOld_LDS[i].is()) 1008 i = i; 1009 #endif 1010 if (pOld_LDS[i].is()) 1011 pLDS[nNewCnt++] = pOld_LDS[i]; 1012 } 1013 DBG_ASSERT( nNewCnt == nNumLDS, "unexpected size of resulting sequence" ); 1014 } 1015 1016 xRes = new SwChartDataSource( aLDS ); 1017 } 1018 } 1019 1020 return xRes; 1021 } 1022 1023 sal_Bool SAL_CALL SwChartDataProvider::createDataSourcePossible( 1024 const uno::Sequence< beans::PropertyValue >& rArguments ) 1025 throw (uno::RuntimeException) 1026 { 1027 vos::OGuard aGuard( Application::GetSolarMutex() ); 1028 1029 sal_Bool bPossible = sal_True; 1030 try 1031 { 1032 Impl_createDataSource( rArguments, sal_True ); 1033 } 1034 catch (lang::IllegalArgumentException &) 1035 { 1036 bPossible = sal_False; 1037 } 1038 1039 return bPossible; 1040 } 1041 1042 uno::Reference< chart2::data::XDataSource > SAL_CALL SwChartDataProvider::createDataSource( 1043 const uno::Sequence< beans::PropertyValue >& rArguments ) 1044 throw (lang::IllegalArgumentException, uno::RuntimeException) 1045 { 1046 vos::OGuard aGuard( Application::GetSolarMutex() ); 1047 return Impl_createDataSource( rArguments ); 1048 } 1049 1050 //////////////////////////////////////////////////////////// 1051 // SwChartDataProvider::GetBrokenCellRangeForExport 1052 // 1053 // fix for #i79009 1054 // we need to return a property that has the same value as the property 1055 // 'CellRangeRepresentation' but for all rows which are increased by one. 1056 // E.g. Table1:A1:D5 -> Table1:A2:D6 1057 // Since the problem is only for old charts which did not support multiple 1058 // we do not need to provide that property/string if the 'CellRangeRepresentation' 1059 // contains multiple ranges. 1060 OUString SwChartDataProvider::GetBrokenCellRangeForExport( 1061 const OUString &rCellRangeRepresentation ) 1062 { 1063 OUString aRes; 1064 1065 // check that we do not have multiple ranges 1066 if (-1 == rCellRangeRepresentation.indexOf( ';' )) 1067 { 1068 // get current cell and table names 1069 String aTblName, aStartCell, aEndCell; 1070 GetTableAndCellsFromRangeRep( rCellRangeRepresentation, 1071 aTblName, aStartCell, aEndCell, sal_False ); 1072 sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; 1073 lcl_GetCellPosition( aStartCell, nStartCol, nStartRow ); 1074 lcl_GetCellPosition( aEndCell, nEndCol, nEndRow ); 1075 1076 // get new cell names 1077 ++nStartRow; 1078 ++nEndRow; 1079 aStartCell = lcl_GetCellName( nStartCol, nStartRow ); 1080 aEndCell = lcl_GetCellName( nEndCol, nEndRow ); 1081 1082 aRes = GetRangeRepFromTableAndCells( aTblName, 1083 aStartCell, aEndCell, sal_False ); 1084 } 1085 1086 return aRes; 1087 } 1088 1089 uno::Sequence< beans::PropertyValue > SAL_CALL SwChartDataProvider::detectArguments( 1090 const uno::Reference< chart2::data::XDataSource >& xDataSource ) 1091 throw (uno::RuntimeException) 1092 { 1093 vos::OGuard aGuard( Application::GetSolarMutex() ); 1094 if (bDisposed) 1095 throw lang::DisposedException(); 1096 1097 uno::Sequence< beans::PropertyValue > aResult; 1098 if (!xDataSource.is()) 1099 return aResult; 1100 1101 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDS_LDS( xDataSource->getDataSequences() ); 1102 const uno::Reference< chart2::data::XLabeledDataSequence > *pDS_LDS = aDS_LDS.getConstArray(); 1103 sal_Int32 nNumDS_LDS = aDS_LDS.getLength(); 1104 1105 if (nNumDS_LDS == 0) 1106 { 1107 DBG_WARNING( "XLabeledDataSequence in data source contains 0 entries" ); 1108 return aResult; 1109 } 1110 1111 SwFrmFmt *pTableFmt = 0; 1112 SwTable *pTable = 0; 1113 String aTableName; 1114 sal_Int32 nTableRows = 0; 1115 sal_Int32 nTableCols = 0; 1116 1117 // data used to build 'CellRangeRepresentation' from later on 1118 std::vector< std::vector< sal_Char > > aMap; 1119 1120 uno::Sequence< sal_Int32 > aSequenceMapping( nNumDS_LDS ); 1121 sal_Int32 *pSequenceMapping = aSequenceMapping.getArray(); 1122 1123 String aCellRanges; 1124 sal_Int16 nDtaSrcIsColumns = -1;// -1: don't know yet, 0: false, 1: true -2: neither 1125 sal_Int32 nLabelSeqLen = -1; // used to see if labels are always used or not and have 1126 // the expected size of 1 (i.e. if FirstCellAsLabel can 1127 // be determined) 1128 // -1: don't know yet, 0: not used, 1: always a single labe cell, ... 1129 // -2: neither/failed 1130 // sal_Int32 nValuesSeqLen = -1; // used to see if all value sequences have the same size 1131 for (sal_Int32 nDS1 = 0; nDS1 < nNumDS_LDS; ++nDS1) 1132 { 1133 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledDataSequence( pDS_LDS[nDS1] ); 1134 if( !xLabeledDataSequence.is() ) 1135 { 1136 DBG_ERROR("got NULL for XLabeledDataSequence from Data source"); 1137 continue; 1138 } 1139 const uno::Reference< chart2::data::XDataSequence > xCurLabel( xLabeledDataSequence->getLabel(), uno::UNO_QUERY ); 1140 const uno::Reference< chart2::data::XDataSequence > xCurValues( xLabeledDataSequence->getValues(), uno::UNO_QUERY ); 1141 1142 // get sequence lengths for label and values. 1143 // (0 length is Ok) 1144 sal_Int32 nCurLabelSeqLen = -1; 1145 sal_Int32 nCurValuesSeqLen = -1; 1146 if (xCurLabel.is()) 1147 nCurLabelSeqLen = xCurLabel->getData().getLength(); 1148 if (xCurValues.is()) 1149 nCurValuesSeqLen = xCurValues->getData().getLength(); 1150 1151 // check for consistent use of 'first cell as label' 1152 if (nLabelSeqLen == -1) // set initial value to compare with below further on 1153 nLabelSeqLen = nCurLabelSeqLen; 1154 if (nLabelSeqLen != nCurLabelSeqLen) 1155 nLabelSeqLen = -2; // failed / no consistent use of label cells 1156 1157 // get table and cell names for label and values data sequences 1158 // (start and end cell will be sorted, i.e. start cell <= end cell) 1159 String aLabelTblName, aLabelStartCell, aLabelEndCell; 1160 String aValuesTblName, aValuesStartCell, aValuesEndCell; 1161 String aLabelRange, aValuesRange; 1162 if (xCurLabel.is()) 1163 aLabelRange = xCurLabel->getSourceRangeRepresentation(); 1164 if (xCurValues.is()) 1165 aValuesRange = xCurValues->getSourceRangeRepresentation(); 1166 if ((aLabelRange.Len() && !GetTableAndCellsFromRangeRep( aLabelRange, 1167 aLabelTblName, aLabelStartCell, aLabelEndCell )) || 1168 !GetTableAndCellsFromRangeRep( aValuesRange, 1169 aValuesTblName, aValuesStartCell, aValuesEndCell )) 1170 { 1171 return aResult; // failed -> return empty property sequence 1172 } 1173 1174 // make sure all sequences use the same table 1175 if (!aTableName.Len()) 1176 aTableName = aValuesTblName; // get initial value to compare with 1177 if (!aTableName.Len() || 1178 aTableName != aValuesTblName || 1179 (aLabelTblName.Len() && aTableName != aLabelTblName)) 1180 { 1181 return aResult; // failed -> return empty property sequence 1182 } 1183 1184 1185 // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting 1186 // first and last cell used in both sequences 1187 // 1188 sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; 1189 String aCell( aLabelStartCell.Len() ? aLabelStartCell : aValuesStartCell ); 1190 DBG_ASSERT( aCell.Len() , "start cell missing?" ); 1191 lcl_GetCellPosition( aCell, nFirstCol, nFirstRow); 1192 lcl_GetCellPosition( aValuesEndCell, nLastCol, nLastRow); 1193 // 1194 sal_Int16 nDirection = -1; // -1: not yet set, 0: columns, 1: rows, -2: failed 1195 if (nFirstCol == nLastCol && nFirstRow == nLastRow) // a single cell... 1196 { 1197 DBG_ASSERT( nCurLabelSeqLen == 0 && nCurValuesSeqLen == 1, 1198 "trying to determine 'DataRowSource': something's fishy... should have been a single cell"); 1199 nDirection = 0; // default direction for a single cell should be 'columns' 1200 } 1201 else // more than one cell is availabale (in values and label together!) 1202 { 1203 if (nFirstCol == nLastCol && nFirstRow != nLastRow) 1204 nDirection = 1; 1205 else if (nFirstCol != nLastCol && nFirstRow == nLastRow) 1206 nDirection = 0; 1207 else 1208 { 1209 DBG_ERROR( "trying to determine 'DataRowSource': unexpected case found" ); 1210 nDirection = -2; 1211 } 1212 } 1213 // check for consistent direction of data source 1214 if (nDtaSrcIsColumns == -1) // set initial value to compare with below 1215 nDtaSrcIsColumns = nDirection; 1216 if (nDtaSrcIsColumns != nDirection) 1217 { 1218 nDtaSrcIsColumns = -2; // failed 1219 } 1220 1221 1222 if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) 1223 { 1224 // build data to obtain 'SequenceMapping' later on 1225 // 1226 DBG_ASSERT( nDtaSrcIsColumns == 0 || /* rows */ 1227 nDtaSrcIsColumns == 1, /* columns */ 1228 "unexpected value for 'nDtaSrcIsColumns'" ); 1229 pSequenceMapping[nDS1] = nDtaSrcIsColumns ? nFirstCol : nFirstRow; 1230 1231 1232 // build data used to determine 'CellRangeRepresentation' later on 1233 // 1234 GetTableByName( *pDoc, aTableName, &pTableFmt, &pTable ); 1235 if (!pTable || pTable->IsTblComplex()) 1236 return aResult; // failed -> return empty property sequence 1237 nTableRows = pTable->GetTabLines().Count(); 1238 nTableCols = pTable->GetTabLines().GetObject(0)->GetTabBoxes().Count(); 1239 aMap.resize( nTableRows ); 1240 for (sal_Int32 i = 0; i < nTableRows; ++i) 1241 aMap[i].resize( nTableCols ); 1242 // 1243 if (aLabelStartCell.Len() && aLabelEndCell.Len()) 1244 { 1245 sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; 1246 lcl_GetCellPosition( aLabelStartCell, nStartCol, nStartRow ); 1247 lcl_GetCellPosition( aLabelEndCell, nEndCol, nEndRow ); 1248 if (nStartRow < 0 || nEndRow >= nTableRows || 1249 nStartCol < 0 || nEndCol >= nTableCols) 1250 { 1251 return aResult; // failed -> return empty property sequence 1252 } 1253 for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) 1254 { 1255 for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) 1256 { 1257 sal_Char &rChar = aMap[i][k]; 1258 if (rChar == '\0') // check for overlapping values and/or labels 1259 rChar = 'L'; 1260 else 1261 return aResult; // failed -> return empty property sequence 1262 } 1263 } 1264 } 1265 if (aValuesStartCell.Len() && aValuesEndCell.Len()) 1266 { 1267 sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; 1268 lcl_GetCellPosition( aValuesStartCell, nStartCol, nStartRow ); 1269 lcl_GetCellPosition( aValuesEndCell, nEndCol, nEndRow ); 1270 if (nStartRow < 0 || nEndRow >= nTableRows || 1271 nStartCol < 0 || nEndCol >= nTableCols) 1272 { 1273 return aResult; // failed -> return empty property sequence 1274 } 1275 for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) 1276 { 1277 for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) 1278 { 1279 sal_Char &rChar = aMap[i][k]; 1280 if (rChar == '\0') // check for overlapping values and/or labels 1281 rChar = 'x'; 1282 else 1283 return aResult; // failed -> return empty property sequence 1284 } 1285 } 1286 } 1287 } 1288 1289 #if OSL_DEBUG_LEVEL > 1 1290 // do some extra sanity checking that the length of the sequences 1291 // matches their range representation 1292 { 1293 sal_Int32 nStartRow = -1, nStartCol = -1, nEndRow = -1, nEndCol = -1; 1294 if (xCurLabel.is()) 1295 { 1296 lcl_GetCellPosition( aLabelStartCell, nStartCol, nStartRow); 1297 lcl_GetCellPosition( aLabelEndCell, nEndCol, nEndRow); 1298 DBG_ASSERT( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurLabel->getData().getLength()) || 1299 (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurLabel->getData().getLength()), 1300 "label sequence length does not match range representation!" ); 1301 } 1302 if (xCurValues.is()) 1303 { 1304 lcl_GetCellPosition( aValuesStartCell, nStartCol, nStartRow); 1305 lcl_GetCellPosition( aValuesEndCell, nEndCol, nEndRow); 1306 DBG_ASSERT( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurValues->getData().getLength()) || 1307 (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurValues->getData().getLength()), 1308 "value sequence length does not match range representation!" ); 1309 } 1310 } 1311 #endif 1312 } // for 1313 1314 1315 // build value for 'CellRangeRepresentation' 1316 // 1317 String aCellRangeBase( aTableName ); 1318 aCellRangeBase += '.'; 1319 String aCurRange; 1320 for (sal_Int32 i = 0; i < nTableRows; ++i) 1321 { 1322 for (sal_Int32 k = 0; k < nTableCols; ++k) 1323 { 1324 if (aMap[i][k] != '\0') // top-left cell of a sub-range found 1325 { 1326 // find rectangular sub-range to use 1327 sal_Int32 nRowIndex1 = i; // row index 1328 sal_Int32 nColIndex1 = k; // column index 1329 sal_Int32 nRowSubLen = 0; 1330 sal_Int32 nColSubLen = 0; 1331 while (nRowIndex1 < nTableRows && aMap[nRowIndex1++][k] != '\0') 1332 ++nRowSubLen; 1333 // be aware of shifted sequences! 1334 // (according to the checks done prior the length should be ok) 1335 while (nColIndex1 < nTableCols && aMap[i][nColIndex1] != '\0' 1336 && aMap[i + nRowSubLen-1][nColIndex1] != '\0') 1337 { 1338 ++nColIndex1; 1339 ++nColSubLen; 1340 } 1341 String aStartCell( lcl_GetCellName( k, i ) ); 1342 String aEndCell( lcl_GetCellName( k + nColSubLen - 1, i + nRowSubLen - 1) ); 1343 aCurRange = aCellRangeBase; 1344 aCurRange += aStartCell; 1345 aCurRange += ':'; 1346 aCurRange += aEndCell; 1347 if (aCellRanges.Len()) 1348 aCellRanges += ';'; 1349 aCellRanges += aCurRange; 1350 1351 // clear already found sub-range from map 1352 for (sal_Int32 nRowIndex2 = 0; nRowIndex2 < nRowSubLen; ++nRowIndex2) 1353 for (sal_Int32 nColumnIndex2 = 0; nColumnIndex2 < nColSubLen; ++nColumnIndex2) 1354 aMap[i + nRowIndex2][k + nColumnIndex2] = '\0'; 1355 } 1356 } 1357 } 1358 // to be nice to the user we now sort the cell ranges according to 1359 // rows or columns depending on the direction used in the data source 1360 uno::Sequence< OUString > aSortedRanges; 1361 GetSubranges( aCellRanges, aSortedRanges, sal_False /*sub ranges should already be normalized*/ ); 1362 SortSubranges( aSortedRanges, (nDtaSrcIsColumns == 1) ); 1363 sal_Int32 nSortedRanges = aSortedRanges.getLength(); 1364 const OUString *pSortedRanges = aSortedRanges.getConstArray(); 1365 OUString aSortedCellRanges; 1366 for (sal_Int32 i = 0; i < nSortedRanges; ++i) 1367 { 1368 if (aSortedCellRanges.getLength()) 1369 aSortedCellRanges += OUString::valueOf( (sal_Unicode) ';'); 1370 aSortedCellRanges += pSortedRanges[i]; 1371 } 1372 1373 1374 // build value for 'SequenceMapping' 1375 // 1376 uno::Sequence< sal_Int32 > aSortedMapping( aSequenceMapping ); 1377 sal_Int32 *pSortedMapping = aSortedMapping.getArray(); 1378 std::sort( pSortedMapping, pSortedMapping + aSortedMapping.getLength() ); 1379 DBG_ASSERT( aSortedMapping.getLength() == nNumDS_LDS, "unexpected size of sequence" ); 1380 sal_Bool bNeedSequenceMapping = sal_False; 1381 for (sal_Int32 i = 0; i < nNumDS_LDS; ++i) 1382 { 1383 sal_Int32 *pIt = std::find( pSortedMapping, pSortedMapping + nNumDS_LDS, 1384 pSequenceMapping[i] ); 1385 DBG_ASSERT( pIt, "index not found" ); 1386 if (!pIt) 1387 return aResult; // failed -> return empty property sequence 1388 pSequenceMapping[i] = pIt - pSortedMapping; 1389 1390 if (i != pSequenceMapping[i]) 1391 bNeedSequenceMapping = sal_True; 1392 } 1393 1394 // check if 'SequenceMapping' is actually not required... 1395 // (don't write unnecessary properties to the XML file) 1396 if (!bNeedSequenceMapping) 1397 aSequenceMapping.realloc(0); 1398 1399 1400 #ifdef TL_NOT_USED // in the end chart2 did not want to have the sequence minimized 1401 // try to shorten the 'SequenceMapping' as much as possible 1402 sal_Int32 k; 1403 for (k = nNumDS_LDS - 1; k >= 0; --k) 1404 { 1405 if (pSequenceMapping[k] != k) 1406 break; 1407 } 1408 aSequenceMapping.realloc( k + 1 ); 1409 #endif 1410 1411 1412 // 1413 // build resulting properties 1414 // 1415 DBG_ASSERT(nLabelSeqLen >= 0 || nLabelSeqLen == -2 /*not used*/, 1416 "unexpected value for 'nLabelSeqLen'" ); 1417 sal_Bool bFirstCellIsLabel = sal_False; // default value if 'nLabelSeqLen' could not properly determined 1418 if (nLabelSeqLen > 0) // == 0 means no label sequence in use 1419 bFirstCellIsLabel = sal_True; 1420 // 1421 DBG_ASSERT( aSortedCellRanges.getLength(), "CellRangeRepresentation missing" ); 1422 OUString aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges ) ); 1423 // 1424 aResult.realloc(5); 1425 sal_Int32 nProps = 0; 1426 aResult[nProps ].Name = C2U("FirstCellAsLabel"); 1427 aResult[nProps++].Value <<= bFirstCellIsLabel; 1428 aResult[nProps ].Name = C2U("CellRangeRepresentation"); 1429 aResult[nProps++].Value <<= aSortedCellRanges; 1430 if (0 != aBrokenCellRangeForExport.getLength()) 1431 { 1432 aResult[nProps ].Name = C2U("BrokenCellRangeForExport"); 1433 aResult[nProps++].Value <<= aBrokenCellRangeForExport; 1434 } 1435 if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) 1436 { 1437 chart::ChartDataRowSource eDataRowSource = (nDtaSrcIsColumns == 1) ? 1438 chart::ChartDataRowSource_COLUMNS : chart::ChartDataRowSource_ROWS; 1439 aResult[nProps ].Name = C2U("DataRowSource"); 1440 aResult[nProps++].Value <<= eDataRowSource; 1441 1442 if (aSequenceMapping.getLength() != 0) 1443 { 1444 aResult[nProps ].Name = C2U("SequenceMapping"); 1445 aResult[nProps++].Value <<= aSequenceMapping; 1446 } 1447 } 1448 aResult.realloc( nProps ); 1449 1450 return aResult; 1451 } 1452 1453 uno::Reference< chart2::data::XDataSequence > SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation( 1454 const OUString& rRangeRepresentation, sal_Bool bTestOnly ) 1455 throw (lang::IllegalArgumentException, uno::RuntimeException) 1456 { 1457 if (bDisposed) 1458 throw lang::DisposedException(); 1459 1460 SwFrmFmt *pTblFmt = 0; // pointer to table format 1461 SwUnoCrsr *pUnoCrsr = 0; // pointer to new created cursor spanning the cell range 1462 GetFormatAndCreateCursorFromRangeRep( pDoc, rRangeRepresentation, 1463 &pTblFmt, &pUnoCrsr ); 1464 if (!pTblFmt || !pUnoCrsr) 1465 throw lang::IllegalArgumentException(); 1466 1467 // check that cursors point and mark are in a single row or column. 1468 String aCellRange( GetCellRangeName( *pTblFmt, *pUnoCrsr ) ); 1469 SwRangeDescriptor aDesc; 1470 FillRangeDescriptor( aDesc, aCellRange ); 1471 if (aDesc.nTop != aDesc.nBottom && aDesc.nLeft != aDesc.nRight) 1472 throw lang::IllegalArgumentException(); 1473 1474 DBG_ASSERT( pTblFmt && pUnoCrsr, "table format or cursor missing" ); 1475 uno::Reference< chart2::data::XDataSequence > xDataSeq; 1476 if (!bTestOnly) 1477 xDataSeq = new SwChartDataSequence( *this, *pTblFmt, pUnoCrsr ); 1478 1479 return xDataSeq; 1480 } 1481 1482 sal_Bool SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentationPossible( 1483 const OUString& rRangeRepresentation ) 1484 throw (uno::RuntimeException) 1485 { 1486 vos::OGuard aGuard( Application::GetSolarMutex() ); 1487 1488 sal_Bool bPossible = sal_True; 1489 try 1490 { 1491 Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation, sal_True ); 1492 } 1493 catch (lang::IllegalArgumentException &) 1494 { 1495 bPossible = sal_False; 1496 } 1497 1498 return bPossible; 1499 } 1500 1501 uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentation( 1502 const OUString& rRangeRepresentation ) 1503 throw (lang::IllegalArgumentException, uno::RuntimeException) 1504 { 1505 vos::OGuard aGuard( Application::GetSolarMutex() ); 1506 return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation ); 1507 } 1508 1509 1510 uno::Reference< sheet::XRangeSelection > SAL_CALL SwChartDataProvider::getRangeSelection( ) 1511 throw (uno::RuntimeException) 1512 { 1513 // note: it is no error to return nothing here 1514 return uno::Reference< sheet::XRangeSelection >(); 1515 } 1516 1517 1518 void SAL_CALL SwChartDataProvider::dispose( ) 1519 throw (uno::RuntimeException) 1520 { 1521 sal_Bool bMustDispose( sal_False ); 1522 { 1523 osl::MutexGuard aGuard( GetChartMutex() ); 1524 bMustDispose = !bDisposed; 1525 if (!bDisposed) 1526 bDisposed = sal_True; 1527 } 1528 if (bMustDispose) 1529 { 1530 // dispose all data-sequences 1531 Map_Set_DataSequenceRef_t::iterator aIt( aDataSequences.begin() ); 1532 while (aIt != aDataSequences.end()) 1533 { 1534 DisposeAllDataSequences( (*aIt).first ); 1535 ++aIt; 1536 } 1537 // release all references to data-sequences 1538 aDataSequences.clear(); 1539 1540 // require listeners to release references to this object 1541 lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) ); 1542 aEvtListeners.disposeAndClear( aEvtObj ); 1543 } 1544 } 1545 1546 1547 void SAL_CALL SwChartDataProvider::addEventListener( 1548 const uno::Reference< lang::XEventListener >& rxListener ) 1549 throw (uno::RuntimeException) 1550 { 1551 osl::MutexGuard aGuard( GetChartMutex() ); 1552 if (!bDisposed && rxListener.is()) 1553 aEvtListeners.addInterface( rxListener ); 1554 } 1555 1556 1557 void SAL_CALL SwChartDataProvider::removeEventListener( 1558 const uno::Reference< lang::XEventListener >& rxListener ) 1559 throw (uno::RuntimeException) 1560 { 1561 osl::MutexGuard aGuard( GetChartMutex() ); 1562 if (!bDisposed && rxListener.is()) 1563 aEvtListeners.removeInterface( rxListener ); 1564 } 1565 1566 1567 1568 OUString SAL_CALL SwChartDataProvider::getImplementationName( ) 1569 throw (uno::RuntimeException) 1570 { 1571 return C2U("SwChartDataProvider"); 1572 } 1573 1574 1575 sal_Bool SAL_CALL SwChartDataProvider::supportsService( 1576 const OUString& rServiceName ) 1577 throw (uno::RuntimeException) 1578 { 1579 vos::OGuard aGuard( Application::GetSolarMutex() ); 1580 return rServiceName.equalsAscii( SN_DATA_PROVIDER ); 1581 } 1582 1583 1584 uno::Sequence< OUString > SAL_CALL SwChartDataProvider::getSupportedServiceNames( ) 1585 throw (uno::RuntimeException) 1586 { 1587 vos::OGuard aGuard( Application::GetSolarMutex() ); 1588 uno::Sequence< OUString > aRes(1); 1589 aRes.getArray()[0] = C2U( SN_DATA_PROVIDER ); 1590 return aRes; 1591 } 1592 1593 1594 void SwChartDataProvider::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 1595 { 1596 // actually this function should be superfluous (need to check later) 1597 ClientModify(this, pOld, pNew ); 1598 } 1599 1600 1601 void SwChartDataProvider::AddDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence ) 1602 { 1603 aDataSequences[ &rTable ].insert( rxDataSequence ); 1604 } 1605 1606 1607 void SwChartDataProvider::RemoveDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence ) 1608 { 1609 aDataSequences[ &rTable ].erase( rxDataSequence ); 1610 } 1611 1612 1613 void SwChartDataProvider::InvalidateTable( const SwTable *pTable ) 1614 { 1615 DBG_ASSERT( pTable, "table pointer is NULL" ); 1616 if (pTable) 1617 { 1618 if (!bDisposed) 1619 pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); 1620 1621 const Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ]; 1622 Set_DataSequenceRef_t::iterator aIt( rSet.begin() ); 1623 while (aIt != rSet.end()) 1624 { 1625 // uno::Reference< util::XModifiable > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); 1626 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1627 uno::Reference< util::XModifiable > xRef( xTemp, uno::UNO_QUERY ); 1628 if (xRef.is()) 1629 { 1630 // mark the sequence as 'dirty' and notify listeners 1631 xRef->setModified( sal_True ); 1632 } 1633 ++aIt; 1634 } 1635 } 1636 } 1637 1638 1639 sal_Bool SwChartDataProvider::DeleteBox( const SwTable *pTable, const SwTableBox &rBox ) 1640 { 1641 sal_Bool bRes = sal_False; 1642 DBG_ASSERT( pTable, "table pointer is NULL" ); 1643 if (pTable) 1644 { 1645 if (!bDisposed) 1646 pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); 1647 1648 Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ]; 1649 1650 // iterate over all data-sequences for that table... 1651 Set_DataSequenceRef_t::iterator aIt( rSet.begin() ); 1652 Set_DataSequenceRef_t::iterator aEndIt( rSet.end() ); 1653 Set_DataSequenceRef_t::iterator aDelIt; // iterator used for deletion when appropriate 1654 while (aIt != aEndIt) 1655 { 1656 SwChartDataSequence *pDataSeq = 0; 1657 sal_Bool bNowEmpty = sal_False; 1658 1659 // check if weak reference is still valid... 1660 // uno::Reference< chart2::data::XDataSequence > xRef( uno::Reference< chart2::data::XDataSequence>(*aIt), uno::UNO_QUERY ); 1661 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1662 uno::Reference< chart2::data::XDataSequence > xRef( xTemp, uno::UNO_QUERY ); 1663 if (xRef.is()) 1664 { 1665 // then delete that table box (check if implementation cursor needs to be adjusted) 1666 pDataSeq = static_cast< SwChartDataSequence * >( xRef.get() ); 1667 if (pDataSeq) 1668 { 1669 #if OSL_DEBUG_LEVEL > 1 1670 OUString aRangeStr( pDataSeq->getSourceRangeRepresentation() ); 1671 #endif 1672 bNowEmpty = pDataSeq->DeleteBox( rBox ); 1673 if (bNowEmpty) 1674 aDelIt = aIt; 1675 } 1676 } 1677 ++aIt; 1678 1679 if (bNowEmpty) 1680 { 1681 rSet.erase( aDelIt ); 1682 if (pDataSeq) 1683 pDataSeq->dispose(); // the current way to tell chart that sth. got removed 1684 } 1685 } 1686 } 1687 return bRes; 1688 } 1689 1690 1691 void SwChartDataProvider::DisposeAllDataSequences( const SwTable *pTable ) 1692 { 1693 DBG_ASSERT( pTable, "table pointer is NULL" ); 1694 if (pTable) 1695 { 1696 if (!bDisposed) 1697 pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); 1698 1699 //! make a copy of the STL container! 1700 //! This is necessary since calling 'dispose' will implicitly remove an element 1701 //! of the original container, and thus any iterator in the original container 1702 //! would become invalid. 1703 const Set_DataSequenceRef_t aSet( aDataSequences[ pTable ] ); 1704 1705 Set_DataSequenceRef_t::iterator aIt( aSet.begin() ); 1706 Set_DataSequenceRef_t::iterator aEndIt( aSet.end() ); 1707 while (aIt != aEndIt) 1708 { 1709 // uno::Reference< lang::XComponent > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); 1710 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1711 uno::Reference< lang::XComponent > xRef( xTemp, uno::UNO_QUERY ); 1712 if (xRef.is()) 1713 { 1714 xRef->dispose(); 1715 } 1716 ++aIt; 1717 } 1718 } 1719 } 1720 1721 1722 //////////////////////////////////////// 1723 // SwChartDataProvider::AddRowCols tries to notify charts of added columns 1724 // or rows and extends the value sequence respectively (if possible). 1725 // If those can be added to the end of existing value data-sequences those 1726 // sequences get mofdified accordingly and will send a modification 1727 // notification (calling 'setModified'). 1728 // 1729 // Since this function is a work-around for non existent Writer core functionality 1730 // (no arbitrary multi-selection in tables that can be used to define a 1731 // data-sequence) this function will be somewhat unreliable. 1732 // For example we will only try to adapt value sequences. For this we assume 1733 // that a sequence of length 1 is a label sequence and those with length >= 2 1734 // we presume to be value sequences. Also new cells can only be added in the 1735 // direction the value sequence is already pointing (rows / cols) and at the 1736 // start or end of the values data-sequence. 1737 // Nothing needs to be done if the new cells are in between the table cursors 1738 // point and mark since data-sequence are considered to consist of all cells 1739 // between those. 1740 // New rows/cols need to be added already to the table before calling 1741 // this function. 1742 // 1743 void SwChartDataProvider::AddRowCols( 1744 const SwTable &rTable, 1745 const SwSelBoxes& rBoxes, 1746 sal_uInt16 nLines, sal_Bool bBehind ) 1747 { 1748 if (rTable.IsTblComplex()) 1749 return; 1750 1751 const sal_uInt16 nBoxes = rBoxes.Count(); 1752 if (nBoxes < 1 || nLines < 1) 1753 return; 1754 1755 SwTableBox* pFirstBox = *( rBoxes.GetData() + 0 ); 1756 SwTableBox* pLastBox = *( rBoxes.GetData() + nBoxes - 1 ); 1757 1758 sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; 1759 if (pFirstBox && pLastBox) 1760 { 1761 lcl_GetCellPosition( pFirstBox->GetName(), nFirstCol, nFirstRow ); 1762 lcl_GetCellPosition( pLastBox->GetName(), nLastCol, nLastRow ); 1763 1764 bool bAddCols = false; // default; also to be used if nBoxes == 1 :-/ 1765 if (nFirstCol == nLastCol && nFirstRow != nLastRow) 1766 bAddCols = true; 1767 if (nFirstCol == nLastCol || nFirstRow == nLastRow) 1768 { 1769 //get range of indices in col/rows for new cells 1770 sal_Int32 nFirstNewCol = nFirstCol; 1771 sal_Int32 nLastNewCol = nLastCol; 1772 sal_Int32 nFirstNewRow = bBehind ? nFirstRow + 1 : nFirstRow - nLines; 1773 sal_Int32 nLastNewRow = nFirstNewRow - 1 + nLines; 1774 if (bAddCols) 1775 { 1776 DBG_ASSERT( nFirstCol == nLastCol, "column indices seem broken" ); 1777 nFirstNewCol = bBehind ? nFirstCol + 1 : nFirstCol - nLines; 1778 nLastNewCol = nFirstNewCol - 1 + nLines; 1779 nFirstNewRow = nFirstRow; 1780 nLastNewRow = nLastRow; 1781 } 1782 1783 // iterate over all data-sequences for the table 1784 const Set_DataSequenceRef_t &rSet = aDataSequences[ &rTable ]; 1785 Set_DataSequenceRef_t::iterator aIt( rSet.begin() ); 1786 while (aIt != rSet.end()) 1787 { 1788 // uno::Reference< chart2::data::XTextualDataSequence > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); 1789 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1790 uno::Reference< chart2::data::XTextualDataSequence > xRef( xTemp, uno::UNO_QUERY ); 1791 if (xRef.is()) 1792 { 1793 const sal_Int32 nLen = xRef->getTextualData().getLength(); 1794 if (nLen > 1) // value data-sequence ? 1795 { 1796 SwChartDataSequence *pDataSeq = 0; 1797 uno::Reference< lang::XUnoTunnel > xTunnel( xRef, uno::UNO_QUERY ); 1798 if(xTunnel.is()) 1799 { 1800 pDataSeq = reinterpret_cast< SwChartDataSequence * >( 1801 sal::static_int_cast< sal_IntPtr >( xTunnel->getSomething( SwChartDataSequence::getUnoTunnelId() ))); 1802 1803 if (pDataSeq) 1804 { 1805 SwRangeDescriptor aDesc; 1806 pDataSeq->FillRangeDesc( aDesc ); 1807 1808 chart::ChartDataRowSource eDRSource = chart::ChartDataRowSource_COLUMNS; 1809 if (aDesc.nTop == aDesc.nBottom && aDesc.nLeft != aDesc.nRight) 1810 eDRSource = chart::ChartDataRowSource_ROWS; 1811 1812 if (!bAddCols && eDRSource == chart::ChartDataRowSource_COLUMNS) 1813 { 1814 // add rows: extend affected columns by newly added row cells 1815 pDataSeq->ExtendTo( true, nFirstNewRow, nLines ); 1816 } 1817 else if (bAddCols && eDRSource == chart::ChartDataRowSource_ROWS) 1818 { 1819 // add cols: extend affected rows by newly added column cells 1820 pDataSeq->ExtendTo( false, nFirstNewCol, nLines ); 1821 } 1822 } 1823 } 1824 } 1825 } 1826 ++aIt; 1827 } 1828 1829 } 1830 } 1831 } 1832 1833 1834 // XRangeXMLConversion --------------------------------------------------- 1835 1836 rtl::OUString SAL_CALL SwChartDataProvider::convertRangeToXML( const rtl::OUString& rRangeRepresentation ) 1837 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 1838 { 1839 vos::OGuard aGuard( Application::GetSolarMutex() ); 1840 if (bDisposed) 1841 throw lang::DisposedException(); 1842 1843 String aRes; 1844 String aRangeRepresentation( rRangeRepresentation ); 1845 1846 // multiple ranges are delimeted by a ';' like in 1847 // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges! 1848 xub_StrLen nNumRanges = aRangeRepresentation.GetTokenCount( ';' ); 1849 SwTable* pFirstFoundTable = 0; // to check that only one table will be used 1850 for (sal_uInt16 i = 0; i < nNumRanges; ++i) 1851 { 1852 String aRange( aRangeRepresentation.GetToken(i, ';') ); 1853 SwFrmFmt *pTblFmt = 0; // pointer to table format 1854 // BM: For what should the check be necessary? for #i79009# it is required that NO check is done 1855 // SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist 1856 // std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr 1857 GetFormatAndCreateCursorFromRangeRep( pDoc, aRange, &pTblFmt, NULL ); 1858 if (!pTblFmt) 1859 throw lang::IllegalArgumentException(); 1860 // if (!pUnoCrsr) 1861 // throw uno::RuntimeException(); 1862 SwTable* pTable = SwTable::FindTable( pTblFmt ); 1863 if (pTable->IsTblComplex()) 1864 throw uno::RuntimeException(); 1865 1866 // check that there is only one table used in all ranges 1867 if (!pFirstFoundTable) 1868 pFirstFoundTable = pTable; 1869 if (pTable != pFirstFoundTable) 1870 throw lang::IllegalArgumentException(); 1871 1872 String aTblName; 1873 String aStartCell; 1874 String aEndCell; 1875 if (!GetTableAndCellsFromRangeRep( aRange, aTblName, aStartCell, aEndCell )) 1876 throw lang::IllegalArgumentException(); 1877 1878 sal_Int32 nCol, nRow; 1879 lcl_GetCellPosition( aStartCell, nCol, nRow ); 1880 if (nCol < 0 || nRow < 0) 1881 throw uno::RuntimeException(); 1882 1883 //!! following objects/functions are implemented in XMLRangeHelper.?xx 1884 //!! which is a copy of the respective file from chart2 !! 1885 XMLRangeHelper::CellRange aCellRange; 1886 aCellRange.aTableName = aTblName; 1887 aCellRange.aUpperLeft.nColumn = nCol; 1888 aCellRange.aUpperLeft.nRow = nRow; 1889 aCellRange.aUpperLeft.bIsEmpty = false; 1890 if (aStartCell != aEndCell && aEndCell.Len() != 0) 1891 { 1892 lcl_GetCellPosition( aEndCell, nCol, nRow ); 1893 if (nCol < 0 || nRow < 0) 1894 throw uno::RuntimeException(); 1895 1896 aCellRange.aLowerRight.nColumn = nCol; 1897 aCellRange.aLowerRight.nRow = nRow; 1898 aCellRange.aLowerRight.bIsEmpty = false; 1899 } 1900 String aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange ) ); 1901 if (aRes.Len()) // in case of multiple ranges add delimeter 1902 aRes.AppendAscii( " " ); 1903 aRes += aTmp; 1904 } 1905 1906 return aRes; 1907 } 1908 1909 rtl::OUString SAL_CALL SwChartDataProvider::convertRangeFromXML( const rtl::OUString& rXMLRange ) 1910 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 1911 { 1912 vos::OGuard aGuard( Application::GetSolarMutex() ); 1913 if (bDisposed) 1914 throw lang::DisposedException(); 1915 1916 String aRes; 1917 String aXMLRange( rXMLRange ); 1918 1919 // multiple ranges are delimeted by a ' ' like in 1920 // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges! 1921 xub_StrLen nNumRanges = aXMLRange.GetTokenCount( ' ' ); 1922 rtl::OUString aFirstFoundTable; // to check that only one table will be used 1923 for (sal_uInt16 i = 0; i < nNumRanges; ++i) 1924 { 1925 String aRange( aXMLRange.GetToken(i, ' ') ); 1926 1927 //!! following objects and function are implemented in XMLRangeHelper.?xx 1928 //!! which is a copy of the respective file from chart2 !! 1929 XMLRangeHelper::CellRange aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange )); 1930 1931 // check that there is only one table used in all ranges 1932 if (aFirstFoundTable.getLength() == 0) 1933 aFirstFoundTable = aCellRange.aTableName; 1934 if (aCellRange.aTableName != aFirstFoundTable) 1935 throw lang::IllegalArgumentException(); 1936 1937 OUString aTmp( aCellRange.aTableName ); 1938 aTmp += OUString::valueOf((sal_Unicode) '.'); 1939 aTmp += lcl_GetCellName( aCellRange.aUpperLeft.nColumn, 1940 aCellRange.aUpperLeft.nRow ); 1941 // does cell range consist of more than a single cell? 1942 if (!aCellRange.aLowerRight.bIsEmpty) 1943 { 1944 aTmp += OUString::valueOf((sal_Unicode) ':'); 1945 aTmp += lcl_GetCellName( aCellRange.aLowerRight.nColumn, 1946 aCellRange.aLowerRight.nRow ); 1947 } 1948 1949 if (aRes.Len()) // in case of multiple ranges add delimeter 1950 aRes.AppendAscii( ";" ); 1951 aRes += String(aTmp); 1952 } 1953 1954 return aRes; 1955 } 1956 1957 1958 ////////////////////////////////////////////////////////////////////// 1959 1960 SwChartDataSource::SwChartDataSource( 1961 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > &rLDS ) : 1962 aLDS( rLDS ) 1963 { 1964 } 1965 1966 1967 SwChartDataSource::~SwChartDataSource() 1968 { 1969 // delete pTblCrsr; 1970 } 1971 1972 1973 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL SwChartDataSource::getDataSequences( ) 1974 throw (uno::RuntimeException) 1975 { 1976 vos::OGuard aGuard( Application::GetSolarMutex() ); 1977 return aLDS; 1978 } 1979 1980 1981 OUString SAL_CALL SwChartDataSource::getImplementationName( ) 1982 throw (uno::RuntimeException) 1983 { 1984 vos::OGuard aGuard( Application::GetSolarMutex() ); 1985 return C2U("SwChartDataSource"); 1986 } 1987 1988 1989 sal_Bool SAL_CALL SwChartDataSource::supportsService( 1990 const OUString& rServiceName ) 1991 throw (uno::RuntimeException) 1992 { 1993 vos::OGuard aGuard( Application::GetSolarMutex() ); 1994 return rServiceName.equalsAscii( SN_DATA_SOURCE ); 1995 } 1996 1997 1998 uno::Sequence< OUString > SAL_CALL SwChartDataSource::getSupportedServiceNames( ) 1999 throw (uno::RuntimeException) 2000 { 2001 vos::OGuard aGuard( Application::GetSolarMutex() ); 2002 uno::Sequence< OUString > aRes(1); 2003 aRes.getArray()[0] = C2U( SN_DATA_SOURCE ); 2004 return aRes; 2005 } 2006 2007 ////////////////////////////////////////////////////////////////////// 2008 2009 SwChartDataSequence::SwChartDataSequence( 2010 SwChartDataProvider &rProvider, 2011 SwFrmFmt &rTblFmt, 2012 SwUnoCrsr *pTableCursor ) : 2013 SwClient( &rTblFmt ), 2014 aEvtListeners( GetChartMutex() ), 2015 aModifyListeners( GetChartMutex() ), 2016 aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT ) ), 2017 aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT ) ), 2018 xDataProvider( &rProvider ), 2019 pDataProvider( &rProvider ), 2020 pTblCrsr( pTableCursor ), 2021 aCursorDepend( this, pTableCursor ), 2022 _pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE ) ) 2023 { 2024 bDisposed = sal_False; 2025 2026 acquire(); 2027 try 2028 { 2029 const SwTable* pTable = SwTable::FindTable( &rTblFmt ); 2030 if (pTable) 2031 { 2032 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2033 pDataProvider->AddDataSequence( *pTable, xRef ); 2034 pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); 2035 } 2036 else { 2037 DBG_ERROR( "table missing" ); 2038 } 2039 } 2040 catch (uno::RuntimeException &) 2041 { 2042 throw; 2043 } 2044 catch (uno::Exception &) 2045 { 2046 } 2047 release(); 2048 2049 #if OSL_DEBUG_LEVEL > 1 2050 OUString aRangeStr( getSourceRangeRepresentation() ); 2051 2052 // check if it can properly convert into a SwUnoTableCrsr 2053 // which is required for some functions 2054 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2055 DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); 2056 (void) pUnoTblCrsr; 2057 #endif 2058 } 2059 2060 2061 SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence &rObj ) : 2062 SwChartDataSequenceBaseClass(), 2063 SwClient( rObj.GetFrmFmt() ), 2064 aEvtListeners( GetChartMutex() ), 2065 aModifyListeners( GetChartMutex() ), 2066 aRole( rObj.aRole ), 2067 aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT) ), 2068 aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT) ), 2069 xDataProvider( rObj.pDataProvider ), 2070 pDataProvider( rObj.pDataProvider ), 2071 pTblCrsr( rObj.pTblCrsr->Clone() ), 2072 aCursorDepend( this, pTblCrsr ), 2073 _pPropSet( rObj._pPropSet ) 2074 { 2075 bDisposed = sal_False; 2076 2077 acquire(); 2078 try 2079 { 2080 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2081 if (pTable) 2082 { 2083 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2084 pDataProvider->AddDataSequence( *pTable, xRef ); 2085 pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); 2086 } 2087 else { 2088 DBG_ERROR( "table missing" ); 2089 } 2090 } 2091 catch (uno::RuntimeException &) 2092 { 2093 throw; 2094 } 2095 catch (uno::Exception &) 2096 { 2097 } 2098 release(); 2099 2100 #if OSL_DEBUG_LEVEL > 1 2101 OUString aRangeStr( getSourceRangeRepresentation() ); 2102 2103 // check if it can properly convert into a SwUnoTableCrsr 2104 // which is required for some functions 2105 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2106 DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); 2107 (void) pUnoTblCrsr; 2108 #endif 2109 } 2110 2111 2112 SwChartDataSequence::~SwChartDataSequence() 2113 { 2114 // since the data-provider holds only weak references to the data-sequence 2115 // there should be no need here to release them explicitly... 2116 2117 delete pTblCrsr; 2118 } 2119 2120 2121 const uno::Sequence< sal_Int8 > & SwChartDataSequence::getUnoTunnelId() 2122 { 2123 static uno::Sequence< sal_Int8 > aSeq = ::CreateUnoTunnelId(); 2124 return aSeq; 2125 } 2126 2127 2128 sal_Int64 SAL_CALL SwChartDataSequence::getSomething( const uno::Sequence< sal_Int8 > &rId ) 2129 throw(uno::RuntimeException) 2130 { 2131 if( rId.getLength() == 16 2132 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), 2133 rId.getConstArray(), 16 ) ) 2134 { 2135 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); 2136 } 2137 return 0; 2138 } 2139 2140 2141 uno::Sequence< uno::Any > SAL_CALL SwChartDataSequence::getData( ) 2142 throw (uno::RuntimeException) 2143 { 2144 vos::OGuard aGuard( Application::GetSolarMutex() ); 2145 if (bDisposed) 2146 throw lang::DisposedException(); 2147 2148 uno::Sequence< uno::Any > aRes; 2149 SwFrmFmt* pTblFmt = GetFrmFmt(); 2150 if(pTblFmt) 2151 { 2152 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2153 if(!pTable->IsTblComplex()) 2154 { 2155 SwRangeDescriptor aDesc; 2156 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2157 { 2158 //!! make copy of pTblCrsr (SwUnoCrsr ) 2159 // keep original cursor and make copy of it that gets handed 2160 // over to the SwXCellRange object which takes ownership and 2161 // thus will destroy the copy later. 2162 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2163 aRange.GetDataSequence( &aRes, 0, 0 ); 2164 } 2165 } 2166 } 2167 return aRes; 2168 } 2169 2170 2171 OUString SAL_CALL SwChartDataSequence::getSourceRangeRepresentation( ) 2172 throw (uno::RuntimeException) 2173 { 2174 vos::OGuard aGuard( Application::GetSolarMutex() ); 2175 if (bDisposed) 2176 throw lang::DisposedException(); 2177 2178 String aRes; 2179 SwFrmFmt* pTblFmt = GetFrmFmt(); 2180 if (pTblFmt) 2181 { 2182 aRes = pTblFmt->GetName(); 2183 String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2184 DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); 2185 aRes += (sal_Unicode) '.'; 2186 aRes += aCellRange; 2187 } 2188 return aRes; 2189 } 2190 2191 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::generateLabel( 2192 chart2::data::LabelOrigin eLabelOrigin ) 2193 throw (uno::RuntimeException) 2194 { 2195 vos::OGuard aGuard( Application::GetSolarMutex() ); 2196 if (bDisposed) 2197 throw lang::DisposedException(); 2198 2199 uno::Sequence< OUString > aLabels; 2200 2201 { 2202 SwRangeDescriptor aDesc; 2203 sal_Bool bOk sal_False; 2204 SwFrmFmt* pTblFmt = GetFrmFmt(); 2205 SwTable* pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; 2206 if (!pTblFmt || !pTable || pTable->IsTblComplex()) 2207 throw uno::RuntimeException(); 2208 else 2209 { 2210 String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2211 DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); 2212 bOk = FillRangeDescriptor( aDesc, aCellRange ); 2213 DBG_ASSERT( bOk, "falied to get SwRangeDescriptor" ); 2214 } 2215 if (bOk) 2216 { 2217 aDesc.Normalize(); 2218 sal_Int32 nColSpan = aDesc.nRight - aDesc.nLeft + 1; 2219 sal_Int32 nRowSpan = aDesc.nBottom - aDesc.nTop + 1; 2220 DBG_ASSERT( nColSpan == 1 || nRowSpan == 1, 2221 "unexpected range of selected cells" ); 2222 2223 String aTxt; // label text to be returned 2224 sal_Bool bReturnEmptyTxt = sal_False; 2225 sal_Bool bUseCol = sal_True; 2226 if (eLabelOrigin == chart2::data::LabelOrigin_COLUMN) 2227 bUseCol = sal_True; 2228 else if (eLabelOrigin == chart2::data::LabelOrigin_ROW) 2229 bUseCol = sal_False; 2230 else if (eLabelOrigin == chart2::data::LabelOrigin_SHORT_SIDE) 2231 { 2232 bUseCol = nColSpan < nRowSpan; 2233 bReturnEmptyTxt = nColSpan == nRowSpan; 2234 } 2235 else if (eLabelOrigin == chart2::data::LabelOrigin_LONG_SIDE) 2236 { 2237 bUseCol = nColSpan > nRowSpan; 2238 bReturnEmptyTxt = nColSpan == nRowSpan; 2239 } 2240 else { 2241 DBG_ERROR( "unexpected case" ); 2242 } 2243 2244 // build label sequence 2245 // 2246 sal_Int32 nSeqLen = bUseCol ? nColSpan : nRowSpan; 2247 aLabels.realloc( nSeqLen ); 2248 OUString *pLabels = aLabels.getArray(); 2249 for (sal_Int32 i = 0; i < nSeqLen; ++i) 2250 { 2251 if (!bReturnEmptyTxt) 2252 { 2253 aTxt = bUseCol ? aColLabelText : aRowLabelText; 2254 sal_Int32 nCol = aDesc.nLeft; 2255 sal_Int32 nRow = aDesc.nTop; 2256 if (bUseCol) 2257 nCol = nCol + i; 2258 else 2259 nRow = nRow + i; 2260 String aCellName( lcl_GetCellName( nCol, nRow ) ); 2261 2262 xub_StrLen nLen = aCellName.Len(); 2263 if (nLen) 2264 { 2265 const sal_Unicode *pBuf = aCellName.GetBuffer(); 2266 const sal_Unicode *pEnd = pBuf + nLen; 2267 while (pBuf < pEnd && !('0' <= *pBuf && *pBuf <= '9')) 2268 ++pBuf; 2269 // start of number found? 2270 if (pBuf < pEnd && ('0' <= *pBuf && *pBuf <= '9')) 2271 { 2272 String aRplc; 2273 String aNew; 2274 if (bUseCol) 2275 { 2276 aRplc = String::CreateFromAscii( "%COLUMNLETTER" ); 2277 aNew = String( aCellName.GetBuffer(), static_cast<xub_StrLen>(pBuf - aCellName.GetBuffer()) ); 2278 } 2279 else 2280 { 2281 aRplc = String::CreateFromAscii( "%ROWNUMBER" ); 2282 aNew = String( pBuf, static_cast<xub_StrLen>((aCellName.GetBuffer() + nLen) - pBuf) ); 2283 } 2284 xub_StrLen nPos = aTxt.Search( aRplc ); 2285 if (nPos != STRING_NOTFOUND) 2286 aTxt = aTxt.Replace( nPos, aRplc.Len(), aNew ); 2287 } 2288 } 2289 } 2290 pLabels[i] = aTxt; 2291 } 2292 } 2293 } 2294 2295 return aLabels; 2296 } 2297 2298 ::sal_Int32 SAL_CALL SwChartDataSequence::getNumberFormatKeyByIndex( 2299 ::sal_Int32 /*nIndex*/ ) 2300 throw (lang::IndexOutOfBoundsException, 2301 uno::RuntimeException) 2302 { 2303 return 0; 2304 } 2305 2306 2307 2308 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getTextualData( ) 2309 throw (uno::RuntimeException) 2310 { 2311 vos::OGuard aGuard( Application::GetSolarMutex() ); 2312 if (bDisposed) 2313 throw lang::DisposedException(); 2314 2315 uno::Sequence< OUString > aRes; 2316 SwFrmFmt* pTblFmt = GetFrmFmt(); 2317 if(pTblFmt) 2318 { 2319 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2320 if(!pTable->IsTblComplex()) 2321 { 2322 SwRangeDescriptor aDesc; 2323 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2324 { 2325 //!! make copy of pTblCrsr (SwUnoCrsr ) 2326 // keep original cursor and make copy of it that gets handed 2327 // over to the SwXCellRange object which takes ownership and 2328 // thus will destroy the copy later. 2329 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2330 aRange.GetDataSequence( 0, &aRes, 0 ); 2331 } 2332 } 2333 } 2334 return aRes; 2335 } 2336 2337 2338 uno::Sequence< double > SAL_CALL SwChartDataSequence::getNumericalData( ) 2339 throw (uno::RuntimeException) 2340 { 2341 vos::OGuard aGuard( Application::GetSolarMutex() ); 2342 if (bDisposed) 2343 throw lang::DisposedException(); 2344 2345 uno::Sequence< double > aRes; 2346 SwFrmFmt* pTblFmt = GetFrmFmt(); 2347 if(pTblFmt) 2348 { 2349 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2350 if(!pTable->IsTblComplex()) 2351 { 2352 SwRangeDescriptor aDesc; 2353 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2354 { 2355 //!! make copy of pTblCrsr (SwUnoCrsr ) 2356 // keep original cursor and make copy of it that gets handed 2357 // over to the SwXCellRange object which takes ownership and 2358 // thus will destroy the copy later. 2359 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2360 2361 // get numerical values and make an effort to return the 2362 // numerical value for text formatted cells 2363 aRange.GetDataSequence( 0, 0, &aRes, sal_True ); 2364 } 2365 } 2366 } 2367 return aRes; 2368 } 2369 2370 2371 uno::Reference< util::XCloneable > SAL_CALL SwChartDataSequence::createClone( ) 2372 throw (uno::RuntimeException) 2373 { 2374 vos::OGuard aGuard( Application::GetSolarMutex() ); 2375 if (bDisposed) 2376 throw lang::DisposedException(); 2377 return new SwChartDataSequence( *this ); 2378 } 2379 2380 2381 uno::Reference< beans::XPropertySetInfo > SAL_CALL SwChartDataSequence::getPropertySetInfo( ) 2382 throw (uno::RuntimeException) 2383 { 2384 vos::OGuard aGuard( Application::GetSolarMutex() ); 2385 if (bDisposed) 2386 throw lang::DisposedException(); 2387 2388 static uno::Reference< beans::XPropertySetInfo > xRes = _pPropSet->getPropertySetInfo(); 2389 return xRes; 2390 } 2391 2392 2393 void SAL_CALL SwChartDataSequence::setPropertyValue( 2394 const OUString& rPropertyName, 2395 const uno::Any& rValue ) 2396 throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) 2397 { 2398 vos::OGuard aGuard( Application::GetSolarMutex() ); 2399 if (bDisposed) 2400 throw lang::DisposedException(); 2401 2402 if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) 2403 { 2404 if ( !(rValue >>= aRole) ) 2405 throw lang::IllegalArgumentException(); 2406 } 2407 else 2408 throw beans::UnknownPropertyException(); 2409 } 2410 2411 2412 uno::Any SAL_CALL SwChartDataSequence::getPropertyValue( 2413 const OUString& rPropertyName ) 2414 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2415 { 2416 vos::OGuard aGuard( Application::GetSolarMutex() ); 2417 if (bDisposed) 2418 throw lang::DisposedException(); 2419 2420 uno::Any aRes; 2421 if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) 2422 aRes <<= aRole; 2423 else 2424 throw beans::UnknownPropertyException(); 2425 2426 return aRes; 2427 } 2428 2429 2430 void SAL_CALL SwChartDataSequence::addPropertyChangeListener( 2431 const OUString& /*rPropertyName*/, 2432 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) 2433 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2434 { 2435 //vos::OGuard aGuard( Application::GetSolarMutex() ); 2436 DBG_ERROR( "not implemented" ); 2437 } 2438 2439 2440 void SAL_CALL SwChartDataSequence::removePropertyChangeListener( 2441 const OUString& /*rPropertyName*/, 2442 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) 2443 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2444 { 2445 //vos::OGuard aGuard( Application::GetSolarMutex() ); 2446 DBG_ERROR( "not implemented" ); 2447 } 2448 2449 2450 void SAL_CALL SwChartDataSequence::addVetoableChangeListener( 2451 const OUString& /*rPropertyName*/, 2452 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) 2453 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2454 { 2455 //vos::OGuard aGuard( Application::GetSolarMutex() ); 2456 DBG_ERROR( "not implemented" ); 2457 } 2458 2459 2460 void SAL_CALL SwChartDataSequence::removeVetoableChangeListener( 2461 const OUString& /*rPropertyName*/, 2462 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) 2463 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2464 { 2465 //vos::OGuard aGuard( Application::GetSolarMutex() ); 2466 DBG_ERROR( "not implemented" ); 2467 } 2468 2469 2470 OUString SAL_CALL SwChartDataSequence::getImplementationName( ) 2471 throw (uno::RuntimeException) 2472 { 2473 return C2U("SwChartDataSequence"); 2474 } 2475 2476 2477 sal_Bool SAL_CALL SwChartDataSequence::supportsService( 2478 const OUString& rServiceName ) 2479 throw (uno::RuntimeException) 2480 { 2481 return rServiceName.equalsAscii( SN_DATA_SEQUENCE ); 2482 } 2483 2484 2485 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getSupportedServiceNames( ) 2486 throw (uno::RuntimeException) 2487 { 2488 vos::OGuard aGuard( Application::GetSolarMutex() ); 2489 uno::Sequence< OUString > aRes(1); 2490 aRes.getArray()[0] = C2U( SN_DATA_SEQUENCE ); 2491 return aRes; 2492 } 2493 2494 2495 void SwChartDataSequence::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 2496 { 2497 ClientModify(this, pOld, pNew ); 2498 2499 // table was deleted or cursor was deleted 2500 if(!GetRegisteredIn() || !aCursorDepend.GetRegisteredIn()) 2501 { 2502 pTblCrsr = 0; 2503 dispose(); 2504 } 2505 else 2506 { 2507 setModified( sal_True ); 2508 } 2509 } 2510 2511 2512 sal_Bool SAL_CALL SwChartDataSequence::isModified( ) 2513 throw (uno::RuntimeException) 2514 { 2515 vos::OGuard aGuard( Application::GetSolarMutex() ); 2516 if (bDisposed) 2517 throw lang::DisposedException(); 2518 2519 return sal_True; 2520 } 2521 2522 2523 void SAL_CALL SwChartDataSequence::setModified( 2524 ::sal_Bool bModified ) 2525 throw (beans::PropertyVetoException, uno::RuntimeException) 2526 { 2527 vos::OGuard aGuard( Application::GetSolarMutex() ); 2528 if (bDisposed) 2529 throw lang::DisposedException(); 2530 2531 if (bModified) 2532 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2533 } 2534 2535 2536 void SAL_CALL SwChartDataSequence::addModifyListener( 2537 const uno::Reference< util::XModifyListener >& rxListener ) 2538 throw (uno::RuntimeException) 2539 { 2540 osl::MutexGuard aGuard( GetChartMutex() ); 2541 if (!bDisposed && rxListener.is()) 2542 aModifyListeners.addInterface( rxListener ); 2543 } 2544 2545 2546 void SAL_CALL SwChartDataSequence::removeModifyListener( 2547 const uno::Reference< util::XModifyListener >& rxListener ) 2548 throw (uno::RuntimeException) 2549 { 2550 osl::MutexGuard aGuard( GetChartMutex() ); 2551 if (!bDisposed && rxListener.is()) 2552 aModifyListeners.removeInterface( rxListener ); 2553 } 2554 2555 2556 void SAL_CALL SwChartDataSequence::disposing( const lang::EventObject& rSource ) 2557 throw (uno::RuntimeException) 2558 { 2559 if (bDisposed) 2560 throw lang::DisposedException(); 2561 if (rSource.Source == xDataProvider) 2562 { 2563 pDataProvider = 0; 2564 xDataProvider.clear(); 2565 } 2566 } 2567 2568 2569 void SAL_CALL SwChartDataSequence::dispose( ) 2570 throw (uno::RuntimeException) 2571 { 2572 sal_Bool bMustDispose( sal_False ); 2573 { 2574 osl::MutexGuard aGuard( GetChartMutex() ); 2575 bMustDispose = !bDisposed; 2576 if (!bDisposed) 2577 bDisposed = sal_True; 2578 } 2579 if (bMustDispose) 2580 { 2581 bDisposed = sal_True; 2582 if (pDataProvider) 2583 { 2584 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2585 if (pTable) 2586 { 2587 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2588 pDataProvider->RemoveDataSequence( *pTable, xRef ); 2589 } 2590 else { 2591 DBG_ERROR( "table missing" ); 2592 } 2593 } 2594 2595 // require listeners to release references to this object 2596 lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) ); 2597 aModifyListeners.disposeAndClear( aEvtObj ); 2598 aEvtListeners.disposeAndClear( aEvtObj ); 2599 } 2600 } 2601 2602 2603 void SAL_CALL SwChartDataSequence::addEventListener( 2604 const uno::Reference< lang::XEventListener >& rxListener ) 2605 throw (uno::RuntimeException) 2606 { 2607 osl::MutexGuard aGuard( GetChartMutex() ); 2608 if (!bDisposed && rxListener.is()) 2609 aEvtListeners.addInterface( rxListener ); 2610 } 2611 2612 2613 void SAL_CALL SwChartDataSequence::removeEventListener( 2614 const uno::Reference< lang::XEventListener >& rxListener ) 2615 throw (uno::RuntimeException) 2616 { 2617 osl::MutexGuard aGuard( GetChartMutex() ); 2618 if (!bDisposed && rxListener.is()) 2619 aEvtListeners.removeInterface( rxListener ); 2620 } 2621 2622 2623 sal_Bool SwChartDataSequence::DeleteBox( const SwTableBox &rBox ) 2624 { 2625 #if OSL_DEBUG_LEVEL > 1 2626 String aBoxName( rBox.GetName() ); 2627 #endif 2628 2629 // to be set if the last box of the data-sequence was removed here 2630 sal_Bool bNowEmpty = sal_False; 2631 2632 // if the implementation cursor gets affected (i.e. thew box where it is located 2633 // in gets removed) we need to move it before that... (otherwise it does not need to change) 2634 // 2635 const SwStartNode* pPointStartNode = pTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 2636 const SwStartNode* pMarkStartNode = pTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 2637 // 2638 if (!pTblCrsr->HasMark() || (pPointStartNode == rBox.GetSttNd() && pMarkStartNode == rBox.GetSttNd())) 2639 { 2640 bNowEmpty = sal_True; 2641 } 2642 else if (pPointStartNode == rBox.GetSttNd() || pMarkStartNode == rBox.GetSttNd()) 2643 { 2644 sal_Int32 nPointRow = -1, nPointCol = -1; 2645 sal_Int32 nMarkRow = -1, nMarkCol = -1; 2646 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2647 String aPointCellName( pTable->GetTblBox( pPointStartNode->GetIndex() )->GetName() ); 2648 String aMarkCellName( pTable->GetTblBox( pMarkStartNode->GetIndex() )->GetName() ); 2649 2650 lcl_GetCellPosition( aPointCellName, nPointCol, nPointRow ); 2651 lcl_GetCellPosition( aMarkCellName, nMarkCol, nMarkRow ); 2652 DBG_ASSERT( nPointRow >= 0 && nPointCol >= 0, "invalid row and col" ); 2653 DBG_ASSERT( nMarkRow >= 0 && nMarkCol >= 0, "invalid row and col" ); 2654 2655 // move vertical or horizontal? 2656 DBG_ASSERT( nPointRow == nMarkRow || nPointCol == nMarkCol, 2657 "row/col indices not matching" ); 2658 DBG_ASSERT( nPointRow != nMarkRow || nPointCol != nMarkCol, 2659 "point and mark are identical" ); 2660 sal_Bool bMoveVertical = (nPointCol == nMarkCol); 2661 sal_Bool bMoveHorizontal = (nPointRow == nMarkRow); 2662 2663 // get movement direction 2664 sal_Bool bMoveLeft = sal_False; // move left or right? 2665 sal_Bool bMoveUp = sal_False; // move up or down? 2666 if (bMoveVertical) 2667 { 2668 if (pPointStartNode == rBox.GetSttNd()) // move point? 2669 bMoveUp = nPointRow > nMarkRow; 2670 else // move mark 2671 bMoveUp = nMarkRow > nPointRow; 2672 } 2673 else if (bMoveHorizontal) 2674 { 2675 if (pPointStartNode == rBox.GetSttNd()) // move point? 2676 bMoveLeft = nPointCol > nMarkCol; 2677 else // move mark 2678 bMoveLeft = nMarkCol > nPointCol; 2679 } 2680 else { 2681 DBG_ERROR( "neither vertical nor horizontal movement" ); 2682 } 2683 2684 // get new box (position) to use... 2685 sal_Int32 nRow = (pPointStartNode == rBox.GetSttNd()) ? nPointRow : nMarkRow; 2686 sal_Int32 nCol = (pPointStartNode == rBox.GetSttNd()) ? nPointCol : nMarkCol; 2687 if (bMoveVertical) 2688 nRow += bMoveUp ? -1 : +1; 2689 if (bMoveHorizontal) 2690 nCol += bMoveLeft ? -1 : +1; 2691 String aNewCellName = lcl_GetCellName( nCol, nRow ); 2692 SwTableBox* pNewBox = (SwTableBox*) pTable->GetTblBox( aNewCellName ); 2693 2694 if (pNewBox) // set new position (cell range) to use 2695 { 2696 // So erh�lt man den ersten Inhaltsnode in einer gegebenen Zelle: 2697 // Zun�chst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box... 2698 SwNodeIndex aIdx( *pNewBox->GetSttNd(), +1 ); 2699 // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein, 2700 // deshalb das GoNext; 2701 SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); 2702 if (!pCNd) 2703 pCNd = GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx ); 2704 //und damit kann man z.B. eine SwPosition erzeugen: 2705 SwPosition aNewPos( *pCNd ); // new position to beused with cursor 2706 2707 // if the mark is to be changed make sure there is one... 2708 if (pMarkStartNode == rBox.GetSttNd() && !pTblCrsr->HasMark()) 2709 pTblCrsr->SetMark(); 2710 2711 // set cursor to new position... 2712 SwPosition *pPos = (pPointStartNode == rBox.GetSttNd()) ? 2713 pTblCrsr->GetPoint() : pTblCrsr->GetMark(); 2714 if (pPos) 2715 { 2716 pPos->nNode = aNewPos.nNode; 2717 pPos->nContent = aNewPos.nContent; 2718 } 2719 else { 2720 DBG_ERROR( "neither point nor mark available for change" ); 2721 } 2722 } 2723 else { 2724 DBG_ERROR( "failed to get position" ); 2725 } 2726 } 2727 2728 return bNowEmpty; 2729 } 2730 2731 2732 void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor &rRangeDesc ) const 2733 { 2734 SwFrmFmt* pTblFmt = GetFrmFmt(); 2735 if(pTblFmt) 2736 { 2737 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2738 if(!pTable->IsTblComplex()) 2739 { 2740 FillRangeDescriptor( rRangeDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2741 } 2742 } 2743 } 2744 2745 /** 2746 SwChartDataSequence::ExtendTo 2747 2748 extends the data-sequence by new cells added at the end of the direction 2749 the data-sequence points to. 2750 If the cells are already within the range of the sequence nothing needs 2751 to be done. 2752 If the cells are beyond the end of the sequence (are not adjacent to the 2753 current last cell) nothing can be done. Only if the cells are adjacent to 2754 the last cell they can be added. 2755 2756 @returns true if the data-sequence was changed. 2757 @param bExtendCols 2758 specifies if columns or rows are to be extended 2759 @param nFirstNew 2760 index of first new row/col to be included in data-sequence 2761 @param nLastNew 2762 index of last new row/col to be included in data-sequence 2763 */ 2764 bool SwChartDataSequence::ExtendTo( bool bExtendCol, 2765 sal_Int32 nFirstNew, sal_Int32 nCount ) 2766 { 2767 bool bChanged = false; 2768 2769 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2770 //pUnoTblCrsr->MakeBoxSels(); 2771 2772 const SwStartNode *pStartNd = 0; 2773 const SwTableBox *pStartBox = 0; 2774 const SwTableBox *pEndBox = 0; 2775 2776 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2777 DBG_ASSERT( !pTable->IsTblComplex(), "table too complex" ); 2778 if (nCount < 1 || nFirstNew < 0 || pTable->IsTblComplex()) 2779 return false; 2780 2781 // 2782 // get range descriptor (cell range) for current data-sequence 2783 // 2784 pStartNd = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 2785 pEndBox = pTable->GetTblBox( pStartNd->GetIndex() ); 2786 const String aEndBox( pEndBox->GetName() ); 2787 // 2788 pStartNd = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 2789 pStartBox = pTable->GetTblBox( pStartNd->GetIndex() ); 2790 const String aStartBox( pStartBox->GetName() ); 2791 // 2792 String aCellRange( aStartBox ); // note that cell range here takes the newly added rows/cols already into account 2793 aCellRange.AppendAscii( ":" ); 2794 aCellRange += aEndBox; 2795 SwRangeDescriptor aDesc; 2796 FillRangeDescriptor( aDesc, aCellRange ); 2797 2798 String aNewStartCell; 2799 String aNewEndCell; 2800 if (bExtendCol && aDesc.nBottom + 1 == nFirstNew) 2801 { 2802 // new column cells adjacent to the bottom of the 2803 // current data-sequence to be added... 2804 DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); 2805 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); 2806 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom + nCount); 2807 bChanged = true; 2808 } 2809 else if (bExtendCol && aDesc.nTop - nCount == nFirstNew) 2810 { 2811 // new column cells adjacent to the top of the 2812 // current data-sequence to be added... 2813 DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); 2814 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop - nCount); 2815 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); 2816 bChanged = true; 2817 } 2818 else if (!bExtendCol && aDesc.nRight + 1 == nFirstNew) 2819 { 2820 // new row cells adjacent to the right of the 2821 // current data-sequence to be added... 2822 DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); 2823 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); 2824 aNewEndCell = lcl_GetCellName(aDesc.nRight + nCount, aDesc.nBottom); 2825 bChanged = true; 2826 } 2827 else if (!bExtendCol && aDesc.nLeft - nCount == nFirstNew) 2828 { 2829 // new row cells adjacent to the left of the 2830 // current data-sequence to be added... 2831 DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); 2832 aNewStartCell = lcl_GetCellName(aDesc.nLeft - nCount, aDesc.nTop); 2833 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); 2834 bChanged = true; 2835 } 2836 2837 if (bChanged) 2838 { 2839 // move table cursor to new start and end of data-sequence 2840 const SwTableBox *pNewStartBox = pTable->GetTblBox( aNewStartCell ); 2841 const SwTableBox *pNewEndBox = pTable->GetTblBox( aNewEndCell ); 2842 pUnoTblCrsr->SetMark(); 2843 pUnoTblCrsr->GetPoint()->nNode = *pNewEndBox->GetSttNd(); 2844 pUnoTblCrsr->GetMark()->nNode = *pNewStartBox->GetSttNd(); 2845 pUnoTblCrsr->Move( fnMoveForward, fnGoNode ); 2846 pUnoTblCrsr->MakeBoxSels(); 2847 } 2848 2849 return bChanged; 2850 } 2851 2852 ////////////////////////////////////////////////////////////////////// 2853 2854 SwChartLabeledDataSequence::SwChartLabeledDataSequence() : 2855 aEvtListeners( GetChartMutex() ), 2856 aModifyListeners( GetChartMutex() ) 2857 { 2858 bDisposed = sal_False; 2859 } 2860 2861 2862 SwChartLabeledDataSequence::~SwChartLabeledDataSequence() 2863 { 2864 } 2865 2866 2867 uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getValues( ) 2868 throw (uno::RuntimeException) 2869 { 2870 vos::OGuard aGuard( Application::GetSolarMutex() ); 2871 if (bDisposed) 2872 throw lang::DisposedException(); 2873 return xData; 2874 } 2875 2876 2877 void SwChartLabeledDataSequence::SetDataSequence( 2878 uno::Reference< chart2::data::XDataSequence >& rxDest, 2879 const uno::Reference< chart2::data::XDataSequence >& rxSource) 2880 { 2881 uno::Reference< util::XModifyListener > xML( dynamic_cast< util::XModifyListener* >(this), uno::UNO_QUERY ); 2882 uno::Reference< lang::XEventListener > xEL( dynamic_cast< lang::XEventListener* >(this), uno::UNO_QUERY ); 2883 2884 // stop listening to old data-sequence 2885 uno::Reference< util::XModifyBroadcaster > xMB( rxDest, uno::UNO_QUERY ); 2886 if (xMB.is()) 2887 xMB->removeModifyListener( xML ); 2888 uno::Reference< lang::XComponent > xC( rxDest, uno::UNO_QUERY ); 2889 if (xC.is()) 2890 xC->removeEventListener( xEL ); 2891 2892 rxDest = rxSource; 2893 2894 // start listening to new data-sequence 2895 xC = uno::Reference< lang::XComponent >( rxDest, uno::UNO_QUERY ); 2896 if (xC.is()) 2897 xC->addEventListener( xEL ); 2898 xMB = uno::Reference< util::XModifyBroadcaster >( rxDest, uno::UNO_QUERY ); 2899 if (xMB.is()) 2900 xMB->addModifyListener( xML ); 2901 } 2902 2903 2904 void SAL_CALL SwChartLabeledDataSequence::setValues( 2905 const uno::Reference< chart2::data::XDataSequence >& rxSequence ) 2906 throw (uno::RuntimeException) 2907 { 2908 vos::OGuard aGuard( Application::GetSolarMutex() ); 2909 if (bDisposed) 2910 throw lang::DisposedException(); 2911 2912 if (xData != rxSequence) 2913 { 2914 SetDataSequence( xData, rxSequence ); 2915 // inform listeners of changes 2916 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2917 } 2918 } 2919 2920 2921 uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getLabel( ) 2922 throw (uno::RuntimeException) 2923 { 2924 vos::OGuard aGuard( Application::GetSolarMutex() ); 2925 if (bDisposed) 2926 throw lang::DisposedException(); 2927 return xLabels; 2928 } 2929 2930 2931 void SAL_CALL SwChartLabeledDataSequence::setLabel( 2932 const uno::Reference< chart2::data::XDataSequence >& rxSequence ) 2933 throw (uno::RuntimeException) 2934 { 2935 vos::OGuard aGuard( Application::GetSolarMutex() ); 2936 if (bDisposed) 2937 throw lang::DisposedException(); 2938 2939 if (xLabels != rxSequence) 2940 { 2941 SetDataSequence( xLabels, rxSequence ); 2942 // inform listeners of changes 2943 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2944 } 2945 } 2946 2947 2948 uno::Reference< util::XCloneable > SAL_CALL SwChartLabeledDataSequence::createClone( ) 2949 throw (uno::RuntimeException) 2950 { 2951 vos::OGuard aGuard( Application::GetSolarMutex() ); 2952 if (bDisposed) 2953 throw lang::DisposedException(); 2954 2955 uno::Reference< util::XCloneable > xRes; 2956 2957 uno::Reference< util::XCloneable > xDataCloneable( xData, uno::UNO_QUERY ); 2958 uno::Reference< util::XCloneable > xLabelsCloneable( xLabels, uno::UNO_QUERY ); 2959 SwChartLabeledDataSequence *pRes = new SwChartLabeledDataSequence(); 2960 if (xDataCloneable.is()) 2961 { 2962 uno::Reference< chart2::data::XDataSequence > xDataClone( xDataCloneable->createClone(), uno::UNO_QUERY ); 2963 pRes->setValues( xDataClone ); 2964 } 2965 2966 if (xLabelsCloneable.is()) 2967 { 2968 uno::Reference< chart2::data::XDataSequence > xLabelsClone( xLabelsCloneable->createClone(), uno::UNO_QUERY ); 2969 pRes->setLabel( xLabelsClone ); 2970 } 2971 xRes = pRes; 2972 return xRes; 2973 } 2974 2975 2976 OUString SAL_CALL SwChartLabeledDataSequence::getImplementationName( ) 2977 throw (uno::RuntimeException) 2978 { 2979 return C2U("SwChartLabeledDataSequence"); 2980 } 2981 2982 2983 sal_Bool SAL_CALL SwChartLabeledDataSequence::supportsService( 2984 const OUString& rServiceName ) 2985 throw (uno::RuntimeException) 2986 { 2987 return rServiceName.equalsAscii( SN_LABELED_DATA_SEQUENCE ); 2988 } 2989 2990 2991 uno::Sequence< OUString > SAL_CALL SwChartLabeledDataSequence::getSupportedServiceNames( ) 2992 throw (uno::RuntimeException) 2993 { 2994 vos::OGuard aGuard( Application::GetSolarMutex() ); 2995 uno::Sequence< OUString > aRes(1); 2996 aRes.getArray()[0] = C2U( SN_LABELED_DATA_SEQUENCE ); 2997 return aRes; 2998 } 2999 3000 3001 void SAL_CALL SwChartLabeledDataSequence::disposing( 3002 const lang::EventObject& rSource ) 3003 throw (uno::RuntimeException) 3004 { 3005 osl::MutexGuard aGuard( GetChartMutex() ); 3006 uno::Reference< uno::XInterface > xRef( rSource.Source ); 3007 if (xRef == xData) 3008 xData.clear(); 3009 if (xRef == xLabels) 3010 xLabels.clear(); 3011 if (!xData.is() && !xLabels.is()) 3012 dispose(); 3013 } 3014 3015 3016 void SAL_CALL SwChartLabeledDataSequence::modified( 3017 const lang::EventObject& rEvent ) 3018 throw (uno::RuntimeException) 3019 { 3020 if (rEvent.Source == xData || rEvent.Source == xLabels) 3021 { 3022 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 3023 } 3024 } 3025 3026 3027 void SAL_CALL SwChartLabeledDataSequence::addModifyListener( 3028 const uno::Reference< util::XModifyListener >& rxListener ) 3029 throw (uno::RuntimeException) 3030 { 3031 osl::MutexGuard aGuard( GetChartMutex() ); 3032 if (!bDisposed && rxListener.is()) 3033 aModifyListeners.addInterface( rxListener ); 3034 } 3035 3036 3037 void SAL_CALL SwChartLabeledDataSequence::removeModifyListener( 3038 const uno::Reference< util::XModifyListener >& rxListener ) 3039 throw (uno::RuntimeException) 3040 { 3041 osl::MutexGuard aGuard( GetChartMutex() ); 3042 if (!bDisposed && rxListener.is()) 3043 aModifyListeners.removeInterface( rxListener ); 3044 } 3045 3046 3047 void SAL_CALL SwChartLabeledDataSequence::dispose( ) 3048 throw (uno::RuntimeException) 3049 { 3050 sal_Bool bMustDispose( sal_False ); 3051 { 3052 osl::MutexGuard aGuard( GetChartMutex() ); 3053 bMustDispose = !bDisposed; 3054 if (!bDisposed) 3055 bDisposed = sal_True; 3056 } 3057 if (bMustDispose) 3058 { 3059 bDisposed = sal_True; 3060 3061 // require listeners to release references to this object 3062 lang::EventObject aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence * >(this) ); 3063 aModifyListeners.disposeAndClear( aEvtObj ); 3064 aEvtListeners.disposeAndClear( aEvtObj ); 3065 } 3066 } 3067 3068 3069 void SAL_CALL SwChartLabeledDataSequence::addEventListener( 3070 const uno::Reference< lang::XEventListener >& rxListener ) 3071 throw (uno::RuntimeException) 3072 { 3073 osl::MutexGuard aGuard( GetChartMutex() ); 3074 if (!bDisposed && rxListener.is()) 3075 aEvtListeners.addInterface( rxListener ); 3076 } 3077 3078 3079 void SAL_CALL SwChartLabeledDataSequence::removeEventListener( 3080 const uno::Reference< lang::XEventListener >& rxListener ) 3081 throw (uno::RuntimeException) 3082 { 3083 osl::MutexGuard aGuard( GetChartMutex() ); 3084 if (!bDisposed && rxListener.is()) 3085 aEvtListeners.removeInterface( rxListener ); 3086 } 3087 3088 ////////////////////////////////////////////////////////////////////// 3089