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