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