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 <svx/charthelper.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 ChartHelper::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 can't 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 can't 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 can't 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 separate 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::const_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 sal_Bool bSeqDisposed = sal_False; 1659 1660 // check if weak reference is still valid... 1661 // uno::Reference< chart2::data::XDataSequence > xRef( uno::Reference< chart2::data::XDataSequence>(*aIt), uno::UNO_QUERY ); 1662 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1663 uno::Reference< chart2::data::XDataSequence > xRef( xTemp, uno::UNO_QUERY ); 1664 if (xRef.is()) 1665 { 1666 // then delete that table box (check if implementation cursor needs to be adjusted) 1667 pDataSeq = static_cast< SwChartDataSequence * >( xRef.get() ); 1668 if (pDataSeq) 1669 { 1670 try 1671 { 1672 #if OSL_DEBUG_LEVEL > 1 1673 OUString aRangeStr( pDataSeq->getSourceRangeRepresentation() ); 1674 #endif 1675 bNowEmpty = pDataSeq->DeleteBox( rBox ); 1676 } 1677 catch (lang::DisposedException&) 1678 { 1679 bNowEmpty = sal_True; 1680 bSeqDisposed = sal_True; 1681 } 1682 1683 if (bNowEmpty) 1684 aDelIt = aIt; 1685 } 1686 } 1687 ++aIt; 1688 1689 if (bNowEmpty) 1690 { 1691 rSet.erase( aDelIt ); 1692 if (pDataSeq && !bSeqDisposed) 1693 pDataSeq->dispose(); // the current way to tell chart that sth. got removed 1694 } 1695 } 1696 } 1697 return bRes; 1698 } 1699 1700 1701 void SwChartDataProvider::DisposeAllDataSequences( const SwTable *pTable ) 1702 { 1703 DBG_ASSERT( pTable, "table pointer is NULL" ); 1704 if (pTable) 1705 { 1706 if (!bDisposed) 1707 pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); 1708 1709 //! make a copy of the STL container! 1710 //! This is necessary since calling 'dispose' will implicitly remove an element 1711 //! of the original container, and thus any iterator in the original container 1712 //! would become invalid. 1713 const Set_DataSequenceRef_t aSet( aDataSequences[ pTable ] ); 1714 1715 Set_DataSequenceRef_t::const_iterator aIt( aSet.begin() ); 1716 Set_DataSequenceRef_t::const_iterator aEndIt( aSet.end() ); 1717 while (aIt != aEndIt) 1718 { 1719 // uno::Reference< lang::XComponent > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); 1720 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1721 uno::Reference< lang::XComponent > xRef( xTemp, uno::UNO_QUERY ); 1722 if (xRef.is()) 1723 { 1724 xRef->dispose(); 1725 } 1726 ++aIt; 1727 } 1728 } 1729 } 1730 1731 1732 //////////////////////////////////////// 1733 // SwChartDataProvider::AddRowCols tries to notify charts of added columns 1734 // or rows and extends the value sequence respectively (if possible). 1735 // If those can be added to the end of existing value data-sequences those 1736 // sequences get mofdified accordingly and will send a modification 1737 // notification (calling 'setModified'). 1738 // 1739 // Since this function is a work-around for non existent Writer core functionality 1740 // (no arbitrary multi-selection in tables that can be used to define a 1741 // data-sequence) this function will be somewhat unreliable. 1742 // For example we will only try to adapt value sequences. For this we assume 1743 // that a sequence of length 1 is a label sequence and those with length >= 2 1744 // we presume to be value sequences. Also new cells can only be added in the 1745 // direction the value sequence is already pointing (rows / cols) and at the 1746 // start or end of the values data-sequence. 1747 // Nothing needs to be done if the new cells are in between the table cursors 1748 // point and mark since data-sequence are considered to consist of all cells 1749 // between those. 1750 // New rows/cols need to be added already to the table before calling 1751 // this function. 1752 // 1753 void SwChartDataProvider::AddRowCols( 1754 const SwTable &rTable, 1755 const SwSelBoxes& rBoxes, 1756 sal_uInt16 nLines, sal_Bool bBehind ) 1757 { 1758 if (rTable.IsTblComplex()) 1759 return; 1760 1761 const sal_uInt16 nBoxes = rBoxes.Count(); 1762 if (nBoxes < 1 || nLines < 1) 1763 return; 1764 1765 SwTableBox* pFirstBox = *( rBoxes.GetData() + 0 ); 1766 SwTableBox* pLastBox = *( rBoxes.GetData() + nBoxes - 1 ); 1767 1768 sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; 1769 if (pFirstBox && pLastBox) 1770 { 1771 lcl_GetCellPosition( pFirstBox->GetName(), nFirstCol, nFirstRow ); 1772 lcl_GetCellPosition( pLastBox->GetName(), nLastCol, nLastRow ); 1773 1774 bool bAddCols = false; // default; also to be used if nBoxes == 1 :-/ 1775 if (nFirstCol == nLastCol && nFirstRow != nLastRow) 1776 bAddCols = true; 1777 if (nFirstCol == nLastCol || nFirstRow == nLastRow) 1778 { 1779 //get range of indices in col/rows for new cells 1780 sal_Int32 nFirstNewCol = nFirstCol; 1781 sal_Int32 nLastNewCol = nLastCol; 1782 sal_Int32 nFirstNewRow = bBehind ? nFirstRow + 1 : nFirstRow - nLines; 1783 sal_Int32 nLastNewRow = nFirstNewRow - 1 + nLines; 1784 if (bAddCols) 1785 { 1786 DBG_ASSERT( nFirstCol == nLastCol, "column indices seem broken" ); 1787 nFirstNewCol = bBehind ? nFirstCol + 1 : nFirstCol - nLines; 1788 nLastNewCol = nFirstNewCol - 1 + nLines; 1789 nFirstNewRow = nFirstRow; 1790 nLastNewRow = nLastRow; 1791 } 1792 1793 // iterate over all data-sequences for the table 1794 const Set_DataSequenceRef_t &rSet = aDataSequences[ &rTable ]; 1795 Set_DataSequenceRef_t::const_iterator aIt( rSet.begin() ); 1796 while (aIt != rSet.end()) 1797 { 1798 // uno::Reference< chart2::data::XTextualDataSequence > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); 1799 uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 1800 uno::Reference< chart2::data::XTextualDataSequence > xRef( xTemp, uno::UNO_QUERY ); 1801 if (xRef.is()) 1802 { 1803 const sal_Int32 nLen = xRef->getTextualData().getLength(); 1804 if (nLen > 1) // value data-sequence ? 1805 { 1806 SwChartDataSequence *pDataSeq = 0; 1807 uno::Reference< lang::XUnoTunnel > xTunnel( xRef, uno::UNO_QUERY ); 1808 if(xTunnel.is()) 1809 { 1810 pDataSeq = reinterpret_cast< SwChartDataSequence * >( 1811 sal::static_int_cast< sal_IntPtr >( xTunnel->getSomething( SwChartDataSequence::getUnoTunnelId() ))); 1812 1813 if (pDataSeq) 1814 { 1815 SwRangeDescriptor aDesc; 1816 pDataSeq->FillRangeDesc( aDesc ); 1817 1818 chart::ChartDataRowSource eDRSource = chart::ChartDataRowSource_COLUMNS; 1819 if (aDesc.nTop == aDesc.nBottom && aDesc.nLeft != aDesc.nRight) 1820 eDRSource = chart::ChartDataRowSource_ROWS; 1821 1822 if (!bAddCols && eDRSource == chart::ChartDataRowSource_COLUMNS) 1823 { 1824 // add rows: extend affected columns by newly added row cells 1825 pDataSeq->ExtendTo( true, nFirstNewRow, nLines ); 1826 } 1827 else if (bAddCols && eDRSource == chart::ChartDataRowSource_ROWS) 1828 { 1829 // add cols: extend affected rows by newly added column cells 1830 pDataSeq->ExtendTo( false, nFirstNewCol, nLines ); 1831 } 1832 } 1833 } 1834 } 1835 } 1836 ++aIt; 1837 } 1838 1839 } 1840 } 1841 } 1842 1843 1844 // XRangeXMLConversion --------------------------------------------------- 1845 1846 rtl::OUString SAL_CALL SwChartDataProvider::convertRangeToXML( const rtl::OUString& rRangeRepresentation ) 1847 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 1848 { 1849 vos::OGuard aGuard( Application::GetSolarMutex() ); 1850 if (bDisposed) 1851 throw lang::DisposedException(); 1852 1853 String aRes; 1854 String aRangeRepresentation( rRangeRepresentation ); 1855 1856 // multiple ranges are delimeted by a ';' like in 1857 // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges! 1858 xub_StrLen nNumRanges = aRangeRepresentation.GetTokenCount( ';' ); 1859 SwTable* pFirstFoundTable = 0; // to check that only one table will be used 1860 for (sal_uInt16 i = 0; i < nNumRanges; ++i) 1861 { 1862 String aRange( aRangeRepresentation.GetToken(i, ';') ); 1863 SwFrmFmt *pTblFmt = 0; // pointer to table format 1864 // BM: For what should the check be necessary? for #i79009# it is required that NO check is done 1865 // SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist 1866 // std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr 1867 GetFormatAndCreateCursorFromRangeRep( pDoc, aRange, &pTblFmt, NULL ); 1868 if (!pTblFmt) 1869 throw lang::IllegalArgumentException(); 1870 // if (!pUnoCrsr) 1871 // throw uno::RuntimeException(); 1872 SwTable* pTable = SwTable::FindTable( pTblFmt ); 1873 if (pTable->IsTblComplex()) 1874 throw uno::RuntimeException(); 1875 1876 // check that there is only one table used in all ranges 1877 if (!pFirstFoundTable) 1878 pFirstFoundTable = pTable; 1879 if (pTable != pFirstFoundTable) 1880 throw lang::IllegalArgumentException(); 1881 1882 String aTblName; 1883 String aStartCell; 1884 String aEndCell; 1885 if (!GetTableAndCellsFromRangeRep( aRange, aTblName, aStartCell, aEndCell )) 1886 throw lang::IllegalArgumentException(); 1887 1888 sal_Int32 nCol, nRow; 1889 lcl_GetCellPosition( aStartCell, nCol, nRow ); 1890 if (nCol < 0 || nRow < 0) 1891 throw uno::RuntimeException(); 1892 1893 //!! following objects/functions are implemented in XMLRangeHelper.?xx 1894 //!! which is a copy of the respective file from chart2 !! 1895 XMLRangeHelper::CellRange aCellRange; 1896 aCellRange.aTableName = aTblName; 1897 aCellRange.aUpperLeft.nColumn = nCol; 1898 aCellRange.aUpperLeft.nRow = nRow; 1899 aCellRange.aUpperLeft.bIsEmpty = false; 1900 if (aStartCell != aEndCell && aEndCell.Len() != 0) 1901 { 1902 lcl_GetCellPosition( aEndCell, nCol, nRow ); 1903 if (nCol < 0 || nRow < 0) 1904 throw uno::RuntimeException(); 1905 1906 aCellRange.aLowerRight.nColumn = nCol; 1907 aCellRange.aLowerRight.nRow = nRow; 1908 aCellRange.aLowerRight.bIsEmpty = false; 1909 } 1910 String aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange ) ); 1911 if (aRes.Len()) // in case of multiple ranges add delimeter 1912 aRes.AppendAscii( " " ); 1913 aRes += aTmp; 1914 } 1915 1916 return aRes; 1917 } 1918 1919 rtl::OUString SAL_CALL SwChartDataProvider::convertRangeFromXML( const rtl::OUString& rXMLRange ) 1920 throw ( uno::RuntimeException, lang::IllegalArgumentException ) 1921 { 1922 vos::OGuard aGuard( Application::GetSolarMutex() ); 1923 if (bDisposed) 1924 throw lang::DisposedException(); 1925 1926 String aRes; 1927 String aXMLRange( rXMLRange ); 1928 1929 // multiple ranges are delimeted by a ' ' like in 1930 // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges! 1931 xub_StrLen nNumRanges = aXMLRange.GetTokenCount( ' ' ); 1932 rtl::OUString aFirstFoundTable; // to check that only one table will be used 1933 for (sal_uInt16 i = 0; i < nNumRanges; ++i) 1934 { 1935 String aRange( aXMLRange.GetToken(i, ' ') ); 1936 1937 //!! following objects and function are implemented in XMLRangeHelper.?xx 1938 //!! which is a copy of the respective file from chart2 !! 1939 XMLRangeHelper::CellRange aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange )); 1940 1941 // check that there is only one table used in all ranges 1942 if (aFirstFoundTable.getLength() == 0) 1943 aFirstFoundTable = aCellRange.aTableName; 1944 if (aCellRange.aTableName != aFirstFoundTable) 1945 throw lang::IllegalArgumentException(); 1946 1947 OUString aTmp( aCellRange.aTableName ); 1948 aTmp += OUString::valueOf((sal_Unicode) '.'); 1949 aTmp += lcl_GetCellName( aCellRange.aUpperLeft.nColumn, 1950 aCellRange.aUpperLeft.nRow ); 1951 // does cell range consist of more than a single cell? 1952 if (!aCellRange.aLowerRight.bIsEmpty) 1953 { 1954 aTmp += OUString::valueOf((sal_Unicode) ':'); 1955 aTmp += lcl_GetCellName( aCellRange.aLowerRight.nColumn, 1956 aCellRange.aLowerRight.nRow ); 1957 } 1958 1959 if (aRes.Len()) // in case of multiple ranges add delimeter 1960 aRes.AppendAscii( ";" ); 1961 aRes += String(aTmp); 1962 } 1963 1964 return aRes; 1965 } 1966 1967 1968 ////////////////////////////////////////////////////////////////////// 1969 1970 SwChartDataSource::SwChartDataSource( 1971 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > &rLDS ) : 1972 aLDS( rLDS ) 1973 { 1974 } 1975 1976 1977 SwChartDataSource::~SwChartDataSource() 1978 { 1979 // delete pTblCrsr; 1980 } 1981 1982 1983 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL SwChartDataSource::getDataSequences( ) 1984 throw (uno::RuntimeException) 1985 { 1986 vos::OGuard aGuard( Application::GetSolarMutex() ); 1987 return aLDS; 1988 } 1989 1990 1991 OUString SAL_CALL SwChartDataSource::getImplementationName( ) 1992 throw (uno::RuntimeException) 1993 { 1994 vos::OGuard aGuard( Application::GetSolarMutex() ); 1995 return C2U("SwChartDataSource"); 1996 } 1997 1998 1999 sal_Bool SAL_CALL SwChartDataSource::supportsService( 2000 const OUString& rServiceName ) 2001 throw (uno::RuntimeException) 2002 { 2003 vos::OGuard aGuard( Application::GetSolarMutex() ); 2004 return rServiceName.equalsAscii( SN_DATA_SOURCE ); 2005 } 2006 2007 2008 uno::Sequence< OUString > SAL_CALL SwChartDataSource::getSupportedServiceNames( ) 2009 throw (uno::RuntimeException) 2010 { 2011 vos::OGuard aGuard( Application::GetSolarMutex() ); 2012 uno::Sequence< OUString > aRes(1); 2013 aRes.getArray()[0] = C2U( SN_DATA_SOURCE ); 2014 return aRes; 2015 } 2016 2017 ////////////////////////////////////////////////////////////////////// 2018 2019 SwChartDataSequence::SwChartDataSequence( 2020 SwChartDataProvider &rProvider, 2021 SwFrmFmt &rTblFmt, 2022 SwUnoCrsr *pTableCursor ) : 2023 SwClient( &rTblFmt ), 2024 aEvtListeners( GetChartMutex() ), 2025 aModifyListeners( GetChartMutex() ), 2026 aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT ) ), 2027 aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT ) ), 2028 xDataProvider( &rProvider ), 2029 pDataProvider( &rProvider ), 2030 pTblCrsr( pTableCursor ), 2031 aCursorDepend( this, pTableCursor ), 2032 _pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE ) ) 2033 { 2034 bDisposed = sal_False; 2035 2036 acquire(); 2037 try 2038 { 2039 const SwTable* pTable = SwTable::FindTable( &rTblFmt ); 2040 if (pTable) 2041 { 2042 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2043 pDataProvider->AddDataSequence( *pTable, xRef ); 2044 pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); 2045 } 2046 else { 2047 DBG_ERROR( "table missing" ); 2048 } 2049 } 2050 catch (uno::RuntimeException &) 2051 { 2052 throw; 2053 } 2054 catch (uno::Exception &) 2055 { 2056 } 2057 release(); 2058 2059 #if OSL_DEBUG_LEVEL > 1 2060 OUString aRangeStr( getSourceRangeRepresentation() ); 2061 2062 // check if it can properly convert into a SwUnoTableCrsr 2063 // which is required for some functions 2064 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2065 DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); 2066 (void) pUnoTblCrsr; 2067 #endif 2068 } 2069 2070 2071 SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence &rObj ) : 2072 SwChartDataSequenceBaseClass(), 2073 SwClient( rObj.GetFrmFmt() ), 2074 aEvtListeners( GetChartMutex() ), 2075 aModifyListeners( GetChartMutex() ), 2076 aRole( rObj.aRole ), 2077 aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT) ), 2078 aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT) ), 2079 xDataProvider( rObj.pDataProvider ), 2080 pDataProvider( rObj.pDataProvider ), 2081 pTblCrsr( rObj.pTblCrsr->Clone() ), 2082 aCursorDepend( this, pTblCrsr ), 2083 _pPropSet( rObj._pPropSet ) 2084 { 2085 bDisposed = sal_False; 2086 2087 acquire(); 2088 try 2089 { 2090 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2091 if (pTable) 2092 { 2093 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2094 pDataProvider->AddDataSequence( *pTable, xRef ); 2095 pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); 2096 } 2097 else { 2098 DBG_ERROR( "table missing" ); 2099 } 2100 } 2101 catch (uno::RuntimeException &) 2102 { 2103 throw; 2104 } 2105 catch (uno::Exception &) 2106 { 2107 } 2108 release(); 2109 2110 #if OSL_DEBUG_LEVEL > 1 2111 OUString aRangeStr( getSourceRangeRepresentation() ); 2112 2113 // check if it can properly convert into a SwUnoTableCrsr 2114 // which is required for some functions 2115 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2116 DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); 2117 (void) pUnoTblCrsr; 2118 #endif 2119 } 2120 2121 2122 SwChartDataSequence::~SwChartDataSequence() 2123 { 2124 // since the data-provider holds only weak references to the data-sequence 2125 // there should be no need here to release them explicitly... 2126 2127 delete pTblCrsr; 2128 } 2129 2130 2131 const uno::Sequence< sal_Int8 > & SwChartDataSequence::getUnoTunnelId() 2132 { 2133 static uno::Sequence< sal_Int8 > aSeq = ::CreateUnoTunnelId(); 2134 return aSeq; 2135 } 2136 2137 2138 sal_Int64 SAL_CALL SwChartDataSequence::getSomething( const uno::Sequence< sal_Int8 > &rId ) 2139 throw(uno::RuntimeException) 2140 { 2141 if( rId.getLength() == 16 2142 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), 2143 rId.getConstArray(), 16 ) ) 2144 { 2145 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); 2146 } 2147 return 0; 2148 } 2149 2150 2151 uno::Sequence< uno::Any > SAL_CALL SwChartDataSequence::getData( ) 2152 throw (uno::RuntimeException) 2153 { 2154 vos::OGuard aGuard( Application::GetSolarMutex() ); 2155 if (bDisposed) 2156 throw lang::DisposedException(); 2157 2158 uno::Sequence< uno::Any > aRes; 2159 SwFrmFmt* pTblFmt = GetFrmFmt(); 2160 if(pTblFmt) 2161 { 2162 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2163 if(!pTable->IsTblComplex()) 2164 { 2165 SwRangeDescriptor aDesc; 2166 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2167 { 2168 //!! make copy of pTblCrsr (SwUnoCrsr ) 2169 // keep original cursor and make copy of it that gets handed 2170 // over to the SwXCellRange object which takes ownership and 2171 // thus will destroy the copy later. 2172 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2173 aRange.GetDataSequence( &aRes, 0, 0 ); 2174 } 2175 } 2176 } 2177 return aRes; 2178 } 2179 2180 2181 OUString SAL_CALL SwChartDataSequence::getSourceRangeRepresentation( ) 2182 throw (uno::RuntimeException) 2183 { 2184 vos::OGuard aGuard( Application::GetSolarMutex() ); 2185 if (bDisposed) 2186 throw lang::DisposedException(); 2187 2188 String aRes; 2189 SwFrmFmt* pTblFmt = GetFrmFmt(); 2190 if (pTblFmt) 2191 { 2192 aRes = pTblFmt->GetName(); 2193 String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2194 DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); 2195 aRes += (sal_Unicode) '.'; 2196 aRes += aCellRange; 2197 } 2198 return aRes; 2199 } 2200 2201 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::generateLabel( 2202 chart2::data::LabelOrigin eLabelOrigin ) 2203 throw (uno::RuntimeException) 2204 { 2205 vos::OGuard aGuard( Application::GetSolarMutex() ); 2206 if (bDisposed) 2207 throw lang::DisposedException(); 2208 2209 uno::Sequence< OUString > aLabels; 2210 2211 { 2212 SwRangeDescriptor aDesc; 2213 sal_Bool bOk sal_False; 2214 SwFrmFmt* pTblFmt = GetFrmFmt(); 2215 SwTable* pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; 2216 if (!pTblFmt || !pTable || pTable->IsTblComplex()) 2217 throw uno::RuntimeException(); 2218 else 2219 { 2220 String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2221 DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); 2222 bOk = FillRangeDescriptor( aDesc, aCellRange ); 2223 DBG_ASSERT( bOk, "falied to get SwRangeDescriptor" ); 2224 } 2225 if (bOk) 2226 { 2227 aDesc.Normalize(); 2228 sal_Int32 nColSpan = aDesc.nRight - aDesc.nLeft + 1; 2229 sal_Int32 nRowSpan = aDesc.nBottom - aDesc.nTop + 1; 2230 DBG_ASSERT( nColSpan == 1 || nRowSpan == 1, 2231 "unexpected range of selected cells" ); 2232 2233 String aTxt; // label text to be returned 2234 sal_Bool bReturnEmptyTxt = sal_False; 2235 sal_Bool bUseCol = sal_True; 2236 if (eLabelOrigin == chart2::data::LabelOrigin_COLUMN) 2237 bUseCol = sal_True; 2238 else if (eLabelOrigin == chart2::data::LabelOrigin_ROW) 2239 bUseCol = sal_False; 2240 else if (eLabelOrigin == chart2::data::LabelOrigin_SHORT_SIDE) 2241 { 2242 bUseCol = nColSpan < nRowSpan; 2243 bReturnEmptyTxt = nColSpan == nRowSpan; 2244 } 2245 else if (eLabelOrigin == chart2::data::LabelOrigin_LONG_SIDE) 2246 { 2247 bUseCol = nColSpan > nRowSpan; 2248 bReturnEmptyTxt = nColSpan == nRowSpan; 2249 } 2250 else { 2251 DBG_ERROR( "unexpected case" ); 2252 } 2253 2254 // build label sequence 2255 // 2256 sal_Int32 nSeqLen = bUseCol ? nColSpan : nRowSpan; 2257 aLabels.realloc( nSeqLen ); 2258 OUString *pLabels = aLabels.getArray(); 2259 for (sal_Int32 i = 0; i < nSeqLen; ++i) 2260 { 2261 if (!bReturnEmptyTxt) 2262 { 2263 aTxt = bUseCol ? aColLabelText : aRowLabelText; 2264 sal_Int32 nCol = aDesc.nLeft; 2265 sal_Int32 nRow = aDesc.nTop; 2266 if (bUseCol) 2267 nCol = nCol + i; 2268 else 2269 nRow = nRow + i; 2270 String aCellName( lcl_GetCellName( nCol, nRow ) ); 2271 2272 xub_StrLen nLen = aCellName.Len(); 2273 if (nLen) 2274 { 2275 const sal_Unicode *pBuf = aCellName.GetBuffer(); 2276 const sal_Unicode *pEnd = pBuf + nLen; 2277 while (pBuf < pEnd && !('0' <= *pBuf && *pBuf <= '9')) 2278 ++pBuf; 2279 // start of number found? 2280 if (pBuf < pEnd && ('0' <= *pBuf && *pBuf <= '9')) 2281 { 2282 String aRplc; 2283 String aNew; 2284 if (bUseCol) 2285 { 2286 aRplc = String::CreateFromAscii( "%COLUMNLETTER" ); 2287 aNew = String( aCellName.GetBuffer(), static_cast<xub_StrLen>(pBuf - aCellName.GetBuffer()) ); 2288 } 2289 else 2290 { 2291 aRplc = String::CreateFromAscii( "%ROWNUMBER" ); 2292 aNew = String( pBuf, static_cast<xub_StrLen>((aCellName.GetBuffer() + nLen) - pBuf) ); 2293 } 2294 xub_StrLen nPos = aTxt.Search( aRplc ); 2295 if (nPos != STRING_NOTFOUND) 2296 aTxt = aTxt.Replace( nPos, aRplc.Len(), aNew ); 2297 } 2298 } 2299 } 2300 pLabels[i] = aTxt; 2301 } 2302 } 2303 } 2304 2305 return aLabels; 2306 } 2307 2308 ::sal_Int32 SAL_CALL SwChartDataSequence::getNumberFormatKeyByIndex( 2309 ::sal_Int32 /*nIndex*/ ) 2310 throw (lang::IndexOutOfBoundsException, 2311 uno::RuntimeException) 2312 { 2313 return 0; 2314 } 2315 2316 2317 2318 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getTextualData( ) 2319 throw (uno::RuntimeException) 2320 { 2321 vos::OGuard aGuard( Application::GetSolarMutex() ); 2322 if (bDisposed) 2323 throw lang::DisposedException(); 2324 2325 uno::Sequence< OUString > aRes; 2326 SwFrmFmt* pTblFmt = GetFrmFmt(); 2327 if(pTblFmt) 2328 { 2329 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2330 if(!pTable->IsTblComplex()) 2331 { 2332 SwRangeDescriptor aDesc; 2333 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2334 { 2335 //!! make copy of pTblCrsr (SwUnoCrsr ) 2336 // keep original cursor and make copy of it that gets handed 2337 // over to the SwXCellRange object which takes ownership and 2338 // thus will destroy the copy later. 2339 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2340 aRange.GetDataSequence( 0, &aRes, 0 ); 2341 } 2342 } 2343 } 2344 return aRes; 2345 } 2346 2347 2348 uno::Sequence< double > SAL_CALL SwChartDataSequence::getNumericalData( ) 2349 throw (uno::RuntimeException) 2350 { 2351 vos::OGuard aGuard( Application::GetSolarMutex() ); 2352 if (bDisposed) 2353 throw lang::DisposedException(); 2354 2355 uno::Sequence< double > aRes; 2356 SwFrmFmt* pTblFmt = GetFrmFmt(); 2357 if(pTblFmt) 2358 { 2359 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2360 if(!pTable->IsTblComplex()) 2361 { 2362 SwRangeDescriptor aDesc; 2363 if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) 2364 { 2365 //!! make copy of pTblCrsr (SwUnoCrsr ) 2366 // keep original cursor and make copy of it that gets handed 2367 // over to the SwXCellRange object which takes ownership and 2368 // thus will destroy the copy later. 2369 SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); 2370 2371 // get numerical values and make an effort to return the 2372 // numerical value for text formatted cells 2373 aRange.GetDataSequence( 0, 0, &aRes, sal_True ); 2374 } 2375 } 2376 } 2377 return aRes; 2378 } 2379 2380 2381 uno::Reference< util::XCloneable > SAL_CALL SwChartDataSequence::createClone( ) 2382 throw (uno::RuntimeException) 2383 { 2384 vos::OGuard aGuard( Application::GetSolarMutex() ); 2385 if (bDisposed) 2386 throw lang::DisposedException(); 2387 return new SwChartDataSequence( *this ); 2388 } 2389 2390 2391 uno::Reference< beans::XPropertySetInfo > SAL_CALL SwChartDataSequence::getPropertySetInfo( ) 2392 throw (uno::RuntimeException) 2393 { 2394 vos::OGuard aGuard( Application::GetSolarMutex() ); 2395 if (bDisposed) 2396 throw lang::DisposedException(); 2397 2398 static uno::Reference< beans::XPropertySetInfo > xRes = _pPropSet->getPropertySetInfo(); 2399 return xRes; 2400 } 2401 2402 2403 void SAL_CALL SwChartDataSequence::setPropertyValue( 2404 const OUString& rPropertyName, 2405 const uno::Any& rValue ) 2406 throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) 2407 { 2408 vos::OGuard aGuard( Application::GetSolarMutex() ); 2409 if (bDisposed) 2410 throw lang::DisposedException(); 2411 2412 if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) 2413 { 2414 if ( !(rValue >>= aRole) ) 2415 throw lang::IllegalArgumentException(); 2416 } 2417 else 2418 throw beans::UnknownPropertyException(); 2419 } 2420 2421 2422 uno::Any SAL_CALL SwChartDataSequence::getPropertyValue( 2423 const OUString& rPropertyName ) 2424 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2425 { 2426 vos::OGuard aGuard( Application::GetSolarMutex() ); 2427 if (bDisposed) 2428 throw lang::DisposedException(); 2429 2430 uno::Any aRes; 2431 if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) 2432 aRes <<= aRole; 2433 else 2434 throw beans::UnknownPropertyException(); 2435 2436 return aRes; 2437 } 2438 2439 2440 void SAL_CALL SwChartDataSequence::addPropertyChangeListener( 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::removePropertyChangeListener( 2451 const OUString& /*rPropertyName*/, 2452 const uno::Reference< beans::XPropertyChangeListener >& /*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::addVetoableChangeListener( 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 void SAL_CALL SwChartDataSequence::removeVetoableChangeListener( 2471 const OUString& /*rPropertyName*/, 2472 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) 2473 throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) 2474 { 2475 //vos::OGuard aGuard( Application::GetSolarMutex() ); 2476 DBG_ERROR( "not implemented" ); 2477 } 2478 2479 2480 OUString SAL_CALL SwChartDataSequence::getImplementationName( ) 2481 throw (uno::RuntimeException) 2482 { 2483 return C2U("SwChartDataSequence"); 2484 } 2485 2486 2487 sal_Bool SAL_CALL SwChartDataSequence::supportsService( 2488 const OUString& rServiceName ) 2489 throw (uno::RuntimeException) 2490 { 2491 return rServiceName.equalsAscii( SN_DATA_SEQUENCE ); 2492 } 2493 2494 2495 uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getSupportedServiceNames( ) 2496 throw (uno::RuntimeException) 2497 { 2498 vos::OGuard aGuard( Application::GetSolarMutex() ); 2499 uno::Sequence< OUString > aRes(1); 2500 aRes.getArray()[0] = C2U( SN_DATA_SEQUENCE ); 2501 return aRes; 2502 } 2503 2504 2505 void SwChartDataSequence::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 2506 { 2507 ClientModify(this, pOld, pNew ); 2508 2509 // table was deleted or cursor was deleted 2510 if(!GetRegisteredIn() || !aCursorDepend.GetRegisteredIn()) 2511 { 2512 pTblCrsr = 0; 2513 dispose(); 2514 } 2515 else 2516 { 2517 setModified( sal_True ); 2518 } 2519 } 2520 2521 2522 sal_Bool SAL_CALL SwChartDataSequence::isModified( ) 2523 throw (uno::RuntimeException) 2524 { 2525 vos::OGuard aGuard( Application::GetSolarMutex() ); 2526 if (bDisposed) 2527 throw lang::DisposedException(); 2528 2529 return sal_True; 2530 } 2531 2532 2533 void SAL_CALL SwChartDataSequence::setModified( 2534 ::sal_Bool bModified ) 2535 throw (beans::PropertyVetoException, uno::RuntimeException) 2536 { 2537 vos::OGuard aGuard( Application::GetSolarMutex() ); 2538 if (bDisposed) 2539 throw lang::DisposedException(); 2540 2541 if (bModified) 2542 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2543 } 2544 2545 2546 void SAL_CALL SwChartDataSequence::addModifyListener( 2547 const uno::Reference< util::XModifyListener >& rxListener ) 2548 throw (uno::RuntimeException) 2549 { 2550 osl::MutexGuard aGuard( GetChartMutex() ); 2551 if (!bDisposed && rxListener.is()) 2552 aModifyListeners.addInterface( rxListener ); 2553 } 2554 2555 2556 void SAL_CALL SwChartDataSequence::removeModifyListener( 2557 const uno::Reference< util::XModifyListener >& rxListener ) 2558 throw (uno::RuntimeException) 2559 { 2560 osl::MutexGuard aGuard( GetChartMutex() ); 2561 if (!bDisposed && rxListener.is()) 2562 aModifyListeners.removeInterface( rxListener ); 2563 } 2564 2565 2566 void SAL_CALL SwChartDataSequence::disposing( const lang::EventObject& rSource ) 2567 throw (uno::RuntimeException) 2568 { 2569 if (bDisposed) 2570 throw lang::DisposedException(); 2571 if (rSource.Source == xDataProvider) 2572 { 2573 pDataProvider = 0; 2574 xDataProvider.clear(); 2575 } 2576 } 2577 2578 2579 void SAL_CALL SwChartDataSequence::dispose( ) 2580 throw (uno::RuntimeException) 2581 { 2582 sal_Bool bMustDispose( sal_False ); 2583 { 2584 osl::MutexGuard aGuard( GetChartMutex() ); 2585 bMustDispose = !bDisposed; 2586 if (!bDisposed) 2587 bDisposed = sal_True; 2588 } 2589 if (bMustDispose) 2590 { 2591 bDisposed = sal_True; 2592 if (pDataProvider) 2593 { 2594 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2595 if (pTable) 2596 { 2597 uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); 2598 pDataProvider->RemoveDataSequence( *pTable, xRef ); 2599 } 2600 else { 2601 DBG_ERROR( "table missing" ); 2602 } 2603 2604 //Comment: The bug is crashed for an exception threw out in SwCharDataSequence::setModified(), just because 2605 //the SwCharDataSequence object has been disposed. Actually, the former design of SwClient will disband 2606 //itself from the notification list in its destruction. But the SwCharDataSeqence won't be destructed but disposed 2607 //in code (the data member SwChartDataSequence::bDisposed will be set to TRUE), the relationship between client 2608 //and modification are not released. So any notification from modify object will lead said exception threw out. 2609 //Recorrect the logic of code in SwChartDataSequence::Dispose(), release the relationship inside... 2610 SwModify* pRegisteredIn = GetRegisteredInNonConst(); 2611 if (pRegisteredIn && pRegisteredIn->GetDepends()) 2612 { 2613 pRegisteredIn->Remove(this); 2614 pTblCrsr = NULL; 2615 } 2616 2617 } 2618 2619 // require listeners to release references to this object 2620 lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) ); 2621 aModifyListeners.disposeAndClear( aEvtObj ); 2622 aEvtListeners.disposeAndClear( aEvtObj ); 2623 } 2624 } 2625 2626 2627 void SAL_CALL SwChartDataSequence::addEventListener( 2628 const uno::Reference< lang::XEventListener >& rxListener ) 2629 throw (uno::RuntimeException) 2630 { 2631 osl::MutexGuard aGuard( GetChartMutex() ); 2632 if (!bDisposed && rxListener.is()) 2633 aEvtListeners.addInterface( rxListener ); 2634 } 2635 2636 2637 void SAL_CALL SwChartDataSequence::removeEventListener( 2638 const uno::Reference< lang::XEventListener >& rxListener ) 2639 throw (uno::RuntimeException) 2640 { 2641 osl::MutexGuard aGuard( GetChartMutex() ); 2642 if (!bDisposed && rxListener.is()) 2643 aEvtListeners.removeInterface( rxListener ); 2644 } 2645 2646 2647 sal_Bool SwChartDataSequence::DeleteBox( const SwTableBox &rBox ) 2648 { 2649 if (bDisposed) 2650 throw lang::DisposedException(); 2651 2652 #if OSL_DEBUG_LEVEL > 1 2653 String aBoxName( rBox.GetName() ); 2654 #endif 2655 2656 // to be set if the last box of the data-sequence was removed here 2657 sal_Bool bNowEmpty = sal_False; 2658 2659 // if the implementation cursor gets affected (i.e. thew box where it is located 2660 // in gets removed) we need to move it before that... (otherwise it does not need to change) 2661 // 2662 const SwStartNode* pPointStartNode = pTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 2663 const SwStartNode* pMarkStartNode = pTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 2664 // 2665 if (!pTblCrsr->HasMark() || (pPointStartNode == rBox.GetSttNd() && pMarkStartNode == rBox.GetSttNd())) 2666 { 2667 bNowEmpty = sal_True; 2668 } 2669 else if (pPointStartNode == rBox.GetSttNd() || pMarkStartNode == rBox.GetSttNd()) 2670 { 2671 sal_Int32 nPointRow = -1, nPointCol = -1; 2672 sal_Int32 nMarkRow = -1, nMarkCol = -1; 2673 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2674 String aPointCellName( pTable->GetTblBox( pPointStartNode->GetIndex() )->GetName() ); 2675 String aMarkCellName( pTable->GetTblBox( pMarkStartNode->GetIndex() )->GetName() ); 2676 2677 lcl_GetCellPosition( aPointCellName, nPointCol, nPointRow ); 2678 lcl_GetCellPosition( aMarkCellName, nMarkCol, nMarkRow ); 2679 DBG_ASSERT( nPointRow >= 0 && nPointCol >= 0, "invalid row and col" ); 2680 DBG_ASSERT( nMarkRow >= 0 && nMarkCol >= 0, "invalid row and col" ); 2681 2682 // move vertical or horizontal? 2683 DBG_ASSERT( nPointRow == nMarkRow || nPointCol == nMarkCol, 2684 "row/col indices not matching" ); 2685 DBG_ASSERT( nPointRow != nMarkRow || nPointCol != nMarkCol, 2686 "point and mark are identical" ); 2687 sal_Bool bMoveVertical = (nPointCol == nMarkCol); 2688 sal_Bool bMoveHorizontal = (nPointRow == nMarkRow); 2689 2690 // get movement direction 2691 sal_Bool bMoveLeft = sal_False; // move left or right? 2692 sal_Bool bMoveUp = sal_False; // move up or down? 2693 if (bMoveVertical) 2694 { 2695 if (pPointStartNode == rBox.GetSttNd()) // move point? 2696 bMoveUp = nPointRow > nMarkRow; 2697 else // move mark 2698 bMoveUp = nMarkRow > nPointRow; 2699 } 2700 else if (bMoveHorizontal) 2701 { 2702 if (pPointStartNode == rBox.GetSttNd()) // move point? 2703 bMoveLeft = nPointCol > nMarkCol; 2704 else // move mark 2705 bMoveLeft = nMarkCol > nPointCol; 2706 } 2707 else { 2708 DBG_ERROR( "neither vertical nor horizontal movement" ); 2709 } 2710 2711 // get new box (position) to use... 2712 sal_Int32 nRow = (pPointStartNode == rBox.GetSttNd()) ? nPointRow : nMarkRow; 2713 sal_Int32 nCol = (pPointStartNode == rBox.GetSttNd()) ? nPointCol : nMarkCol; 2714 if (bMoveVertical) 2715 nRow += bMoveUp ? -1 : +1; 2716 if (bMoveHorizontal) 2717 nCol += bMoveLeft ? -1 : +1; 2718 String aNewCellName = lcl_GetCellName( nCol, nRow ); 2719 SwTableBox* pNewBox = (SwTableBox*) pTable->GetTblBox( aNewCellName ); 2720 2721 if (pNewBox) // set new position (cell range) to use 2722 { 2723 // So erh�lt man den ersten Inhaltsnode in einer gegebenen Zelle: 2724 // Zun�chst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box... 2725 SwNodeIndex aIdx( *pNewBox->GetSttNd(), +1 ); 2726 // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein, 2727 // deshalb das GoNext; 2728 SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); 2729 if (!pCNd) 2730 pCNd = GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx ); 2731 //und damit kann man z.B. eine SwPosition erzeugen: 2732 SwPosition aNewPos( *pCNd ); // new position to beused with cursor 2733 2734 // if the mark is to be changed make sure there is one... 2735 if (pMarkStartNode == rBox.GetSttNd() && !pTblCrsr->HasMark()) 2736 pTblCrsr->SetMark(); 2737 2738 // set cursor to new position... 2739 SwPosition *pPos = (pPointStartNode == rBox.GetSttNd()) ? 2740 pTblCrsr->GetPoint() : pTblCrsr->GetMark(); 2741 if (pPos) 2742 { 2743 pPos->nNode = aNewPos.nNode; 2744 pPos->nContent = aNewPos.nContent; 2745 } 2746 else { 2747 DBG_ERROR( "neither point nor mark available for change" ); 2748 } 2749 } 2750 else { 2751 DBG_ERROR( "failed to get position" ); 2752 } 2753 } 2754 2755 return bNowEmpty; 2756 } 2757 2758 2759 void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor &rRangeDesc ) const 2760 { 2761 SwFrmFmt* pTblFmt = GetFrmFmt(); 2762 if(pTblFmt) 2763 { 2764 SwTable* pTable = SwTable::FindTable( pTblFmt ); 2765 if(!pTable->IsTblComplex()) 2766 { 2767 FillRangeDescriptor( rRangeDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ); 2768 } 2769 } 2770 } 2771 2772 /** 2773 SwChartDataSequence::ExtendTo 2774 2775 extends the data-sequence by new cells added at the end of the direction 2776 the data-sequence points to. 2777 If the cells are already within the range of the sequence nothing needs 2778 to be done. 2779 If the cells are beyond the end of the sequence (are not adjacent to the 2780 current last cell) nothing can be done. Only if the cells are adjacent to 2781 the last cell they can be added. 2782 2783 @returns true if the data-sequence was changed. 2784 @param bExtendCols 2785 specifies if columns or rows are to be extended 2786 @param nFirstNew 2787 index of first new row/col to be included in data-sequence 2788 @param nLastNew 2789 index of last new row/col to be included in data-sequence 2790 */ 2791 bool SwChartDataSequence::ExtendTo( bool bExtendCol, 2792 sal_Int32 nFirstNew, sal_Int32 nCount ) 2793 { 2794 bool bChanged = false; 2795 2796 SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); 2797 //pUnoTblCrsr->MakeBoxSels(); 2798 2799 const SwStartNode *pStartNd = 0; 2800 const SwTableBox *pStartBox = 0; 2801 const SwTableBox *pEndBox = 0; 2802 2803 const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); 2804 DBG_ASSERT( !pTable->IsTblComplex(), "table too complex" ); 2805 if (nCount < 1 || nFirstNew < 0 || pTable->IsTblComplex()) 2806 return false; 2807 2808 // 2809 // get range descriptor (cell range) for current data-sequence 2810 // 2811 pStartNd = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 2812 pEndBox = pTable->GetTblBox( pStartNd->GetIndex() ); 2813 const String aEndBox( pEndBox->GetName() ); 2814 // 2815 pStartNd = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 2816 pStartBox = pTable->GetTblBox( pStartNd->GetIndex() ); 2817 const String aStartBox( pStartBox->GetName() ); 2818 // 2819 String aCellRange( aStartBox ); // note that cell range here takes the newly added rows/cols already into account 2820 aCellRange.AppendAscii( ":" ); 2821 aCellRange += aEndBox; 2822 SwRangeDescriptor aDesc; 2823 FillRangeDescriptor( aDesc, aCellRange ); 2824 2825 String aNewStartCell; 2826 String aNewEndCell; 2827 if (bExtendCol && aDesc.nBottom + 1 == nFirstNew) 2828 { 2829 // new column cells adjacent to the bottom of the 2830 // current data-sequence to be added... 2831 DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); 2832 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); 2833 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom + nCount); 2834 bChanged = true; 2835 } 2836 else if (bExtendCol && aDesc.nTop - nCount == nFirstNew) 2837 { 2838 // new column cells adjacent to the top of the 2839 // current data-sequence to be added... 2840 DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); 2841 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop - nCount); 2842 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); 2843 bChanged = true; 2844 } 2845 else if (!bExtendCol && aDesc.nRight + 1 == nFirstNew) 2846 { 2847 // new row cells adjacent to the right of the 2848 // current data-sequence to be added... 2849 DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); 2850 aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); 2851 aNewEndCell = lcl_GetCellName(aDesc.nRight + nCount, aDesc.nBottom); 2852 bChanged = true; 2853 } 2854 else if (!bExtendCol && aDesc.nLeft - nCount == nFirstNew) 2855 { 2856 // new row cells adjacent to the left of the 2857 // current data-sequence to be added... 2858 DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); 2859 aNewStartCell = lcl_GetCellName(aDesc.nLeft - nCount, aDesc.nTop); 2860 aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); 2861 bChanged = true; 2862 } 2863 2864 if (bChanged) 2865 { 2866 // move table cursor to new start and end of data-sequence 2867 const SwTableBox *pNewStartBox = pTable->GetTblBox( aNewStartCell ); 2868 const SwTableBox *pNewEndBox = pTable->GetTblBox( aNewEndCell ); 2869 pUnoTblCrsr->SetMark(); 2870 pUnoTblCrsr->GetPoint()->nNode = *pNewEndBox->GetSttNd(); 2871 pUnoTblCrsr->GetMark()->nNode = *pNewStartBox->GetSttNd(); 2872 pUnoTblCrsr->Move( fnMoveForward, fnGoNode ); 2873 pUnoTblCrsr->MakeBoxSels(); 2874 } 2875 2876 return bChanged; 2877 } 2878 2879 ////////////////////////////////////////////////////////////////////// 2880 2881 SwChartLabeledDataSequence::SwChartLabeledDataSequence() : 2882 aEvtListeners( GetChartMutex() ), 2883 aModifyListeners( GetChartMutex() ) 2884 { 2885 bDisposed = sal_False; 2886 } 2887 2888 2889 SwChartLabeledDataSequence::~SwChartLabeledDataSequence() 2890 { 2891 } 2892 2893 2894 uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getValues( ) 2895 throw (uno::RuntimeException) 2896 { 2897 vos::OGuard aGuard( Application::GetSolarMutex() ); 2898 if (bDisposed) 2899 throw lang::DisposedException(); 2900 return xData; 2901 } 2902 2903 2904 void SwChartLabeledDataSequence::SetDataSequence( 2905 uno::Reference< chart2::data::XDataSequence >& rxDest, 2906 const uno::Reference< chart2::data::XDataSequence >& rxSource) 2907 { 2908 uno::Reference< util::XModifyListener > xML( dynamic_cast< util::XModifyListener* >(this), uno::UNO_QUERY ); 2909 uno::Reference< lang::XEventListener > xEL( dynamic_cast< lang::XEventListener* >(this), uno::UNO_QUERY ); 2910 2911 // stop listening to old data-sequence 2912 uno::Reference< util::XModifyBroadcaster > xMB( rxDest, uno::UNO_QUERY ); 2913 if (xMB.is()) 2914 xMB->removeModifyListener( xML ); 2915 uno::Reference< lang::XComponent > xC( rxDest, uno::UNO_QUERY ); 2916 if (xC.is()) 2917 xC->removeEventListener( xEL ); 2918 2919 rxDest = rxSource; 2920 2921 // start listening to new data-sequence 2922 xC = uno::Reference< lang::XComponent >( rxDest, uno::UNO_QUERY ); 2923 if (xC.is()) 2924 xC->addEventListener( xEL ); 2925 xMB = uno::Reference< util::XModifyBroadcaster >( rxDest, uno::UNO_QUERY ); 2926 if (xMB.is()) 2927 xMB->addModifyListener( xML ); 2928 } 2929 2930 2931 void SAL_CALL SwChartLabeledDataSequence::setValues( 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 (xData != rxSequence) 2940 { 2941 SetDataSequence( xData, rxSequence ); 2942 // inform listeners of changes 2943 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2944 } 2945 } 2946 2947 2948 uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getLabel( ) 2949 throw (uno::RuntimeException) 2950 { 2951 vos::OGuard aGuard( Application::GetSolarMutex() ); 2952 if (bDisposed) 2953 throw lang::DisposedException(); 2954 return xLabels; 2955 } 2956 2957 2958 void SAL_CALL SwChartLabeledDataSequence::setLabel( 2959 const uno::Reference< chart2::data::XDataSequence >& rxSequence ) 2960 throw (uno::RuntimeException) 2961 { 2962 vos::OGuard aGuard( Application::GetSolarMutex() ); 2963 if (bDisposed) 2964 throw lang::DisposedException(); 2965 2966 if (xLabels != rxSequence) 2967 { 2968 SetDataSequence( xLabels, rxSequence ); 2969 // inform listeners of changes 2970 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 2971 } 2972 } 2973 2974 2975 uno::Reference< util::XCloneable > SAL_CALL SwChartLabeledDataSequence::createClone( ) 2976 throw (uno::RuntimeException) 2977 { 2978 vos::OGuard aGuard( Application::GetSolarMutex() ); 2979 if (bDisposed) 2980 throw lang::DisposedException(); 2981 2982 uno::Reference< util::XCloneable > xRes; 2983 2984 uno::Reference< util::XCloneable > xDataCloneable( xData, uno::UNO_QUERY ); 2985 uno::Reference< util::XCloneable > xLabelsCloneable( xLabels, uno::UNO_QUERY ); 2986 SwChartLabeledDataSequence *pRes = new SwChartLabeledDataSequence(); 2987 if (xDataCloneable.is()) 2988 { 2989 uno::Reference< chart2::data::XDataSequence > xDataClone( xDataCloneable->createClone(), uno::UNO_QUERY ); 2990 pRes->setValues( xDataClone ); 2991 } 2992 2993 if (xLabelsCloneable.is()) 2994 { 2995 uno::Reference< chart2::data::XDataSequence > xLabelsClone( xLabelsCloneable->createClone(), uno::UNO_QUERY ); 2996 pRes->setLabel( xLabelsClone ); 2997 } 2998 xRes = pRes; 2999 return xRes; 3000 } 3001 3002 3003 OUString SAL_CALL SwChartLabeledDataSequence::getImplementationName( ) 3004 throw (uno::RuntimeException) 3005 { 3006 return C2U("SwChartLabeledDataSequence"); 3007 } 3008 3009 3010 sal_Bool SAL_CALL SwChartLabeledDataSequence::supportsService( 3011 const OUString& rServiceName ) 3012 throw (uno::RuntimeException) 3013 { 3014 return rServiceName.equalsAscii( SN_LABELED_DATA_SEQUENCE ); 3015 } 3016 3017 3018 uno::Sequence< OUString > SAL_CALL SwChartLabeledDataSequence::getSupportedServiceNames( ) 3019 throw (uno::RuntimeException) 3020 { 3021 vos::OGuard aGuard( Application::GetSolarMutex() ); 3022 uno::Sequence< OUString > aRes(1); 3023 aRes.getArray()[0] = C2U( SN_LABELED_DATA_SEQUENCE ); 3024 return aRes; 3025 } 3026 3027 3028 void SAL_CALL SwChartLabeledDataSequence::disposing( 3029 const lang::EventObject& rSource ) 3030 throw (uno::RuntimeException) 3031 { 3032 osl::MutexGuard aGuard( GetChartMutex() ); 3033 uno::Reference< uno::XInterface > xRef( rSource.Source ); 3034 if (xRef == xData) 3035 xData.clear(); 3036 if (xRef == xLabels) 3037 xLabels.clear(); 3038 if (!xData.is() && !xLabels.is()) 3039 dispose(); 3040 } 3041 3042 3043 void SAL_CALL SwChartLabeledDataSequence::modified( 3044 const lang::EventObject& rEvent ) 3045 throw (uno::RuntimeException) 3046 { 3047 if (rEvent.Source == xData || rEvent.Source == xLabels) 3048 { 3049 LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); 3050 } 3051 } 3052 3053 3054 void SAL_CALL SwChartLabeledDataSequence::addModifyListener( 3055 const uno::Reference< util::XModifyListener >& rxListener ) 3056 throw (uno::RuntimeException) 3057 { 3058 osl::MutexGuard aGuard( GetChartMutex() ); 3059 if (!bDisposed && rxListener.is()) 3060 aModifyListeners.addInterface( rxListener ); 3061 } 3062 3063 3064 void SAL_CALL SwChartLabeledDataSequence::removeModifyListener( 3065 const uno::Reference< util::XModifyListener >& rxListener ) 3066 throw (uno::RuntimeException) 3067 { 3068 osl::MutexGuard aGuard( GetChartMutex() ); 3069 if (!bDisposed && rxListener.is()) 3070 aModifyListeners.removeInterface( rxListener ); 3071 } 3072 3073 3074 void SAL_CALL SwChartLabeledDataSequence::dispose( ) 3075 throw (uno::RuntimeException) 3076 { 3077 sal_Bool bMustDispose( sal_False ); 3078 { 3079 osl::MutexGuard aGuard( GetChartMutex() ); 3080 bMustDispose = !bDisposed; 3081 if (!bDisposed) 3082 bDisposed = sal_True; 3083 } 3084 if (bMustDispose) 3085 { 3086 bDisposed = sal_True; 3087 3088 // require listeners to release references to this object 3089 lang::EventObject aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence * >(this) ); 3090 aModifyListeners.disposeAndClear( aEvtObj ); 3091 aEvtListeners.disposeAndClear( aEvtObj ); 3092 } 3093 } 3094 3095 3096 void SAL_CALL SwChartLabeledDataSequence::addEventListener( 3097 const uno::Reference< lang::XEventListener >& rxListener ) 3098 throw (uno::RuntimeException) 3099 { 3100 osl::MutexGuard aGuard( GetChartMutex() ); 3101 if (!bDisposed && rxListener.is()) 3102 aEvtListeners.addInterface( rxListener ); 3103 } 3104 3105 3106 void SAL_CALL SwChartLabeledDataSequence::removeEventListener( 3107 const uno::Reference< lang::XEventListener >& rxListener ) 3108 throw (uno::RuntimeException) 3109 { 3110 osl::MutexGuard aGuard( GetChartMutex() ); 3111 if (!bDisposed && rxListener.is()) 3112 aEvtListeners.removeInterface( rxListener ); 3113 } 3114 3115 ////////////////////////////////////////////////////////////////////// 3116