1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <com/sun/star/chart/ChartDataRowSource.hpp>
24 #include <com/sun/star/chart2/data/LabelOrigin.hpp>
25 #include <cppuhelper/interfacecontainer.hxx>
26 #include <osl/mutex.hxx>
27 #include <vcl/svapp.hxx>
28 #include <svl/zforlist.hxx> // SvNumberFormatter
29 #include <svx/charthelper.hxx>
31 #include <XMLRangeHelper.hxx>
32 #include <unochart.hxx>
33 #include <swtable.hxx>
34 #include <unoprnms.hxx>
37 #include <unocrsr.hxx>
43 #include <swtypes.hxx>
44 #include <unocore.hrc>
46 #include <comphelper/servicehelper.hxx>
47 #include <comphelper/string.hxx>
49 #define SN_DATA_PROVIDER "com.sun.star.chart2.data.DataProvider"
50 #define SN_DATA_SOURCE "com.sun.star.chart2.data.DataSource"
51 #define SN_DATA_SEQUENCE "com.sun.star.chart2.data.DataSequence"
52 #define SN_LABELED_DATA_SEQUENCE "com.sun.star.chart2.data.LabeledDataSequence"
54 using namespace ::com::sun::star
;
57 extern void sw_GetCellPosition( const String
&rCellName
, sal_Int32
&rColumn
, sal_Int32
&rRow
);
58 extern String
sw_GetCellName( sal_Int32 nColumn
, sal_Int32 nRow
);
59 extern int sw_CompareCellsByColFirst( const String
&rCellName1
, const String
&rCellName2
);
60 extern int sw_CompareCellsByRowFirst( const String
&rCellName1
, const String
&rCellName2
);
61 extern int sw_CompareCellRanges(
62 const String
&rRange1StartCell
, const String
&rRange1EndCell
,
63 const String
&rRange2StartCell
, const String
&rRange2EndCell
,
64 sal_Bool bCmpColsFirst
);
65 extern void sw_NormalizeRange( String
&rCell1
, String
&rCell2
);
68 void SwChartHelper::DoUpdateAllCharts( SwDoc
* pDoc
)
73 uno::Reference
< frame::XModel
> xRes
;
77 SwNodeIndex
aIdx( *pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
78 while( 0 != (pStNd
= aIdx
.GetNode().GetStartNode()) )
81 if (0 != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
82 ChartHelper::IsChart( pONd
->GetOLEObj().GetObject() ) )
84 // Load the object and set modified
86 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
87 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
91 uno::Reference
< util::XModifiable
> xModif( xIP
->getComponent(), uno::UNO_QUERY_THROW
);
92 xModif
->setModified( sal_True
);
94 catch ( uno::Exception
& )
100 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
104 SwChartLockController_Helper::SwChartLockController_Helper( SwDoc
*pDocument
) :
108 aUnlockTimer
.SetTimeout( 1500 );
109 aUnlockTimer
.SetTimeoutHdl( LINK( this, SwChartLockController_Helper
, DoUnlockAllCharts
));
112 SwChartLockController_Helper::~SwChartLockController_Helper()
114 if (pDoc
) // still connected?
118 void SwChartLockController_Helper::StartOrContinueLocking()
122 aUnlockTimer
.Start(); // start or continue time of locking
125 void SwChartLockController_Helper::Disconnect()
132 void SwChartLockController_Helper::LockUnlockAllCharts( sal_Bool bLock
)
137 const SwFrmFmts
& rTblFmts
= *pDoc
->GetTblFrmFmts();
138 for( sal_uInt16 n
= 0; n
< rTblFmts
.size(); ++n
)
141 const SwTableNode
* pTblNd
;
142 SwFrmFmt
* pFmt
= rTblFmts
[ n
];
144 if( 0 != ( pTmpTbl
= SwTable::FindTable( pFmt
) ) &&
145 0 != ( pTblNd
= pTmpTbl
->GetTableNode() ) &&
146 pTblNd
->GetNodes().IsDocNodes() )
148 uno::Reference
< frame::XModel
> xRes
;
151 SwNodeIndex
aIdx( *pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
152 while( 0 != (pStNd
= aIdx
.GetNode().GetStartNode()) )
155 if (0 != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
156 pONd
->GetChartTblName().Len() > 0 /* is chart object? */)
158 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
159 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
161 xRes
= uno::Reference
< frame::XModel
>( xIP
->getComponent(), uno::UNO_QUERY
);
165 xRes
->lockControllers();
167 xRes
->unlockControllers();
171 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
179 IMPL_LINK( SwChartLockController_Helper
, DoUnlockAllCharts
, Timer
*, /*pTimer*/ )
185 static osl::Mutex
& GetChartMutex()
187 static osl::Mutex aMutex
;
191 static void LaunchModifiedEvent(
192 ::cppu::OInterfaceContainerHelper
&rICH
,
193 const uno::Reference
< uno::XInterface
> &rxI
)
195 lang::EventObject
aEvtObj( rxI
);
196 cppu::OInterfaceIteratorHelper
aIt( rICH
);
197 while (aIt
.hasMoreElements())
199 uno::Reference
< util::XModifyListener
> xRef( aIt
.next(), uno::UNO_QUERY
);
201 xRef
->modified( aEvtObj
);
205 // rCellRangeName needs to be of one of the following formats:
207 // - e.g. "Table1.A2:E5"
208 bool FillRangeDescriptor(
209 SwRangeDescriptor
&rDesc
,
210 const String
&rCellRangeName
)
212 xub_StrLen nToken
= STRING_NOTFOUND
== rCellRangeName
.Search('.') ? 0 : 1;
213 String
aCellRangeNoTableName( rCellRangeName
.GetToken( nToken
, '.' ) );
214 String
aTLName( aCellRangeNoTableName
.GetToken(0, ':') ); // name of top left cell
215 String
aBRName( aCellRangeNoTableName
.GetToken(1, ':') ); // name of bottom right cell
216 if(!aTLName
.Len() || !aBRName
.Len())
219 rDesc
.nTop
= rDesc
.nLeft
= rDesc
.nBottom
= rDesc
.nRight
= -1;
220 sw_GetCellPosition( aTLName
, rDesc
.nLeft
, rDesc
.nTop
);
221 sw_GetCellPosition( aBRName
, rDesc
.nRight
, rDesc
.nBottom
);
223 OSL_ENSURE( rDesc
.nTop
!= -1 &&
225 rDesc
.nBottom
!= -1 &&
227 "failed to get range descriptor" );
228 OSL_ENSURE( rDesc
.nTop
<= rDesc
.nBottom
&& rDesc
.nLeft
<= rDesc
.nRight
,
229 "invalid range descriptor");
233 static String
GetCellRangeName( SwFrmFmt
&rTblFmt
, SwUnoCrsr
&rTblCrsr
)
237 //!! see also SwXTextTableCursor::getRangeName
239 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(&rTblCrsr
);
242 pUnoTblCrsr
->MakeBoxSels();
244 const SwStartNode
* pStart
;
245 const SwTableBox
* pStartBox
= 0;
246 const SwTableBox
* pEndBox
= 0;
248 pStart
= pUnoTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
251 const SwTable
* pTable
= SwTable::FindTable( &rTblFmt
);
252 pEndBox
= pTable
->GetTblBox( pStart
->GetIndex());
253 aRes
= pEndBox
->GetName();
255 if(pUnoTblCrsr
->HasMark())
257 pStart
= pUnoTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
258 pStartBox
= pTable
->GetTblBox( pStart
->GetIndex());
260 OSL_ENSURE( pStartBox
, "start box not found" );
261 OSL_ENSURE( pEndBox
, "end box not found" );
262 // need to switch start and end?
263 if (*pUnoTblCrsr
->GetPoint() < *pUnoTblCrsr
->GetMark())
265 const SwTableBox
* pTmpBox
= pStartBox
;
270 aRes
= pStartBox
->GetName();
271 aRes
+= (sal_Unicode
)':';
273 aRes
+= pEndBox
->GetName();
275 aRes
+= pStartBox
->GetName();
281 static String
GetRangeRepFromTableAndCells( const String
&rTableName
,
282 const String
&rStartCell
, const String
&rEndCell
,
283 sal_Bool bForceEndCellName
)
285 OSL_ENSURE( rTableName
.Len(), "table name missing" );
286 OSL_ENSURE( rStartCell
.Len(), "cell name missing" );
287 String
aRes( rTableName
);
288 aRes
+= (sal_Unicode
) '.';
293 aRes
+= (sal_Unicode
) ':';
296 else if (bForceEndCellName
)
298 aRes
+= (sal_Unicode
) ':';
305 static bool GetTableAndCellsFromRangeRep(
306 const OUString
&rRangeRepresentation
,
310 bool bSortStartEndCells
= true )
312 // parse range representation for table name and cell/range names
313 // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2"
314 String aTblName
; // table name
315 OUString aRange
; // cell range
316 String aStartCell
; // name of top left cell
317 String aEndCell
; // name of bottom right cell
318 sal_Int32 nIdx
= rRangeRepresentation
.indexOf( '.' );
321 aTblName
= rRangeRepresentation
.copy( 0, nIdx
);
322 aRange
= rRangeRepresentation
.copy( nIdx
+ 1 );
323 sal_Int32 nPos
= aRange
.indexOf( ':' );
324 if (nPos
>= 0) // a cell-range like "Table1.A2:D4"
326 aStartCell
= aRange
.copy( 0, nPos
);
327 aEndCell
= aRange
.copy( nPos
+ 1 );
329 // need to switch start and end cell ?
330 // (does not check for normalization here)
331 if (bSortStartEndCells
&& 1 == sw_CompareCellsByColFirst( aStartCell
, aEndCell
))
333 String
aTmp( aStartCell
);
334 aStartCell
= aEndCell
;
338 else // a single cell like in "Table1.B3"
340 aStartCell
= aEndCell
= aRange
;
344 bool bSuccess
= aTblName
.Len() != 0 &&
345 aStartCell
.Len() != 0 && aEndCell
.Len() != 0;
349 rStartCell
= aStartCell
;
355 static void GetTableByName( const SwDoc
&rDoc
, const String
&rTableName
,
356 SwFrmFmt
**ppTblFmt
, SwTable
**ppTable
)
358 SwFrmFmt
*pTblFmt
= NULL
;
360 // find frame format of table
361 //! see SwXTextTables::getByName
362 sal_uInt16 nCount
= rDoc
.GetTblFrmFmtCount(true);
363 for (sal_uInt16 i
= 0; i
< nCount
&& !pTblFmt
; ++i
)
365 SwFrmFmt
& rTblFmt
= rDoc
.GetTblFrmFmt(i
, true);
366 if(rTableName
== rTblFmt
.GetName())
374 *ppTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
377 static void GetFormatAndCreateCursorFromRangeRep(
379 const OUString
&rRangeRepresentation
, // must be a single range (i.e. so called sub-range)
380 SwFrmFmt
**ppTblFmt
, // will be set to the table format of the table used in the range representation
381 SwUnoCrsr
**ppUnoCrsr
) // will be set to cursor spanning the cell range
382 // (cursor will be created!)
384 String aTblName
; // table name
385 String aStartCell
; // name of top left cell
386 String aEndCell
; // name of bottom right cell
387 bool bNamesFound
= GetTableAndCellsFromRangeRep( rRangeRepresentation
,
388 aTblName
, aStartCell
, aEndCell
);
399 SwFrmFmt
*pTblFmt
= NULL
;
401 // is the correct table format already provided?
402 if (*ppTblFmt
!= NULL
&& (*ppTblFmt
)->GetName() == aTblName
)
405 GetTableByName( *pDoc
, aTblName
, &pTblFmt
, NULL
);
410 if (ppUnoCrsr
!= NULL
)
412 *ppUnoCrsr
= NULL
; // default result in case of failure
414 SwTable
*pTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
415 // create new SwUnoCrsr spanning the specified range
416 //! see also SwXTextTable::GetRangeByName
418 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
419 const SwTableBox
* pTLBox
=
420 pTable
? pTable
->GetTblBox( aStartCell
, true ) : 0;
423 // hier muessen die Actions aufgehoben werden
424 UnoActionRemoveContext
aRemoveContext(pTblFmt
->GetDoc());
425 const SwStartNode
* pSttNd
= pTLBox
->GetSttNd();
426 SwPosition
aPos(*pSttNd
);
427 // set cursor to top left box of range
428 SwUnoCrsr
* pUnoCrsr
= pTblFmt
->GetDoc()->CreateUnoCrsr(aPos
, true);
429 pUnoCrsr
->Move( fnMoveForward
, fnGoNode
);
430 pUnoCrsr
->SetRemainInSection( sal_False
);
432 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
433 const SwTableBox
* pBRBox
= pTable
->GetTblBox( aEndCell
, true );
437 pUnoCrsr
->GetPoint()->nNode
= *pBRBox
->GetSttNd();
438 pUnoCrsr
->Move( fnMoveForward
, fnGoNode
);
439 SwUnoTableCrsr
* pCrsr
=
440 dynamic_cast<SwUnoTableCrsr
*>(pUnoCrsr
);
441 pCrsr
->MakeBoxSels();
455 static bool GetSubranges( const OUString
&rRangeRepresentation
,
456 uno::Sequence
< OUString
> &rSubRanges
, bool bNormalize
)
459 String
aRangesStr( rRangeRepresentation
);
460 xub_StrLen nLen
= comphelper::string::getTokenCount(aRangesStr
, ';');
461 uno::Sequence
< OUString
> aRanges( nLen
);
466 OUString
*pRanges
= aRanges
.getArray();
468 for ( xub_StrLen i
= 0; i
< nLen
&& bRes
; ++i
)
470 String
aRange( aRangesStr
.GetToken( i
, ';' ) );
473 pRanges
[nCnt
] = aRange
;
475 String aTableName
, aStartCell
, aEndCell
;
476 if (!GetTableAndCellsFromRangeRep( aRange
,
477 aTableName
, aStartCell
, aEndCell
))
482 sw_NormalizeRange( aStartCell
, aEndCell
);
483 pRanges
[nCnt
] = GetRangeRepFromTableAndCells( aTableName
,
484 aStartCell
, aEndCell
, sal_True
);
487 // make sure to use only a single table
489 aFirstTable
= aTableName
;
491 if (aFirstTable
!= aTableName
) bRes
= false;
497 aRanges
.realloc( nCnt
);
499 rSubRanges
= aRanges
;
503 static void SortSubranges( uno::Sequence
< OUString
> &rSubRanges
, sal_Bool bCmpByColumn
)
505 sal_Int32 nLen
= rSubRanges
.getLength();
506 OUString
*pSubRanges
= rSubRanges
.getArray();
508 String aSmallestTblName
;
509 String aSmallestStartCell
;
510 String aSmallestEndCell
;
512 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
514 sal_Int32 nIdxOfSmallest
= i
;
515 GetTableAndCellsFromRangeRep( pSubRanges
[nIdxOfSmallest
],
516 aSmallestTblName
, aSmallestStartCell
, aSmallestEndCell
);
517 if (aSmallestEndCell
.Len() == 0)
518 aSmallestEndCell
= aSmallestStartCell
;
520 for (sal_Int32 k
= i
+1; k
< nLen
; ++k
)
522 // get cell names for sub range
526 GetTableAndCellsFromRangeRep( pSubRanges
[k
],
527 aTblName
, aStartCell
, aEndCell
);
528 if (aEndCell
.Len() == 0)
529 aEndCell
= aStartCell
;
531 // compare cell ranges ( is the new one smaller? )
532 if (-1 == sw_CompareCellRanges( aStartCell
, aEndCell
,
533 aSmallestStartCell
, aSmallestEndCell
, bCmpByColumn
))
536 aSmallestTblName
= aTblName
;
537 aSmallestStartCell
= aStartCell
;
538 aSmallestEndCell
= aEndCell
;
542 // move smallest element to the start of the not sorted area
543 OUString
aTmp( pSubRanges
[ nIdxOfSmallest
] );
544 pSubRanges
[ nIdxOfSmallest
] = pSubRanges
[ i
];
545 pSubRanges
[ i
] = aTmp
;
549 SwChartDataProvider::SwChartDataProvider( const SwDoc
* pSwDoc
) :
550 aEvtListeners( GetChartMutex() ),
553 bDisposed
= sal_False
;
556 SwChartDataProvider::~SwChartDataProvider()
560 uno::Reference
< chart2::data::XDataSource
> SwChartDataProvider::Impl_createDataSource(
561 const uno::Sequence
< beans::PropertyValue
>& rArguments
, sal_Bool bTestOnly
)
562 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
564 SolarMutexGuard aGuard
;
566 throw lang::DisposedException();
568 uno::Reference
< chart2::data::XDataSource
> xRes
;
571 throw uno::RuntimeException();
574 OUString aRangeRepresentation
;
575 uno::Sequence
< sal_Int32
> aSequenceMapping
;
576 sal_Bool bFirstIsLabel
= sal_False
;
577 sal_Bool bDtaSrcIsColumns
= sal_True
; // true : DataSource will be sequence of columns
578 // false: DataSource will be sequence of rows
579 OUString aChartOleObjectName
;//work around wrong writer ranges ( see Issue 58464 )
580 sal_Int32 nArgs
= rArguments
.getLength();
581 OSL_ENSURE( nArgs
!= 0, "no properties provided" );
584 const beans::PropertyValue
*pArg
= rArguments
.getConstArray();
585 for (sal_Int32 i
= 0; i
< nArgs
; ++i
)
587 if ( pArg
[i
].Name
== "DataRowSource" )
589 chart::ChartDataRowSource eSource
;
590 if (!(pArg
[i
].Value
>>= eSource
))
593 if (!(pArg
[i
].Value
>>= nTmp
))
594 throw lang::IllegalArgumentException();
595 eSource
= static_cast< chart::ChartDataRowSource
>( nTmp
);
597 bDtaSrcIsColumns
= eSource
== chart::ChartDataRowSource_COLUMNS
;
599 else if ( pArg
[i
].Name
== "FirstCellAsLabel" )
601 if (!(pArg
[i
].Value
>>= bFirstIsLabel
))
602 throw lang::IllegalArgumentException();
604 else if ( pArg
[i
].Name
== "CellRangeRepresentation" )
606 if (!(pArg
[i
].Value
>>= aRangeRepresentation
))
607 throw lang::IllegalArgumentException();
609 else if ( pArg
[i
].Name
== "SequenceMapping" )
611 if (!(pArg
[i
].Value
>>= aSequenceMapping
))
612 throw lang::IllegalArgumentException();
614 else if ( pArg
[i
].Name
== "ChartOleObjectName" )
616 if (!(pArg
[i
].Value
>>= aChartOleObjectName
))
617 throw lang::IllegalArgumentException();
621 uno::Sequence
< OUString
> aSubRanges
;
622 // get sub-ranges and check that they all are from the very same table
623 sal_Bool bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, sal_True
);
625 if (!bOk
&& pDoc
&& !aChartOleObjectName
.isEmpty() )
627 //try to correct the range here
628 //work around wrong writer ranges ( see Issue 58464 )
629 String aChartTableName
;
631 const SwNodes
& rNodes
= pDoc
->GetNodes();
632 for( sal_uLong nN
= rNodes
.Count(); nN
--; )
634 SwNodePtr pNode
= rNodes
[nN
];
637 const SwOLENode
* pOleNode
= pNode
->GetOLENode();
640 const SwOLEObj
& rOObj
= pOleNode
->GetOLEObj();
641 if( aChartOleObjectName
.equals( rOObj
.GetCurrentPersistName() ) )
643 aChartTableName
= pOleNode
->GetChartTblName();
648 if( aChartTableName
.Len() )
650 //the wrong range is still shifted one row down
651 //thus the first row is missing and an invalid row at the end is added.
652 //Therefore we need to shift the range one row up
653 SwRangeDescriptor aDesc
;
654 if (aRangeRepresentation
.isEmpty())
655 return xRes
; // we cant handle this thus returning an empty references
656 aRangeRepresentation
= aRangeRepresentation
.copy( 1 ); // get rid of '.' to have only the cell range left
657 FillRangeDescriptor( aDesc
, aRangeRepresentation
);
659 if (aDesc
.nTop
<= 0) // no chance to shift the range one row up?
660 return xRes
; // we cant handle this thus returning an empty references
664 String
aNewStartCell( sw_GetCellName( aDesc
.nLeft
, aDesc
.nTop
) );
665 String
aNewEndCell( sw_GetCellName( aDesc
.nRight
, aDesc
.nBottom
) );
666 aRangeRepresentation
= GetRangeRepFromTableAndCells(
667 aChartTableName
, aNewStartCell
, aNewEndCell
, sal_True
);
668 bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, sal_True
);
671 if (!bOk
) // different tables used, or incorrect range specifiers
672 throw lang::IllegalArgumentException();
674 SortSubranges( aSubRanges
, bDtaSrcIsColumns
);
675 const OUString
*pSubRanges
= aSubRanges
.getConstArray();
676 #if OSL_DEBUG_LEVEL > 1
678 sal_Int32 nSR
= aSubRanges
.getLength();
679 OUString
*pSR
= aSubRanges
.getArray();
681 for (sal_Int32 i
= 0; i
< nSR
; ++i
)
688 // get table format for that single table from above
689 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
690 SwUnoCrsr
*pUnoCrsr
= 0; // here required to check if the cells in the range do actually exist
691 std::auto_ptr
< SwUnoCrsr
> pAuto( pUnoCrsr
); // to end lifetime of object pointed to by pUnoCrsr
692 if (aSubRanges
.getLength() > 0)
693 GetFormatAndCreateCursorFromRangeRep( pDoc
, pSubRanges
[0], &pTblFmt
, &pUnoCrsr
);
694 if (!pTblFmt
|| !pUnoCrsr
)
695 throw lang::IllegalArgumentException();
699 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
700 if(pTable
->IsTblComplex())
701 return xRes
; // we cant handle this thus returning an empty references
704 // get a character map in the size of the table to mark
705 // all the ranges to use in
706 sal_Int32 nRows
= pTable
->GetTabLines().size();
707 sal_Int32 nCols
= pTable
->GetTabLines().front()->GetTabBoxes().size();
708 std::vector
< std::vector
< sal_Char
> > aMap( nRows
);
709 for (sal_Int32 i
= 0; i
< nRows
; ++i
)
710 aMap
[i
].resize( nCols
);
712 // iterate over subranges and mark used cells in above map
713 //!! by proceeding this way we automatically get rid of
714 //!! multiple listed or overlapping cell ranges which should
715 //!! just be ignored silently
716 sal_Int32 nSubRanges
= aSubRanges
.getLength();
717 for (sal_Int32 i
= 0; i
< nSubRanges
; ++i
)
719 String aTblName
, aStartCell
, aEndCell
;
720 bool bOk2
= GetTableAndCellsFromRangeRep(
721 pSubRanges
[i
], aTblName
, aStartCell
, aEndCell
);
723 OSL_ENSURE( bOk2
, "failed to get table and start/end cells" );
725 sal_Int32 nStartRow
, nStartCol
, nEndRow
, nEndCol
;
726 sw_GetCellPosition( aStartCell
, nStartCol
, nStartRow
);
727 sw_GetCellPosition( aEndCell
, nEndCol
, nEndRow
);
728 OSL_ENSURE( nStartRow
<= nEndRow
&& nStartCol
<= nEndCol
,
729 "cell range not normalized");
731 // test if the ranges span more than the available cells
732 if( nStartRow
< 0 || nEndRow
>= nRows
||
733 nStartCol
< 0 || nEndCol
>= nCols
)
735 throw lang::IllegalArgumentException();
737 for (sal_Int32 k1
= nStartRow
; k1
<= nEndRow
; ++k1
)
739 for (sal_Int32 k2
= nStartCol
; k2
<= nEndCol
; ++k2
)
745 // find label and data sequences to use
747 sal_Int32 oi
; // outer index (slower changing index)
748 sal_Int32 ii
; // inner index (faster changing index)
749 sal_Int32 oiEnd
= bDtaSrcIsColumns
? nCols
: nRows
;
750 sal_Int32 iiEnd
= bDtaSrcIsColumns
? nRows
: nCols
;
751 std::vector
< sal_Int32
> aLabelIdx( oiEnd
);
752 std::vector
< sal_Int32
> aDataStartIdx( oiEnd
);
753 std::vector
< sal_Int32
> aDataLen( oiEnd
);
754 for (oi
= 0; oi
< oiEnd
; ++oi
)
757 aDataStartIdx
[oi
] = -1;
761 for (oi
= 0; oi
< oiEnd
; ++oi
)
766 sal_Char
&rChar
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
];
768 // label should be used but is not yet found?
769 if (rChar
== 'x' && bFirstIsLabel
&& aLabelIdx
[oi
] == -1)
772 rChar
= 'L'; // setting a different char for labels here
773 // makes the test for the data sequence below
777 // find data sequence
778 if (rChar
== 'x' && aDataStartIdx
[oi
] == -1)
780 aDataStartIdx
[oi
] = ii
;
782 // get length of data sequence
785 while (ii
< iiEnd
&& 'x' == (c
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
791 // check that there is no other separate sequence of data
792 // to be found because that is not supported
795 if ('x' == (c
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
796 throw lang::IllegalArgumentException();
805 // make some other consistency checks while calculating
806 // the number of XLabeledDataSequence to build:
807 // - labels should always be used or not at all
808 // - the data sequences should have equal non-zero length
809 sal_Int32 nNumLDS
= 0;
812 sal_Int32 nFirstSeqLen
= 0;
813 sal_Int32 nFirstSeqLabelIdx
= -1;
814 for (oi
= 0; oi
< oiEnd
; ++oi
)
816 bool bFirstFound
= false;
817 // row/col used at all?
818 if (aDataStartIdx
[oi
] != -1 &&
819 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1))
824 nFirstSeqLen
= aDataLen
[oi
];
825 nFirstSeqLabelIdx
= aLabelIdx
[oi
];
830 if (nFirstSeqLen
!= aDataLen
[oi
] ||
831 nFirstSeqLabelIdx
!= aLabelIdx
[oi
])
832 throw lang::IllegalArgumentException();
838 throw lang::IllegalArgumentException();
840 // now we should have all necessary data to build a proper DataSource
841 // thus if we came this far there should be no further problem
843 return xRes
; // have createDataSourcePossible return true
845 // create data source from found label and data sequences
846 uno::Sequence
< uno::Reference
< chart2::data::XDataSequence
> > aLabelSeqs( nNumLDS
);
847 uno::Reference
< chart2::data::XDataSequence
> *pLabelSeqs
= aLabelSeqs
.getArray();
848 uno::Sequence
< uno::Reference
< chart2::data::XDataSequence
> > aDataSeqs( nNumLDS
);
849 uno::Reference
< chart2::data::XDataSequence
> *pDataSeqs
= aDataSeqs
.getArray();
850 sal_Int32 nSeqsIdx
= 0;
851 for (oi
= 0; oi
< oiEnd
; ++oi
)
853 // row/col not used? (see if-statement above where nNumLDS was counted)
854 if (!(aDataStartIdx
[oi
] != -1 &&
855 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1)))
858 // get cell ranges for label and data
860 SwRangeDescriptor aLabelDesc
;
861 SwRangeDescriptor aDataDesc
;
862 if (bDtaSrcIsColumns
) // use columns
864 aLabelDesc
.nTop
= aLabelIdx
[oi
];
865 aLabelDesc
.nLeft
= oi
;
866 aLabelDesc
.nBottom
= aLabelDesc
.nTop
;
867 aLabelDesc
.nRight
= oi
;
869 aDataDesc
.nTop
= aDataStartIdx
[oi
];
870 aDataDesc
.nLeft
= oi
;
871 aDataDesc
.nBottom
= aDataDesc
.nTop
+ aDataLen
[oi
] - 1;
872 aDataDesc
.nRight
= oi
;
876 aLabelDesc
.nTop
= oi
;
877 aLabelDesc
.nLeft
= aLabelIdx
[oi
];
878 aLabelDesc
.nBottom
= oi
;
879 aLabelDesc
.nRight
= aLabelDesc
.nLeft
;
882 aDataDesc
.nLeft
= aDataStartIdx
[oi
];
883 aDataDesc
.nBottom
= oi
;
884 aDataDesc
.nRight
= aDataDesc
.nLeft
+ aDataLen
[oi
] - 1;
886 String
aBaseName( pTblFmt
->GetName() );
890 if (aLabelIdx
[oi
] != -1)
892 aLabelRange
+= aBaseName
;
893 aLabelRange
+= sw_GetCellName( aLabelDesc
.nLeft
, aLabelDesc
.nTop
);
895 aLabelRange
+= sw_GetCellName( aLabelDesc
.nRight
, aLabelDesc
.nBottom
);
899 if (aDataStartIdx
[oi
] != -1)
901 aDataRange
+= aBaseName
;
902 aDataRange
+= sw_GetCellName( aDataDesc
.nLeft
, aDataDesc
.nTop
);
904 aDataRange
+= sw_GetCellName( aDataDesc
.nRight
, aDataDesc
.nBottom
);
907 // get cursors spanning the cell ranges for label and data
908 SwUnoCrsr
*pLabelUnoCrsr
= 0;
909 SwUnoCrsr
*pDataUnoCrsr
= 0;
910 GetFormatAndCreateCursorFromRangeRep( pDoc
, aLabelRange
, &pTblFmt
, &pLabelUnoCrsr
);
911 GetFormatAndCreateCursorFromRangeRep( pDoc
, aDataRange
, &pTblFmt
, &pDataUnoCrsr
);
913 // create XDataSequence's from cursors
915 pLabelSeqs
[ nSeqsIdx
] = new SwChartDataSequence( *this, *pTblFmt
, pLabelUnoCrsr
);
916 OSL_ENSURE( pDataUnoCrsr
, "pointer to data sequence missing" );
918 pDataSeqs
[ nSeqsIdx
] = new SwChartDataSequence( *this, *pTblFmt
, pDataUnoCrsr
);
919 if (pLabelUnoCrsr
|| pDataUnoCrsr
)
922 OSL_ENSURE( nSeqsIdx
== nNumLDS
,
923 "mismatch between sequence size and num,ber of entries" );
925 // build data source from data and label sequences
926 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aLDS( nNumLDS
);
927 uno::Reference
< chart2::data::XLabeledDataSequence
> *pLDS
= aLDS
.getArray();
928 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
930 SwChartLabeledDataSequence
*pLabeledDtaSeq
= new SwChartLabeledDataSequence
;
931 pLabeledDtaSeq
->setLabel( pLabelSeqs
[i
] );
932 pLabeledDtaSeq
->setValues( pDataSeqs
[i
] );
933 pLDS
[i
] = pLabeledDtaSeq
;
936 // apply 'SequenceMapping' if it was provided
937 sal_Int32 nSequenceMappingLen
= aSequenceMapping
.getLength();
938 if (nSequenceMappingLen
)
940 sal_Int32
*pSequenceMapping
= aSequenceMapping
.getArray();
941 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aOld_LDS( aLDS
);
942 uno::Reference
< chart2::data::XLabeledDataSequence
> *pOld_LDS
= aOld_LDS
.getArray();
944 sal_Int32 nNewCnt
= 0;
945 for (sal_Int32 i
= 0; i
< nSequenceMappingLen
; ++i
)
947 // check that index to be used is valid
948 // and has not yet been used
949 sal_Int32 nIdx
= pSequenceMapping
[i
];
950 if (0 <= nIdx
&& nIdx
< nNumLDS
&& pOld_LDS
[nIdx
].is())
952 pLDS
[nNewCnt
++] = pOld_LDS
[nIdx
];
954 // mark index as being used already (avoids duplicate entries)
955 pOld_LDS
[nIdx
].clear();
958 // add not yet used 'old' sequences to new one
959 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
961 #if OSL_DEBUG_LEVEL > 1
962 if (!pOld_LDS
[i
].is())
965 if (pOld_LDS
[i
].is())
966 pLDS
[nNewCnt
++] = pOld_LDS
[i
];
968 OSL_ENSURE( nNewCnt
== nNumLDS
, "unexpected size of resulting sequence" );
971 xRes
= new SwChartDataSource( aLDS
);
978 sal_Bool SAL_CALL
SwChartDataProvider::createDataSourcePossible(
979 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
980 throw (uno::RuntimeException
)
982 SolarMutexGuard aGuard
;
984 sal_Bool bPossible
= sal_True
;
987 Impl_createDataSource( rArguments
, sal_True
);
989 catch (lang::IllegalArgumentException
&)
991 bPossible
= sal_False
;
997 uno::Reference
< chart2::data::XDataSource
> SAL_CALL
SwChartDataProvider::createDataSource(
998 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
999 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1001 SolarMutexGuard aGuard
;
1002 return Impl_createDataSource( rArguments
);
1005 ////////////////////////////////////////////////////////////
1006 // SwChartDataProvider::GetBrokenCellRangeForExport
1009 // we need to return a property that has the same value as the property
1010 // 'CellRangeRepresentation' but for all rows which are increased by one.
1011 // E.g. Table1:A1:D5 -> Table1:A2:D6
1012 // Since the problem is only for old charts which did not support multiple
1013 // we do not need to provide that property/string if the 'CellRangeRepresentation'
1014 // contains multiple ranges.
1015 OUString
SwChartDataProvider::GetBrokenCellRangeForExport(
1016 const OUString
&rCellRangeRepresentation
)
1020 // check that we do not have multiple ranges
1021 if (-1 == rCellRangeRepresentation
.indexOf( ';' ))
1023 // get current cell and table names
1024 String aTblName
, aStartCell
, aEndCell
;
1025 GetTableAndCellsFromRangeRep( rCellRangeRepresentation
,
1026 aTblName
, aStartCell
, aEndCell
, false );
1027 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1028 sw_GetCellPosition( aStartCell
, nStartCol
, nStartRow
);
1029 sw_GetCellPosition( aEndCell
, nEndCol
, nEndRow
);
1031 // get new cell names
1034 aStartCell
= sw_GetCellName( nStartCol
, nStartRow
);
1035 aEndCell
= sw_GetCellName( nEndCol
, nEndRow
);
1037 aRes
= GetRangeRepFromTableAndCells( aTblName
,
1038 aStartCell
, aEndCell
, sal_False
);
1044 uno::Sequence
< beans::PropertyValue
> SAL_CALL
SwChartDataProvider::detectArguments(
1045 const uno::Reference
< chart2::data::XDataSource
>& xDataSource
)
1046 throw (uno::RuntimeException
)
1048 SolarMutexGuard aGuard
;
1050 throw lang::DisposedException();
1052 uno::Sequence
< beans::PropertyValue
> aResult
;
1053 if (!xDataSource
.is())
1056 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aDS_LDS( xDataSource
->getDataSequences() );
1057 const uno::Reference
< chart2::data::XLabeledDataSequence
> *pDS_LDS
= aDS_LDS
.getConstArray();
1058 sal_Int32 nNumDS_LDS
= aDS_LDS
.getLength();
1060 if (nNumDS_LDS
== 0)
1062 OSL_FAIL( "XLabeledDataSequence in data source contains 0 entries" );
1066 SwFrmFmt
*pTableFmt
= 0;
1067 SwTable
*pTable
= 0;
1069 sal_Int32 nTableRows
= 0;
1070 sal_Int32 nTableCols
= 0;
1072 // data used to build 'CellRangeRepresentation' from later on
1073 std::vector
< std::vector
< sal_Char
> > aMap
;
1075 uno::Sequence
< sal_Int32
> aSequenceMapping( nNumDS_LDS
);
1076 sal_Int32
*pSequenceMapping
= aSequenceMapping
.getArray();
1079 sal_Int16 nDtaSrcIsColumns
= -1;// -1: don't know yet, 0: false, 1: true -2: neither
1080 sal_Int32 nLabelSeqLen
= -1; // used to see if labels are always used or not and have
1081 // the expected size of 1 (i.e. if FirstCellAsLabel can
1083 // -1: don't know yet, 0: not used, 1: always a single labe cell, ...
1084 // -2: neither/failed
1085 for (sal_Int32 nDS1
= 0; nDS1
< nNumDS_LDS
; ++nDS1
)
1087 uno::Reference
< chart2::data::XLabeledDataSequence
> xLabeledDataSequence( pDS_LDS
[nDS1
] );
1088 if( !xLabeledDataSequence
.is() )
1090 OSL_FAIL("got NULL for XLabeledDataSequence from Data source");
1093 const uno::Reference
< chart2::data::XDataSequence
> xCurLabel( xLabeledDataSequence
->getLabel(), uno::UNO_QUERY
);
1094 const uno::Reference
< chart2::data::XDataSequence
> xCurValues( xLabeledDataSequence
->getValues(), uno::UNO_QUERY
);
1096 // get sequence lengths for label and values.
1098 sal_Int32 nCurLabelSeqLen
= -1;
1099 sal_Int32 nCurValuesSeqLen
= -1;
1101 nCurLabelSeqLen
= xCurLabel
->getData().getLength();
1102 if (xCurValues
.is())
1103 nCurValuesSeqLen
= xCurValues
->getData().getLength();
1105 // check for consistent use of 'first cell as label'
1106 if (nLabelSeqLen
== -1) // set initial value to compare with below further on
1107 nLabelSeqLen
= nCurLabelSeqLen
;
1108 if (nLabelSeqLen
!= nCurLabelSeqLen
)
1109 nLabelSeqLen
= -2; // failed / no consistent use of label cells
1111 // get table and cell names for label and values data sequences
1112 // (start and end cell will be sorted, i.e. start cell <= end cell)
1113 String aLabelTblName
, aLabelStartCell
, aLabelEndCell
;
1114 String aValuesTblName
, aValuesStartCell
, aValuesEndCell
;
1115 String aLabelRange
, aValuesRange
;
1117 aLabelRange
= xCurLabel
->getSourceRangeRepresentation();
1118 if (xCurValues
.is())
1119 aValuesRange
= xCurValues
->getSourceRangeRepresentation();
1120 if ((aLabelRange
.Len() && !GetTableAndCellsFromRangeRep( aLabelRange
,
1121 aLabelTblName
, aLabelStartCell
, aLabelEndCell
)) ||
1122 !GetTableAndCellsFromRangeRep( aValuesRange
,
1123 aValuesTblName
, aValuesStartCell
, aValuesEndCell
))
1125 return aResult
; // failed -> return empty property sequence
1128 // make sure all sequences use the same table
1129 if (!aTableName
.Len())
1130 aTableName
= aValuesTblName
; // get initial value to compare with
1131 if (!aTableName
.Len() ||
1132 aTableName
!= aValuesTblName
||
1133 (aLabelTblName
.Len() && aTableName
!= aLabelTblName
))
1135 return aResult
; // failed -> return empty property sequence
1139 // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting
1140 // first and last cell used in both sequences
1142 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1143 String
aCell( aLabelStartCell
.Len() ? aLabelStartCell
: aValuesStartCell
);
1144 OSL_ENSURE( aCell
.Len() , "start cell missing?" );
1145 sw_GetCellPosition( aCell
, nFirstCol
, nFirstRow
);
1146 sw_GetCellPosition( aValuesEndCell
, nLastCol
, nLastRow
);
1148 sal_Int16 nDirection
= -1; // -1: not yet set, 0: columns, 1: rows, -2: failed
1149 if (nFirstCol
== nLastCol
&& nFirstRow
== nLastRow
) // a single cell...
1151 OSL_ENSURE( nCurLabelSeqLen
== 0 && nCurValuesSeqLen
== 1,
1152 "trying to determine 'DataRowSource': something's fishy... should have been a single cell");
1153 (void)nCurValuesSeqLen
;
1154 nDirection
= 0; // default direction for a single cell should be 'columns'
1156 else // more than one cell is availabale (in values and label together!)
1158 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1160 else if (nFirstCol
!= nLastCol
&& nFirstRow
== nLastRow
)
1164 OSL_FAIL( "trying to determine 'DataRowSource': unexpected case found" );
1168 // check for consistent direction of data source
1169 if (nDtaSrcIsColumns
== -1) // set initial value to compare with below
1170 nDtaSrcIsColumns
= nDirection
;
1171 if (nDtaSrcIsColumns
!= nDirection
)
1173 nDtaSrcIsColumns
= -2; // failed
1177 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1179 // build data to obtain 'SequenceMapping' later on
1181 OSL_ENSURE( nDtaSrcIsColumns
== 0 || /* rows */
1182 nDtaSrcIsColumns
== 1, /* columns */
1183 "unexpected value for 'nDtaSrcIsColumns'" );
1184 pSequenceMapping
[nDS1
] = nDtaSrcIsColumns
? nFirstCol
: nFirstRow
;
1187 // build data used to determine 'CellRangeRepresentation' later on
1189 GetTableByName( *pDoc
, aTableName
, &pTableFmt
, &pTable
);
1190 if (!pTable
|| pTable
->IsTblComplex())
1191 return aResult
; // failed -> return empty property sequence
1192 nTableRows
= pTable
->GetTabLines().size();
1193 nTableCols
= pTable
->GetTabLines().front()->GetTabBoxes().size();
1194 aMap
.resize( nTableRows
);
1195 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1196 aMap
[i
].resize( nTableCols
);
1198 if (aLabelStartCell
.Len() && aLabelEndCell
.Len())
1200 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1201 sw_GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1202 sw_GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1203 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1204 nStartCol
< 0 || nEndCol
>= nTableCols
)
1206 return aResult
; // failed -> return empty property sequence
1208 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1210 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1212 sal_Char
&rChar
= aMap
[i
][k
];
1213 if (rChar
== '\0') // check for overlapping values and/or labels
1216 return aResult
; // failed -> return empty property sequence
1220 if (aValuesStartCell
.Len() && aValuesEndCell
.Len())
1222 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1223 sw_GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1224 sw_GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1225 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1226 nStartCol
< 0 || nEndCol
>= nTableCols
)
1228 return aResult
; // failed -> return empty property sequence
1230 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1232 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1234 sal_Char
&rChar
= aMap
[i
][k
];
1235 if (rChar
== '\0') // check for overlapping values and/or labels
1238 return aResult
; // failed -> return empty property sequence
1244 #if OSL_DEBUG_LEVEL > 0
1245 // do some extra sanity checking that the length of the sequences
1246 // matches their range representation
1248 sal_Int32 nStartRow
= -1, nStartCol
= -1, nEndRow
= -1, nEndCol
= -1;
1251 sw_GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1252 sw_GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1253 OSL_ENSURE( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurLabel
->getData().getLength()) ||
1254 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurLabel
->getData().getLength()),
1255 "label sequence length does not match range representation!" );
1257 if (xCurValues
.is())
1259 sw_GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1260 sw_GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1261 OSL_ENSURE( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurValues
->getData().getLength()) ||
1262 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurValues
->getData().getLength()),
1263 "value sequence length does not match range representation!" );
1270 // build value for 'CellRangeRepresentation'
1272 String
aCellRangeBase( aTableName
);
1273 aCellRangeBase
+= '.';
1275 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1277 for (sal_Int32 k
= 0; k
< nTableCols
; ++k
)
1279 if (aMap
[i
][k
] != '\0') // top-left cell of a sub-range found
1281 // find rectangular sub-range to use
1282 sal_Int32 nRowIndex1
= i
; // row index
1283 sal_Int32 nColIndex1
= k
; // column index
1284 sal_Int32 nRowSubLen
= 0;
1285 sal_Int32 nColSubLen
= 0;
1286 while (nRowIndex1
< nTableRows
&& aMap
[nRowIndex1
++][k
] != '\0')
1288 // be aware of shifted sequences!
1289 // (according to the checks done prior the length should be ok)
1290 while (nColIndex1
< nTableCols
&& aMap
[i
][nColIndex1
] != '\0'
1291 && aMap
[i
+ nRowSubLen
-1][nColIndex1
] != '\0')
1296 String
aStartCell( sw_GetCellName( k
, i
) );
1297 String
aEndCell( sw_GetCellName( k
+ nColSubLen
- 1, i
+ nRowSubLen
- 1) );
1298 aCurRange
= aCellRangeBase
;
1299 aCurRange
+= aStartCell
;
1301 aCurRange
+= aEndCell
;
1302 if (aCellRanges
.Len())
1304 aCellRanges
+= aCurRange
;
1306 // clear already found sub-range from map
1307 for (sal_Int32 nRowIndex2
= 0; nRowIndex2
< nRowSubLen
; ++nRowIndex2
)
1308 for (sal_Int32 nColumnIndex2
= 0; nColumnIndex2
< nColSubLen
; ++nColumnIndex2
)
1309 aMap
[i
+ nRowIndex2
][k
+ nColumnIndex2
] = '\0';
1313 // to be nice to the user we now sort the cell ranges according to
1314 // rows or columns depending on the direction used in the data source
1315 uno::Sequence
< OUString
> aSortedRanges
;
1316 GetSubranges( aCellRanges
, aSortedRanges
, sal_False
/*sub ranges should already be normalized*/ );
1317 SortSubranges( aSortedRanges
, (nDtaSrcIsColumns
== 1) );
1318 sal_Int32 nSortedRanges
= aSortedRanges
.getLength();
1319 const OUString
*pSortedRanges
= aSortedRanges
.getConstArray();
1320 OUString aSortedCellRanges
;
1321 for (sal_Int32 i
= 0; i
< nSortedRanges
; ++i
)
1323 if (!aSortedCellRanges
.isEmpty())
1324 aSortedCellRanges
+= OUString::valueOf( (sal_Unicode
) ';');
1325 aSortedCellRanges
+= pSortedRanges
[i
];
1329 // build value for 'SequenceMapping'
1331 uno::Sequence
< sal_Int32
> aSortedMapping( aSequenceMapping
);
1332 sal_Int32
*pSortedMapping
= aSortedMapping
.getArray();
1333 std::sort( pSortedMapping
, pSortedMapping
+ aSortedMapping
.getLength() );
1334 OSL_ENSURE( aSortedMapping
.getLength() == nNumDS_LDS
, "unexpected size of sequence" );
1335 bool bNeedSequenceMapping
= false;
1336 for (sal_Int32 i
= 0; i
< nNumDS_LDS
; ++i
)
1338 sal_Int32
*pIt
= std::find( pSortedMapping
, pSortedMapping
+ nNumDS_LDS
,
1339 pSequenceMapping
[i
] );
1340 OSL_ENSURE( pIt
, "index not found" );
1342 return aResult
; // failed -> return empty property sequence
1343 pSequenceMapping
[i
] = pIt
- pSortedMapping
;
1345 if (i
!= pSequenceMapping
[i
])
1346 bNeedSequenceMapping
= true;
1349 // check if 'SequenceMapping' is actually not required...
1350 // (don't write unnecessary properties to the XML file)
1351 if (!bNeedSequenceMapping
)
1352 aSequenceMapping
.realloc(0);
1355 // build resulting properties
1357 OSL_ENSURE(nLabelSeqLen
>= 0 || nLabelSeqLen
== -2 /*not used*/,
1358 "unexpected value for 'nLabelSeqLen'" );
1359 sal_Bool bFirstCellIsLabel
= sal_False
; // default value if 'nLabelSeqLen' could not properly determined
1360 if (nLabelSeqLen
> 0) // == 0 means no label sequence in use
1361 bFirstCellIsLabel
= sal_True
;
1363 OSL_ENSURE( !aSortedCellRanges
.isEmpty(), "CellRangeRepresentation missing" );
1364 OUString
aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges
) );
1367 sal_Int32 nProps
= 0;
1368 aResult
[nProps
].Name
= "FirstCellAsLabel";
1369 aResult
[nProps
++].Value
<<= bFirstCellIsLabel
;
1370 aResult
[nProps
].Name
= "CellRangeRepresentation";
1371 aResult
[nProps
++].Value
<<= aSortedCellRanges
;
1372 if (!aBrokenCellRangeForExport
.isEmpty())
1374 aResult
[nProps
].Name
= "BrokenCellRangeForExport";
1375 aResult
[nProps
++].Value
<<= aBrokenCellRangeForExport
;
1377 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1379 chart::ChartDataRowSource eDataRowSource
= (nDtaSrcIsColumns
== 1) ?
1380 chart::ChartDataRowSource_COLUMNS
: chart::ChartDataRowSource_ROWS
;
1381 aResult
[nProps
].Name
= "DataRowSource";
1382 aResult
[nProps
++].Value
<<= eDataRowSource
;
1384 if (aSequenceMapping
.getLength() != 0)
1386 aResult
[nProps
].Name
= "SequenceMapping";
1387 aResult
[nProps
++].Value
<<= aSequenceMapping
;
1390 aResult
.realloc( nProps
);
1395 uno::Reference
< chart2::data::XDataSequence
> SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation(
1396 const OUString
& rRangeRepresentation
, sal_Bool bTestOnly
)
1397 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1400 throw lang::DisposedException();
1402 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
1403 SwUnoCrsr
*pUnoCrsr
= 0; // pointer to new created cursor spanning the cell range
1404 GetFormatAndCreateCursorFromRangeRep( pDoc
, rRangeRepresentation
,
1405 &pTblFmt
, &pUnoCrsr
);
1406 if (!pTblFmt
|| !pUnoCrsr
)
1407 throw lang::IllegalArgumentException();
1409 // check that cursors point and mark are in a single row or column.
1410 String
aCellRange( GetCellRangeName( *pTblFmt
, *pUnoCrsr
) );
1411 SwRangeDescriptor aDesc
;
1412 FillRangeDescriptor( aDesc
, aCellRange
);
1413 if (aDesc
.nTop
!= aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1414 throw lang::IllegalArgumentException();
1416 OSL_ENSURE( pTblFmt
&& pUnoCrsr
, "table format or cursor missing" );
1417 uno::Reference
< chart2::data::XDataSequence
> xDataSeq
;
1419 xDataSeq
= new SwChartDataSequence( *this, *pTblFmt
, pUnoCrsr
);
1424 sal_Bool SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentationPossible(
1425 const OUString
& rRangeRepresentation
)
1426 throw (uno::RuntimeException
)
1428 SolarMutexGuard aGuard
;
1430 sal_Bool bPossible
= sal_True
;
1433 Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
, sal_True
);
1435 catch (lang::IllegalArgumentException
&)
1437 bPossible
= sal_False
;
1443 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentation(
1444 const OUString
& rRangeRepresentation
)
1445 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1447 SolarMutexGuard aGuard
;
1448 return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
);
1451 uno::Reference
< sheet::XRangeSelection
> SAL_CALL
SwChartDataProvider::getRangeSelection( )
1452 throw (uno::RuntimeException
)
1454 // note: it is no error to return nothing here
1455 return uno::Reference
< sheet::XRangeSelection
>();
1458 void SAL_CALL
SwChartDataProvider::dispose( )
1459 throw (uno::RuntimeException
)
1461 bool bMustDispose( false );
1463 osl::MutexGuard
aGuard( GetChartMutex() );
1464 bMustDispose
= !bDisposed
;
1466 bDisposed
= sal_True
;
1470 // dispose all data-sequences
1471 Map_Set_DataSequenceRef_t::iterator
aIt( aDataSequences
.begin() );
1472 while (aIt
!= aDataSequences
.end())
1474 DisposeAllDataSequences( (*aIt
).first
);
1477 // release all references to data-sequences
1478 aDataSequences
.clear();
1480 // require listeners to release references to this object
1481 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XDataSequence
* >(this) );
1482 aEvtListeners
.disposeAndClear( aEvtObj
);
1486 void SAL_CALL
SwChartDataProvider::addEventListener(
1487 const uno::Reference
< lang::XEventListener
>& rxListener
)
1488 throw (uno::RuntimeException
)
1490 osl::MutexGuard
aGuard( GetChartMutex() );
1491 if (!bDisposed
&& rxListener
.is())
1492 aEvtListeners
.addInterface( rxListener
);
1495 void SAL_CALL
SwChartDataProvider::removeEventListener(
1496 const uno::Reference
< lang::XEventListener
>& rxListener
)
1497 throw (uno::RuntimeException
)
1499 osl::MutexGuard
aGuard( GetChartMutex() );
1500 if (!bDisposed
&& rxListener
.is())
1501 aEvtListeners
.removeInterface( rxListener
);
1504 OUString SAL_CALL
SwChartDataProvider::getImplementationName( )
1505 throw (uno::RuntimeException
)
1507 return OUString("SwChartDataProvider");
1510 sal_Bool SAL_CALL
SwChartDataProvider::supportsService(
1511 const OUString
& rServiceName
)
1512 throw (uno::RuntimeException
)
1514 SolarMutexGuard aGuard
;
1515 return rServiceName
== SN_DATA_PROVIDER
;
1518 uno::Sequence
< OUString
> SAL_CALL
SwChartDataProvider::getSupportedServiceNames( )
1519 throw (uno::RuntimeException
)
1521 SolarMutexGuard aGuard
;
1522 uno::Sequence
< OUString
> aRes(1);
1523 aRes
.getArray()[0] = SN_DATA_PROVIDER
;
1527 void SwChartDataProvider::Modify( const SfxPoolItem
* pOld
, const SfxPoolItem
*pNew
)
1529 // actually this function should be superfluous (need to check later)
1530 ClientModify(this, pOld
, pNew
);
1533 void SwChartDataProvider::AddDataSequence( const SwTable
&rTable
, uno::Reference
< chart2::data::XDataSequence
> &rxDataSequence
)
1535 aDataSequences
[ &rTable
].insert( rxDataSequence
);
1538 void SwChartDataProvider::RemoveDataSequence( const SwTable
&rTable
, uno::Reference
< chart2::data::XDataSequence
> &rxDataSequence
)
1540 aDataSequences
[ &rTable
].erase( rxDataSequence
);
1543 void SwChartDataProvider::InvalidateTable( const SwTable
*pTable
)
1545 OSL_ENSURE( pTable
, "table pointer is NULL" );
1549 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1551 const Set_DataSequenceRef_t
&rSet
= aDataSequences
[ pTable
];
1552 Set_DataSequenceRef_t::const_iterator
aIt( rSet
.begin() );
1553 while (aIt
!= rSet
.end())
1555 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1556 uno::Reference
< util::XModifiable
> xRef( xTemp
, uno::UNO_QUERY
);
1559 // mark the sequence as 'dirty' and notify listeners
1560 xRef
->setModified( sal_True
);
1567 sal_Bool
SwChartDataProvider::DeleteBox( const SwTable
*pTable
, const SwTableBox
&rBox
)
1569 sal_Bool bRes
= sal_False
;
1570 OSL_ENSURE( pTable
, "table pointer is NULL" );
1574 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1576 Set_DataSequenceRef_t
&rSet
= aDataSequences
[ pTable
];
1578 // iterate over all data-sequences for that table...
1579 Set_DataSequenceRef_t::iterator
aIt( rSet
.begin() );
1580 Set_DataSequenceRef_t::iterator
aEndIt( rSet
.end() );
1581 Set_DataSequenceRef_t::iterator aDelIt
; // iterator used for deletion when appropriate
1582 while (aIt
!= aEndIt
)
1584 SwChartDataSequence
*pDataSeq
= 0;
1585 sal_Bool bNowEmpty
= sal_False
;
1586 sal_Bool bSeqDisposed
= sal_False
;
1588 // check if weak reference is still valid...
1589 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1590 uno::Reference
< chart2::data::XDataSequence
> xRef( xTemp
, uno::UNO_QUERY
);
1593 // then delete that table box (check if implementation cursor needs to be adjusted)
1594 pDataSeq
= static_cast< SwChartDataSequence
* >( xRef
.get() );
1599 bNowEmpty
= pDataSeq
->DeleteBox( rBox
);
1601 catch (const lang::DisposedException
&)
1603 bNowEmpty
= sal_True
;
1604 bSeqDisposed
= sal_True
;
1615 rSet
.erase( aDelIt
);
1616 if (pDataSeq
&& !bSeqDisposed
)
1617 pDataSeq
->dispose(); // the current way to tell chart that sth. got removed
1624 void SwChartDataProvider::DisposeAllDataSequences( const SwTable
*pTable
)
1626 OSL_ENSURE( pTable
, "table pointer is NULL" );
1630 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1632 //! make a copy of the STL container!
1633 //! This is necessary since calling 'dispose' will implicitly remove an element
1634 //! of the original container, and thus any iterator in the original container
1635 //! would become invalid.
1636 const Set_DataSequenceRef_t
aSet( aDataSequences
[ pTable
] );
1638 Set_DataSequenceRef_t::const_iterator
aIt( aSet
.begin() );
1639 Set_DataSequenceRef_t::const_iterator
aEndIt( aSet
.end() );
1640 while (aIt
!= aEndIt
)
1642 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1643 uno::Reference
< lang::XComponent
> xRef( xTemp
, uno::UNO_QUERY
);
1653 ////////////////////////////////////////
1654 // SwChartDataProvider::AddRowCols tries to notify charts of added columns
1655 // or rows and extends the value sequence respectively (if possible).
1656 // If those can be added to the end of existing value data-sequences those
1657 // sequences get mofdified accordingly and will send a modification
1658 // notification (calling 'setModified').
1660 // Since this function is a work-around for non existent Writer core functionality
1661 // (no arbitrary multi-selection in tables that can be used to define a
1662 // data-sequence) this function will be somewhat unreliable.
1663 // For example we will only try to adapt value sequences. For this we assume
1664 // that a sequence of length 1 is a label sequence and those with length >= 2
1665 // we presume to be value sequences. Also new cells can only be added in the
1666 // direction the value sequence is already pointing (rows / cols) and at the
1667 // start or end of the values data-sequence.
1668 // Nothing needs to be done if the new cells are in between the table cursors
1669 // point and mark since data-sequence are considered to consist of all cells
1671 // New rows/cols need to be added already to the table before calling
1674 void SwChartDataProvider::AddRowCols(
1675 const SwTable
&rTable
,
1676 const SwSelBoxes
& rBoxes
,
1677 sal_uInt16 nLines
, sal_Bool bBehind
)
1679 if (rTable
.IsTblComplex())
1682 const size_t nBoxes
= rBoxes
.size();
1683 if (nBoxes
< 1 || nLines
< 1)
1686 SwTableBox
* pFirstBox
= rBoxes
[0];
1687 SwTableBox
* pLastBox
= rBoxes
.back();
1689 if (pFirstBox
&& pLastBox
)
1691 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1692 sw_GetCellPosition( pFirstBox
->GetName(), nFirstCol
, nFirstRow
);
1693 sw_GetCellPosition( pLastBox
->GetName(), nLastCol
, nLastRow
);
1695 bool bAddCols
= false; // default; also to be used if nBoxes == 1 :-/
1696 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1698 if (nFirstCol
== nLastCol
|| nFirstRow
== nLastRow
)
1700 //get range of indices in col/rows for new cells
1701 sal_Int32 nFirstNewCol
= nFirstCol
;
1702 sal_Int32 nFirstNewRow
= bBehind
? nFirstRow
+ 1 : nFirstRow
- nLines
;
1705 OSL_ENSURE( nFirstCol
== nLastCol
, "column indices seem broken" );
1706 nFirstNewCol
= bBehind
? nFirstCol
+ 1 : nFirstCol
- nLines
;
1707 nFirstNewRow
= nFirstRow
;
1710 // iterate over all data-sequences for the table
1711 const Set_DataSequenceRef_t
&rSet
= aDataSequences
[ &rTable
];
1712 Set_DataSequenceRef_t::const_iterator
aIt( rSet
.begin() );
1713 while (aIt
!= rSet
.end())
1715 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1716 uno::Reference
< chart2::data::XTextualDataSequence
> xRef( xTemp
, uno::UNO_QUERY
);
1719 const sal_Int32 nLen
= xRef
->getTextualData().getLength();
1720 if (nLen
> 1) // value data-sequence ?
1722 SwChartDataSequence
*pDataSeq
= 0;
1723 uno::Reference
< lang::XUnoTunnel
> xTunnel( xRef
, uno::UNO_QUERY
);
1726 pDataSeq
= reinterpret_cast< SwChartDataSequence
* >(
1727 sal::static_int_cast
< sal_IntPtr
>( xTunnel
->getSomething( SwChartDataSequence::getUnoTunnelId() )));
1731 SwRangeDescriptor aDesc
;
1732 pDataSeq
->FillRangeDesc( aDesc
);
1734 chart::ChartDataRowSource eDRSource
= chart::ChartDataRowSource_COLUMNS
;
1735 if (aDesc
.nTop
== aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1736 eDRSource
= chart::ChartDataRowSource_ROWS
;
1738 if (!bAddCols
&& eDRSource
== chart::ChartDataRowSource_COLUMNS
)
1740 // add rows: extend affected columns by newly added row cells
1741 pDataSeq
->ExtendTo( true, nFirstNewRow
, nLines
);
1743 else if (bAddCols
&& eDRSource
== chart::ChartDataRowSource_ROWS
)
1745 // add cols: extend affected rows by newly added column cells
1746 pDataSeq
->ExtendTo( false, nFirstNewCol
, nLines
);
1759 // XRangeXMLConversion ---------------------------------------------------
1760 OUString SAL_CALL
SwChartDataProvider::convertRangeToXML( const OUString
& rRangeRepresentation
)
1761 throw ( uno::RuntimeException
, lang::IllegalArgumentException
)
1763 SolarMutexGuard aGuard
;
1765 throw lang::DisposedException();
1768 String
aRangeRepresentation( rRangeRepresentation
);
1770 // multiple ranges are delimeted by a ';' like in
1771 // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges!
1772 xub_StrLen nNumRanges
= comphelper::string::getTokenCount(aRangeRepresentation
, ';');
1773 SwTable
* pFirstFoundTable
= 0; // to check that only one table will be used
1774 for (sal_uInt16 i
= 0; i
< nNumRanges
; ++i
)
1776 String
aRange( aRangeRepresentation
.GetToken(i
, ';') );
1777 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
1778 GetFormatAndCreateCursorFromRangeRep( pDoc
, aRange
, &pTblFmt
, NULL
);
1780 throw lang::IllegalArgumentException();
1781 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
1782 if (pTable
->IsTblComplex())
1783 throw uno::RuntimeException();
1785 // check that there is only one table used in all ranges
1786 if (!pFirstFoundTable
)
1787 pFirstFoundTable
= pTable
;
1788 if (pTable
!= pFirstFoundTable
)
1789 throw lang::IllegalArgumentException();
1794 if (!GetTableAndCellsFromRangeRep( aRange
, aTblName
, aStartCell
, aEndCell
))
1795 throw lang::IllegalArgumentException();
1797 sal_Int32 nCol
, nRow
;
1798 sw_GetCellPosition( aStartCell
, nCol
, nRow
);
1799 if (nCol
< 0 || nRow
< 0)
1800 throw uno::RuntimeException();
1802 //!! following objects/functions are implemented in XMLRangeHelper.?xx
1803 //!! which is a copy of the respective file from chart2 !!
1804 XMLRangeHelper::CellRange aCellRange
;
1805 aCellRange
.aTableName
= aTblName
;
1806 aCellRange
.aUpperLeft
.nColumn
= nCol
;
1807 aCellRange
.aUpperLeft
.nRow
= nRow
;
1808 aCellRange
.aUpperLeft
.bIsEmpty
= false;
1809 if (aStartCell
!= aEndCell
&& aEndCell
.Len() != 0)
1811 sw_GetCellPosition( aEndCell
, nCol
, nRow
);
1812 if (nCol
< 0 || nRow
< 0)
1813 throw uno::RuntimeException();
1815 aCellRange
.aLowerRight
.nColumn
= nCol
;
1816 aCellRange
.aLowerRight
.nRow
= nRow
;
1817 aCellRange
.aLowerRight
.bIsEmpty
= false;
1819 String
aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange
) );
1820 if (aRes
.Len()) // in case of multiple ranges add delimeter
1821 aRes
.AppendAscii( " " );
1828 OUString SAL_CALL
SwChartDataProvider::convertRangeFromXML( const OUString
& rXMLRange
)
1829 throw ( uno::RuntimeException
, lang::IllegalArgumentException
)
1831 SolarMutexGuard aGuard
;
1833 throw lang::DisposedException();
1836 String
aXMLRange( rXMLRange
);
1838 // multiple ranges are delimeted by a ' ' like in
1839 // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges!
1840 xub_StrLen nNumRanges
= comphelper::string::getTokenCount(aXMLRange
, ' ');
1841 OUString aFirstFoundTable
; // to check that only one table will be used
1842 for (sal_uInt16 i
= 0; i
< nNumRanges
; ++i
)
1844 String
aRange( aXMLRange
.GetToken(i
, ' ') );
1846 //!! following objects and function are implemented in XMLRangeHelper.?xx
1847 //!! which is a copy of the respective file from chart2 !!
1848 XMLRangeHelper::CellRange
aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange
));
1850 // check that there is only one table used in all ranges
1851 if (aFirstFoundTable
.isEmpty())
1852 aFirstFoundTable
= aCellRange
.aTableName
;
1853 if (aCellRange
.aTableName
!= aFirstFoundTable
)
1854 throw lang::IllegalArgumentException();
1856 OUString
aTmp( aCellRange
.aTableName
);
1857 aTmp
+= OUString::valueOf((sal_Unicode
) '.');
1858 aTmp
+= sw_GetCellName( aCellRange
.aUpperLeft
.nColumn
,
1859 aCellRange
.aUpperLeft
.nRow
);
1860 // does cell range consist of more than a single cell?
1861 if (!aCellRange
.aLowerRight
.bIsEmpty
)
1863 aTmp
+= OUString::valueOf((sal_Unicode
) ':');
1864 aTmp
+= sw_GetCellName( aCellRange
.aLowerRight
.nColumn
,
1865 aCellRange
.aLowerRight
.nRow
);
1868 if (aRes
.Len()) // in case of multiple ranges add delimeter
1869 aRes
.AppendAscii( ";" );
1870 aRes
+= String(aTmp
);
1876 SwChartDataSource::SwChartDataSource(
1877 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > &rLDS
) :
1882 SwChartDataSource::~SwChartDataSource()
1886 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > SAL_CALL
SwChartDataSource::getDataSequences( )
1887 throw (uno::RuntimeException
)
1889 SolarMutexGuard aGuard
;
1893 OUString SAL_CALL
SwChartDataSource::getImplementationName( )
1894 throw (uno::RuntimeException
)
1896 SolarMutexGuard aGuard
;
1897 return OUString("SwChartDataSource");
1900 sal_Bool SAL_CALL
SwChartDataSource::supportsService(
1901 const OUString
& rServiceName
)
1902 throw (uno::RuntimeException
)
1904 SolarMutexGuard aGuard
;
1905 return rServiceName
== SN_DATA_SOURCE
;
1908 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSource::getSupportedServiceNames( )
1909 throw (uno::RuntimeException
)
1911 SolarMutexGuard aGuard
;
1912 uno::Sequence
< OUString
> aRes(1);
1913 aRes
.getArray()[0] = SN_DATA_SOURCE
;
1917 SwChartDataSequence::SwChartDataSequence(
1918 SwChartDataProvider
&rProvider
,
1920 SwUnoCrsr
*pTableCursor
) :
1921 SwClient( &rTblFmt
),
1922 aEvtListeners( GetChartMutex() ),
1923 aModifyListeners( GetChartMutex() ),
1924 aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT
) ),
1925 aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT
) ),
1926 xDataProvider( &rProvider
),
1927 pDataProvider( &rProvider
),
1928 pTblCrsr( pTableCursor
),
1929 aCursorDepend( this, pTableCursor
),
1930 _pPropSet( aSwMapProvider
.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE
) )
1932 bDisposed
= sal_False
;
1937 const SwTable
* pTable
= SwTable::FindTable( &rTblFmt
);
1940 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
1941 pDataProvider
->AddDataSequence( *pTable
, xRef
);
1942 pDataProvider
->addEventListener( dynamic_cast< lang::XEventListener
* >(this) );
1945 OSL_FAIL( "table missing" );
1948 catch (uno::RuntimeException
&)
1952 catch (uno::Exception
&)
1957 #if OSL_DEBUG_LEVEL > 0
1958 // check if it can properly convert into a SwUnoTableCrsr
1959 // which is required for some functions
1960 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
1961 OSL_ENSURE(pUnoTblCrsr
, "SwChartDataSequence: cursor not SwUnoTableCrsr");
1966 SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence
&rObj
) :
1967 SwChartDataSequenceBaseClass(),
1968 SwClient( rObj
.GetFrmFmt() ),
1969 aEvtListeners( GetChartMutex() ),
1970 aModifyListeners( GetChartMutex() ),
1971 aRole( rObj
.aRole
),
1972 aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT
) ),
1973 aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT
) ),
1974 xDataProvider( rObj
.pDataProvider
),
1975 pDataProvider( rObj
.pDataProvider
),
1976 pTblCrsr( rObj
.pTblCrsr
->Clone() ),
1977 aCursorDepend( this, pTblCrsr
),
1978 _pPropSet( rObj
._pPropSet
)
1980 bDisposed
= sal_False
;
1985 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
1988 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
1989 pDataProvider
->AddDataSequence( *pTable
, xRef
);
1990 pDataProvider
->addEventListener( dynamic_cast< lang::XEventListener
* >(this) );
1993 OSL_FAIL( "table missing" );
1996 catch (uno::RuntimeException
&)
2000 catch (uno::Exception
&)
2005 #if OSL_DEBUG_LEVEL > 0
2006 // check if it can properly convert into a SwUnoTableCrsr
2007 // which is required for some functions
2008 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
2009 OSL_ENSURE(pUnoTblCrsr
, "SwChartDataSequence: cursor not SwUnoTableCrsr");
2014 SwChartDataSequence::~SwChartDataSequence()
2016 // since the data-provider holds only weak references to the data-sequence
2017 // there should be no need here to release them explicitly...
2024 class theSwChartDataSequenceUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theSwChartDataSequenceUnoTunnelId
> {};
2027 const uno::Sequence
< sal_Int8
> & SwChartDataSequence::getUnoTunnelId()
2029 return theSwChartDataSequenceUnoTunnelId::get().getSeq();
2032 sal_Int64 SAL_CALL
SwChartDataSequence::getSomething( const uno::Sequence
< sal_Int8
> &rId
)
2033 throw(uno::RuntimeException
)
2035 if( rId
.getLength() == 16
2036 && 0 == memcmp( getUnoTunnelId().getConstArray(),
2037 rId
.getConstArray(), 16 ) )
2039 return sal::static_int_cast
< sal_Int64
>( reinterpret_cast< sal_IntPtr
>(this) );
2044 uno::Sequence
< uno::Any
> SAL_CALL
SwChartDataSequence::getData( )
2045 throw (uno::RuntimeException
)
2047 SolarMutexGuard aGuard
;
2049 throw lang::DisposedException();
2051 uno::Sequence
< uno::Any
> aRes
;
2052 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2055 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2056 if(!pTable
->IsTblComplex())
2058 SwRangeDescriptor aDesc
;
2059 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2061 //!! make copy of pTblCrsr (SwUnoCrsr )
2062 // keep original cursor and make copy of it that gets handed
2063 // over to the SwXCellRange object which takes ownership and
2064 // thus will destroy the copy later.
2065 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2066 aRange
.GetDataSequence( &aRes
, 0, 0 );
2073 OUString SAL_CALL
SwChartDataSequence::getSourceRangeRepresentation( )
2074 throw (uno::RuntimeException
)
2076 SolarMutexGuard aGuard
;
2078 throw lang::DisposedException();
2081 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2084 aRes
= pTblFmt
->GetName();
2085 String
aCellRange( GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2086 OSL_ENSURE( aCellRange
.Len() != 0, "failed to get cell range" );
2087 aRes
+= (sal_Unicode
) '.';
2093 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::generateLabel(
2094 chart2::data::LabelOrigin eLabelOrigin
)
2095 throw (uno::RuntimeException
)
2097 SolarMutexGuard aGuard
;
2099 throw lang::DisposedException();
2101 uno::Sequence
< OUString
> aLabels
;
2104 SwRangeDescriptor aDesc
;
2106 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2107 SwTable
* pTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
2108 if (!pTblFmt
|| !pTable
|| pTable
->IsTblComplex())
2109 throw uno::RuntimeException();
2112 String
aCellRange( GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2113 OSL_ENSURE( aCellRange
.Len() != 0, "failed to get cell range" );
2114 bOk
= FillRangeDescriptor( aDesc
, aCellRange
);
2115 OSL_ENSURE( bOk
, "falied to get SwRangeDescriptor" );
2120 sal_Int32 nColSpan
= aDesc
.nRight
- aDesc
.nLeft
+ 1;
2121 sal_Int32 nRowSpan
= aDesc
.nBottom
- aDesc
.nTop
+ 1;
2122 OSL_ENSURE( nColSpan
== 1 || nRowSpan
== 1,
2123 "unexpected range of selected cells" );
2125 String aTxt
; // label text to be returned
2126 bool bReturnEmptyTxt
= false;
2127 bool bUseCol
= true;
2128 if (eLabelOrigin
== chart2::data::LabelOrigin_COLUMN
)
2130 else if (eLabelOrigin
== chart2::data::LabelOrigin_ROW
)
2132 else if (eLabelOrigin
== chart2::data::LabelOrigin_SHORT_SIDE
)
2134 bUseCol
= nColSpan
< nRowSpan
;
2135 bReturnEmptyTxt
= nColSpan
== nRowSpan
;
2137 else if (eLabelOrigin
== chart2::data::LabelOrigin_LONG_SIDE
)
2139 bUseCol
= nColSpan
> nRowSpan
;
2140 bReturnEmptyTxt
= nColSpan
== nRowSpan
;
2143 OSL_FAIL( "unexpected case" );
2146 // build label sequence
2148 sal_Int32 nSeqLen
= bUseCol
? nColSpan
: nRowSpan
;
2149 aLabels
.realloc( nSeqLen
);
2150 OUString
*pLabels
= aLabels
.getArray();
2151 for (sal_Int32 i
= 0; i
< nSeqLen
; ++i
)
2153 if (!bReturnEmptyTxt
)
2155 aTxt
= bUseCol
? aColLabelText
: aRowLabelText
;
2156 sal_Int32 nCol
= aDesc
.nLeft
;
2157 sal_Int32 nRow
= aDesc
.nTop
;
2162 String
aCellName( sw_GetCellName( nCol
, nRow
) );
2164 xub_StrLen nLen
= aCellName
.Len();
2167 const sal_Unicode
*pBuf
= aCellName
.GetBuffer();
2168 const sal_Unicode
*pEnd
= pBuf
+ nLen
;
2169 while (pBuf
< pEnd
&& !('0' <= *pBuf
&& *pBuf
<= '9'))
2171 // start of number found?
2172 if (pBuf
< pEnd
&& ('0' <= *pBuf
&& *pBuf
<= '9'))
2178 aRplc
= OUString("%COLUMNLETTER");
2179 aNew
= OUString(aCellName
.GetBuffer(), pBuf
- aCellName
.GetBuffer());
2183 aRplc
= OUString("%ROWNUMBER");
2184 aNew
= OUString(pBuf
, (aCellName
.GetBuffer() + nLen
) - pBuf
);
2186 xub_StrLen nPos
= aTxt
.Search( aRplc
);
2187 if (nPos
!= STRING_NOTFOUND
)
2188 aTxt
= aTxt
.Replace( nPos
, aRplc
.Len(), aNew
);
2200 ::sal_Int32 SAL_CALL
SwChartDataSequence::getNumberFormatKeyByIndex(
2201 ::sal_Int32
/*nIndex*/ )
2202 throw (lang::IndexOutOfBoundsException
,
2203 uno::RuntimeException
)
2208 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getTextualData( )
2209 throw (uno::RuntimeException
)
2211 SolarMutexGuard aGuard
;
2213 throw lang::DisposedException();
2215 uno::Sequence
< OUString
> aRes
;
2216 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2219 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2220 if(!pTable
->IsTblComplex())
2222 SwRangeDescriptor aDesc
;
2223 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2225 //!! make copy of pTblCrsr (SwUnoCrsr )
2226 // keep original cursor and make copy of it that gets handed
2227 // over to the SwXCellRange object which takes ownership and
2228 // thus will destroy the copy later.
2229 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2230 aRange
.GetDataSequence( 0, &aRes
, 0 );
2237 uno::Sequence
< double > SAL_CALL
SwChartDataSequence::getNumericalData( )
2238 throw (uno::RuntimeException
)
2240 SolarMutexGuard aGuard
;
2242 throw lang::DisposedException();
2244 uno::Sequence
< double > aRes
;
2245 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2248 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2249 if(!pTable
->IsTblComplex())
2251 SwRangeDescriptor aDesc
;
2252 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2254 //!! make copy of pTblCrsr (SwUnoCrsr )
2255 // keep original cursor and make copy of it that gets handed
2256 // over to the SwXCellRange object which takes ownership and
2257 // thus will destroy the copy later.
2258 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2260 // get numerical values and make an effort to return the
2261 // numerical value for text formatted cells
2262 aRange
.GetDataSequence( 0, 0, &aRes
, sal_True
);
2269 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartDataSequence::createClone( )
2270 throw (uno::RuntimeException
)
2272 SolarMutexGuard aGuard
;
2274 throw lang::DisposedException();
2275 return new SwChartDataSequence( *this );
2278 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
SwChartDataSequence::getPropertySetInfo( )
2279 throw (uno::RuntimeException
)
2281 SolarMutexGuard aGuard
;
2283 throw lang::DisposedException();
2285 static uno::Reference
< beans::XPropertySetInfo
> xRes
= _pPropSet
->getPropertySetInfo();
2289 void SAL_CALL
SwChartDataSequence::setPropertyValue(
2290 const OUString
& rPropertyName
,
2291 const uno::Any
& rValue
)
2292 throw (beans::UnknownPropertyException
, beans::PropertyVetoException
, lang::IllegalArgumentException
, lang::WrappedTargetException
, uno::RuntimeException
)
2294 SolarMutexGuard aGuard
;
2296 throw lang::DisposedException();
2298 if (rPropertyName
.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE
)))
2300 if ( !(rValue
>>= aRole
) )
2301 throw lang::IllegalArgumentException();
2304 throw beans::UnknownPropertyException();
2307 uno::Any SAL_CALL
SwChartDataSequence::getPropertyValue(
2308 const OUString
& rPropertyName
)
2309 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2311 SolarMutexGuard aGuard
;
2313 throw lang::DisposedException();
2316 if (rPropertyName
.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE
)))
2319 throw beans::UnknownPropertyException();
2324 void SAL_CALL
SwChartDataSequence::addPropertyChangeListener(
2325 const OUString
& /*rPropertyName*/,
2326 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2327 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2329 OSL_FAIL( "not implemented" );
2332 void SAL_CALL
SwChartDataSequence::removePropertyChangeListener(
2333 const OUString
& /*rPropertyName*/,
2334 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2335 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2337 OSL_FAIL( "not implemented" );
2340 void SAL_CALL
SwChartDataSequence::addVetoableChangeListener(
2341 const OUString
& /*rPropertyName*/,
2342 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2343 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2345 OSL_FAIL( "not implemented" );
2348 void SAL_CALL
SwChartDataSequence::removeVetoableChangeListener(
2349 const OUString
& /*rPropertyName*/,
2350 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2351 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2353 OSL_FAIL( "not implemented" );
2356 OUString SAL_CALL
SwChartDataSequence::getImplementationName( )
2357 throw (uno::RuntimeException
)
2359 return OUString("SwChartDataSequence");
2362 sal_Bool SAL_CALL
SwChartDataSequence::supportsService(
2363 const OUString
& rServiceName
)
2364 throw (uno::RuntimeException
)
2366 return rServiceName
== SN_DATA_SEQUENCE
;
2369 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getSupportedServiceNames( )
2370 throw (uno::RuntimeException
)
2372 SolarMutexGuard aGuard
;
2373 uno::Sequence
< OUString
> aRes(1);
2374 aRes
.getArray()[0] = SN_DATA_SEQUENCE
;
2378 void SwChartDataSequence::Modify( const SfxPoolItem
* pOld
, const SfxPoolItem
*pNew
)
2380 ClientModify(this, pOld
, pNew
);
2382 // table was deleted or cursor was deleted
2383 if(!GetRegisteredIn() || !aCursorDepend
.GetRegisteredIn())
2390 setModified( sal_True
);
2394 sal_Bool SAL_CALL
SwChartDataSequence::isModified( )
2395 throw (uno::RuntimeException
)
2397 SolarMutexGuard aGuard
;
2399 throw lang::DisposedException();
2404 void SAL_CALL
SwChartDataSequence::setModified(
2405 ::sal_Bool bModified
)
2406 throw (beans::PropertyVetoException
, uno::RuntimeException
)
2408 SolarMutexGuard aGuard
;
2410 throw lang::DisposedException();
2413 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2416 void SAL_CALL
SwChartDataSequence::addModifyListener(
2417 const uno::Reference
< util::XModifyListener
>& rxListener
)
2418 throw (uno::RuntimeException
)
2420 osl::MutexGuard
aGuard( GetChartMutex() );
2421 if (!bDisposed
&& rxListener
.is())
2422 aModifyListeners
.addInterface( rxListener
);
2425 void SAL_CALL
SwChartDataSequence::removeModifyListener(
2426 const uno::Reference
< util::XModifyListener
>& rxListener
)
2427 throw (uno::RuntimeException
)
2429 osl::MutexGuard
aGuard( GetChartMutex() );
2430 if (!bDisposed
&& rxListener
.is())
2431 aModifyListeners
.removeInterface( rxListener
);
2434 void SAL_CALL
SwChartDataSequence::disposing( const lang::EventObject
& rSource
)
2435 throw (uno::RuntimeException
)
2438 throw lang::DisposedException();
2439 if (rSource
.Source
== xDataProvider
)
2442 xDataProvider
.clear();
2446 void SAL_CALL
SwChartDataSequence::dispose( )
2447 throw (uno::RuntimeException
)
2449 bool bMustDispose( false );
2451 osl::MutexGuard
aGuard( GetChartMutex() );
2452 bMustDispose
= !bDisposed
;
2454 bDisposed
= sal_True
;
2458 bDisposed
= sal_True
;
2461 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2464 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
2465 pDataProvider
->RemoveDataSequence( *pTable
, xRef
);
2468 OSL_FAIL( "table missing" );
2471 //#i119653# The bug is crashed for an exception thrown by
2472 //SwCharDataSequence::setModified() because
2473 //the SwCharDataSequence object has been disposed.
2475 //Actually, the former design of SwClient will disconnect itself
2476 //from the notification list in its destructor.
2478 //But the SwCharDataSeqence won't be destructed but disposed in code
2479 //(the data member SwChartDataSequence::bDisposed will be set to
2480 //TRUE), the relationship between client and modification is not
2483 //So any notification from modify object will lead to said
2484 //exception threw out. Recorrect the logic of code in
2485 //SwChartDataSequence::Dispose(), release the relationship
2487 SwModify
* pLclRegisteredIn
= GetRegisteredInNonConst();
2488 if (pLclRegisteredIn
&& pLclRegisteredIn
->GetDepends())
2490 pLclRegisteredIn
->Remove(this);
2495 // require listeners to release references to this object
2496 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XDataSequence
* >(this) );
2497 aModifyListeners
.disposeAndClear( aEvtObj
);
2498 aEvtListeners
.disposeAndClear( aEvtObj
);
2502 void SAL_CALL
SwChartDataSequence::addEventListener(
2503 const uno::Reference
< lang::XEventListener
>& rxListener
)
2504 throw (uno::RuntimeException
)
2506 osl::MutexGuard
aGuard( GetChartMutex() );
2507 if (!bDisposed
&& rxListener
.is())
2508 aEvtListeners
.addInterface( rxListener
);
2511 void SAL_CALL
SwChartDataSequence::removeEventListener(
2512 const uno::Reference
< lang::XEventListener
>& rxListener
)
2513 throw (uno::RuntimeException
)
2515 osl::MutexGuard
aGuard( GetChartMutex() );
2516 if (!bDisposed
&& rxListener
.is())
2517 aEvtListeners
.removeInterface( rxListener
);
2520 sal_Bool
SwChartDataSequence::DeleteBox( const SwTableBox
&rBox
)
2523 throw lang::DisposedException();
2525 #if OSL_DEBUG_LEVEL > 1
2526 String
aBoxName( rBox
.GetName() );
2529 // to be set if the last box of the data-sequence was removed here
2530 sal_Bool bNowEmpty
= sal_False
;
2532 // if the implementation cursor gets affected (i.e. thew box where it is located
2533 // in gets removed) we need to move it before that... (otherwise it does not need to change)
2535 const SwStartNode
* pPointStartNode
= pTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
2536 const SwStartNode
* pMarkStartNode
= pTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
2538 if (!pTblCrsr
->HasMark() || (pPointStartNode
== rBox
.GetSttNd() && pMarkStartNode
== rBox
.GetSttNd()))
2540 bNowEmpty
= sal_True
;
2542 else if (pPointStartNode
== rBox
.GetSttNd() || pMarkStartNode
== rBox
.GetSttNd())
2544 sal_Int32 nPointRow
= -1, nPointCol
= -1;
2545 sal_Int32 nMarkRow
= -1, nMarkCol
= -1;
2546 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2547 String
aPointCellName( pTable
->GetTblBox( pPointStartNode
->GetIndex() )->GetName() );
2548 String
aMarkCellName( pTable
->GetTblBox( pMarkStartNode
->GetIndex() )->GetName() );
2550 sw_GetCellPosition( aPointCellName
, nPointCol
, nPointRow
);
2551 sw_GetCellPosition( aMarkCellName
, nMarkCol
, nMarkRow
);
2552 OSL_ENSURE( nPointRow
>= 0 && nPointCol
>= 0, "invalid row and col" );
2553 OSL_ENSURE( nMarkRow
>= 0 && nMarkCol
>= 0, "invalid row and col" );
2555 // move vertical or horizontal?
2556 OSL_ENSURE( nPointRow
== nMarkRow
|| nPointCol
== nMarkCol
,
2557 "row/col indices not matching" );
2558 OSL_ENSURE( nPointRow
!= nMarkRow
|| nPointCol
!= nMarkCol
,
2559 "point and mark are identical" );
2560 bool bMoveVertical
= (nPointCol
== nMarkCol
);
2561 bool bMoveHorizontal
= (nPointRow
== nMarkRow
);
2563 // get movement direction
2564 bool bMoveLeft
= false; // move left or right?
2565 bool bMoveUp
= false; // move up or down?
2568 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2569 bMoveUp
= nPointRow
> nMarkRow
;
2571 bMoveUp
= nMarkRow
> nPointRow
;
2573 else if (bMoveHorizontal
)
2575 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2576 bMoveLeft
= nPointCol
> nMarkCol
;
2578 bMoveLeft
= nMarkCol
> nPointCol
;
2581 OSL_FAIL( "neither vertical nor horizontal movement" );
2584 // get new box (position) to use...
2585 sal_Int32 nRow
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointRow
: nMarkRow
;
2586 sal_Int32 nCol
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointCol
: nMarkCol
;
2588 nRow
+= bMoveUp
? -1 : +1;
2589 if (bMoveHorizontal
)
2590 nCol
+= bMoveLeft
? -1 : +1;
2591 String aNewCellName
= sw_GetCellName( nCol
, nRow
);
2592 SwTableBox
* pNewBox
= (SwTableBox
*) pTable
->GetTblBox( aNewCellName
);
2594 if (pNewBox
) // set new position (cell range) to use
2596 // So erh lt man den ersten Inhaltsnode in einer gegebenen Zelle:
2597 // Zun chst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box...
2598 SwNodeIndex
aIdx( *pNewBox
->GetSttNd(), +1 );
2599 // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein,
2600 // deshalb das GoNext;
2601 SwCntntNode
*pCNd
= aIdx
.GetNode().GetCntntNode();
2603 pCNd
= GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx
);
2604 //und damit kann man z.B. eine SwPosition erzeugen:
2605 SwPosition
aNewPos( *pCNd
); // new position to beused with cursor
2607 // if the mark is to be changed make sure there is one...
2608 if (pMarkStartNode
== rBox
.GetSttNd() && !pTblCrsr
->HasMark())
2609 pTblCrsr
->SetMark();
2611 // set cursor to new position...
2612 SwPosition
*pPos
= (pPointStartNode
== rBox
.GetSttNd()) ?
2613 pTblCrsr
->GetPoint() : pTblCrsr
->GetMark();
2616 pPos
->nNode
= aNewPos
.nNode
;
2617 pPos
->nContent
= aNewPos
.nContent
;
2620 OSL_FAIL( "neither point nor mark available for change" );
2624 OSL_FAIL( "failed to get position" );
2631 void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor
&rRangeDesc
) const
2633 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2636 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2637 if(!pTable
->IsTblComplex())
2639 FillRangeDescriptor( rRangeDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2645 SwChartDataSequence::ExtendTo
2647 extends the data-sequence by new cells added at the end of the direction
2648 the data-sequence points to.
2649 If the cells are already within the range of the sequence nothing needs
2651 If the cells are beyond the end of the sequence (are not adjacent to the
2652 current last cell) nothing can be done. Only if the cells are adjacent to
2653 the last cell they can be added.
2655 @returns true if the data-sequence was changed.
2657 specifies if columns or rows are to be extended
2659 index of first new row/col to be included in data-sequence
2661 index of last new row/col to be included in data-sequence
2663 bool SwChartDataSequence::ExtendTo( bool bExtendCol
,
2664 sal_Int32 nFirstNew
, sal_Int32 nCount
)
2666 bool bChanged
= false;
2668 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
2669 //pUnoTblCrsr->MakeBoxSels();
2671 const SwStartNode
*pStartNd
= 0;
2672 const SwTableBox
*pStartBox
= 0;
2673 const SwTableBox
*pEndBox
= 0;
2675 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2676 OSL_ENSURE( !pTable
->IsTblComplex(), "table too complex" );
2677 if (nCount
< 1 || nFirstNew
< 0 || pTable
->IsTblComplex())
2681 // get range descriptor (cell range) for current data-sequence
2683 pStartNd
= pUnoTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
2684 pEndBox
= pTable
->GetTblBox( pStartNd
->GetIndex() );
2685 const String
aEndBox( pEndBox
->GetName() );
2687 pStartNd
= pUnoTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
2688 pStartBox
= pTable
->GetTblBox( pStartNd
->GetIndex() );
2689 const String
aStartBox( pStartBox
->GetName() );
2691 String
aCellRange( aStartBox
); // note that cell range here takes the newly added rows/cols already into account
2692 aCellRange
.AppendAscii( ":" );
2693 aCellRange
+= aEndBox
;
2694 SwRangeDescriptor aDesc
;
2695 FillRangeDescriptor( aDesc
, aCellRange
);
2697 String aNewStartCell
;
2699 if (bExtendCol
&& aDesc
.nBottom
+ 1 == nFirstNew
)
2701 // new column cells adjacent to the bottom of the
2702 // current data-sequence to be added...
2703 OSL_ENSURE( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2704 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2705 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
+ nCount
);
2708 else if (bExtendCol
&& aDesc
.nTop
- nCount
== nFirstNew
)
2710 // new column cells adjacent to the top of the
2711 // current data-sequence to be added...
2712 OSL_ENSURE( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2713 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
- nCount
);
2714 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2717 else if (!bExtendCol
&& aDesc
.nRight
+ 1 == nFirstNew
)
2719 // new row cells adjacent to the right of the
2720 // current data-sequence to be added...
2721 OSL_ENSURE( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2722 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2723 aNewEndCell
= sw_GetCellName(aDesc
.nRight
+ nCount
, aDesc
.nBottom
);
2726 else if (!bExtendCol
&& aDesc
.nLeft
- nCount
== nFirstNew
)
2728 // new row cells adjacent to the left of the
2729 // current data-sequence to be added...
2730 OSL_ENSURE( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2731 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
- nCount
, aDesc
.nTop
);
2732 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2738 // move table cursor to new start and end of data-sequence
2739 const SwTableBox
*pNewStartBox
= pTable
->GetTblBox( aNewStartCell
);
2740 const SwTableBox
*pNewEndBox
= pTable
->GetTblBox( aNewEndCell
);
2741 pUnoTblCrsr
->SetMark();
2742 pUnoTblCrsr
->GetPoint()->nNode
= *pNewEndBox
->GetSttNd();
2743 pUnoTblCrsr
->GetMark()->nNode
= *pNewStartBox
->GetSttNd();
2744 pUnoTblCrsr
->Move( fnMoveForward
, fnGoNode
);
2745 pUnoTblCrsr
->MakeBoxSels();
2751 SwChartLabeledDataSequence::SwChartLabeledDataSequence() :
2752 aEvtListeners( GetChartMutex() ),
2753 aModifyListeners( GetChartMutex() )
2755 bDisposed
= sal_False
;
2758 SwChartLabeledDataSequence::~SwChartLabeledDataSequence()
2762 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getValues( )
2763 throw (uno::RuntimeException
)
2765 SolarMutexGuard aGuard
;
2767 throw lang::DisposedException();
2771 void SwChartLabeledDataSequence::SetDataSequence(
2772 uno::Reference
< chart2::data::XDataSequence
>& rxDest
,
2773 const uno::Reference
< chart2::data::XDataSequence
>& rxSource
)
2775 uno::Reference
< util::XModifyListener
> xML( dynamic_cast< util::XModifyListener
* >(this), uno::UNO_QUERY
);
2776 uno::Reference
< lang::XEventListener
> xEL( dynamic_cast< lang::XEventListener
* >(this), uno::UNO_QUERY
);
2778 // stop listening to old data-sequence
2779 uno::Reference
< util::XModifyBroadcaster
> xMB( rxDest
, uno::UNO_QUERY
);
2781 xMB
->removeModifyListener( xML
);
2782 uno::Reference
< lang::XComponent
> xC( rxDest
, uno::UNO_QUERY
);
2784 xC
->removeEventListener( xEL
);
2788 // start listening to new data-sequence
2789 xC
= uno::Reference
< lang::XComponent
>( rxDest
, uno::UNO_QUERY
);
2791 xC
->addEventListener( xEL
);
2792 xMB
= uno::Reference
< util::XModifyBroadcaster
>( rxDest
, uno::UNO_QUERY
);
2794 xMB
->addModifyListener( xML
);
2797 void SAL_CALL
SwChartLabeledDataSequence::setValues(
2798 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2799 throw (uno::RuntimeException
)
2801 SolarMutexGuard aGuard
;
2803 throw lang::DisposedException();
2805 if (xData
!= rxSequence
)
2807 SetDataSequence( xData
, rxSequence
);
2808 // inform listeners of changes
2809 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2813 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getLabel( )
2814 throw (uno::RuntimeException
)
2816 SolarMutexGuard aGuard
;
2818 throw lang::DisposedException();
2822 void SAL_CALL
SwChartLabeledDataSequence::setLabel(
2823 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2824 throw (uno::RuntimeException
)
2826 SolarMutexGuard aGuard
;
2828 throw lang::DisposedException();
2830 if (xLabels
!= rxSequence
)
2832 SetDataSequence( xLabels
, rxSequence
);
2833 // inform listeners of changes
2834 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2838 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartLabeledDataSequence::createClone( )
2839 throw (uno::RuntimeException
)
2841 SolarMutexGuard aGuard
;
2843 throw lang::DisposedException();
2845 uno::Reference
< util::XCloneable
> xRes
;
2847 uno::Reference
< util::XCloneable
> xDataCloneable( xData
, uno::UNO_QUERY
);
2848 uno::Reference
< util::XCloneable
> xLabelsCloneable( xLabels
, uno::UNO_QUERY
);
2849 SwChartLabeledDataSequence
*pRes
= new SwChartLabeledDataSequence();
2850 if (xDataCloneable
.is())
2852 uno::Reference
< chart2::data::XDataSequence
> xDataClone( xDataCloneable
->createClone(), uno::UNO_QUERY
);
2853 pRes
->setValues( xDataClone
);
2856 if (xLabelsCloneable
.is())
2858 uno::Reference
< chart2::data::XDataSequence
> xLabelsClone( xLabelsCloneable
->createClone(), uno::UNO_QUERY
);
2859 pRes
->setLabel( xLabelsClone
);
2865 OUString SAL_CALL
SwChartLabeledDataSequence::getImplementationName( )
2866 throw (uno::RuntimeException
)
2868 return OUString("SwChartLabeledDataSequence");
2871 sal_Bool SAL_CALL
SwChartLabeledDataSequence::supportsService(
2872 const OUString
& rServiceName
)
2873 throw (uno::RuntimeException
)
2875 return rServiceName
== SN_LABELED_DATA_SEQUENCE
;
2878 uno::Sequence
< OUString
> SAL_CALL
SwChartLabeledDataSequence::getSupportedServiceNames( )
2879 throw (uno::RuntimeException
)
2881 SolarMutexGuard aGuard
;
2882 uno::Sequence
< OUString
> aRes(1);
2883 aRes
.getArray()[0] = SN_LABELED_DATA_SEQUENCE
;
2887 void SAL_CALL
SwChartLabeledDataSequence::disposing(
2888 const lang::EventObject
& rSource
)
2889 throw (uno::RuntimeException
)
2891 osl::MutexGuard
aGuard( GetChartMutex() );
2892 uno::Reference
< uno::XInterface
> xRef( rSource
.Source
);
2895 if (xRef
== xLabels
)
2897 if (!xData
.is() && !xLabels
.is())
2901 void SAL_CALL
SwChartLabeledDataSequence::modified(
2902 const lang::EventObject
& rEvent
)
2903 throw (uno::RuntimeException
)
2905 if (rEvent
.Source
== xData
|| rEvent
.Source
== xLabels
)
2907 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2911 void SAL_CALL
SwChartLabeledDataSequence::addModifyListener(
2912 const uno::Reference
< util::XModifyListener
>& rxListener
)
2913 throw (uno::RuntimeException
)
2915 osl::MutexGuard
aGuard( GetChartMutex() );
2916 if (!bDisposed
&& rxListener
.is())
2917 aModifyListeners
.addInterface( rxListener
);
2920 void SAL_CALL
SwChartLabeledDataSequence::removeModifyListener(
2921 const uno::Reference
< util::XModifyListener
>& rxListener
)
2922 throw (uno::RuntimeException
)
2924 osl::MutexGuard
aGuard( GetChartMutex() );
2925 if (!bDisposed
&& rxListener
.is())
2926 aModifyListeners
.removeInterface( rxListener
);
2929 void SAL_CALL
SwChartLabeledDataSequence::dispose( )
2930 throw (uno::RuntimeException
)
2932 bool bMustDispose( false );
2934 osl::MutexGuard
aGuard( GetChartMutex() );
2935 bMustDispose
= !bDisposed
;
2937 bDisposed
= sal_True
;
2941 bDisposed
= sal_True
;
2943 // require listeners to release references to this object
2944 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence
* >(this) );
2945 aModifyListeners
.disposeAndClear( aEvtObj
);
2946 aEvtListeners
.disposeAndClear( aEvtObj
);
2950 void SAL_CALL
SwChartLabeledDataSequence::addEventListener(
2951 const uno::Reference
< lang::XEventListener
>& rxListener
)
2952 throw (uno::RuntimeException
)
2954 osl::MutexGuard
aGuard( GetChartMutex() );
2955 if (!bDisposed
&& rxListener
.is())
2956 aEvtListeners
.addInterface( rxListener
);
2959 void SAL_CALL
SwChartLabeledDataSequence::removeEventListener(
2960 const uno::Reference
< lang::XEventListener
>& rxListener
)
2961 throw (uno::RuntimeException
)
2963 osl::MutexGuard
aGuard( GetChartMutex() );
2964 if (!bDisposed
&& rxListener
.is())
2965 aEvtListeners
.removeInterface( rxListener
);
2968 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */