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