1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unochart.cxx,v $
10 * $Revision: 1.18.36.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
38 #include <com/sun/star/chart/ChartDataRowSource.hpp>
39 #include <com/sun/star/chart2/data/LabelOrigin.hpp>
40 #include <cppuhelper/interfacecontainer.hxx>
41 #include <vos/mutex.hxx>
42 #include <osl/mutex.hxx>
43 #include <vcl/svapp.hxx>
44 #include <svtools/zforlist.hxx> // SvNumberFormatter
45 #include <svtools/chartprettypainter.hxx>
47 #include <tools/link.hxx>
49 #include <XMLRangeHelper.hxx>
50 #include <unochart.hxx>
51 #include <swtable.hxx>
52 #include <unoprnms.hxx>
55 #include <unocrsr.hxx>
61 #include <swtable.hxx>
62 #include <swtypes.hxx>
64 #include <unocore.hrc>
69 #define SN_DATA_PROVIDER "com.sun.star.chart2.data.DataProvider"
70 #define SN_DATA_SOURCE "com.sun.star.chart2.data.DataSource"
71 #define SN_DATA_SEQUENCE "com.sun.star.chart2.data.DataSequence"
72 #define SN_LABELED_DATA_SEQUENCE "com.sun.star.chart2.data.LabeledDataSequence"
74 #define DIRECTION_DONT_KNOW -1
75 #define DIRECTION_HAS_ERROR -2
76 #define DIRECTION_COLS 0
77 #define DIRECTION_ROWS 1
79 using namespace ::com::sun::star
;
80 using ::rtl::OUString
;
83 extern void lcl_GetCellPosition( const String
&rCellName
, sal_Int32
&rColumn
, sal_Int32
&rRow
);
84 extern String
lcl_GetCellName( sal_Int32 nColumn
, sal_Int32 nRow
);
85 extern int lcl_CompareCellsByColFirst( const String
&rCellName1
, const String
&rCellName2
);
86 extern int lcl_CompareCellsByRowFirst( const String
&rCellName1
, const String
&rCellName2
);
87 extern int lcl_CompareCellRanges(
88 const String
&rRange1StartCell
, const String
&rRange1EndCell
,
89 const String
&rRange2StartCell
, const String
&rRange2EndCell
,
90 sal_Bool bCmpColsFirst
);
91 extern void lcl_NormalizeRange( String
&rCell1
, String
&rCell2
);
93 //////////////////////////////////////////////////////////////////////
96 void SwChartHelper::DoUpdateAllCharts( SwDoc
* pDoc
)
101 uno::Reference
< frame::XModel
> xRes
;
105 SwNodeIndex
aIdx( *pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
106 while( 0 != (pStNd
= aIdx
.GetNode().GetStartNode()) )
109 if (0 != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
110 ChartPrettyPainter::IsChart( pONd
->GetOLEObj().GetObject() ) )
112 // Load the object and set modified
114 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
115 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
119 uno::Reference
< util::XModifiable
> xModif( xIP
->getComponent(), uno::UNO_QUERY_THROW
);
120 xModif
->setModified( sal_True
);
122 catch ( uno::Exception
& )
128 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
132 //////////////////////////////////////////////////////////////////////
134 SwChartLockController_Helper::SwChartLockController_Helper( SwDoc
*pDocument
) :
137 aUnlockTimer
.SetTimeout( 1500 );
138 aUnlockTimer
.SetTimeoutHdl( LINK( this, SwChartLockController_Helper
, DoUnlockAllCharts
));
142 SwChartLockController_Helper::~SwChartLockController_Helper()
144 if (pDoc
) // still connected?
149 void SwChartLockController_Helper::StartOrContinueLocking()
153 aUnlockTimer
.Start(); // start or continue time of locking
157 void SwChartLockController_Helper::Disconnect()
165 void SwChartLockController_Helper::LockUnlockAllCharts( sal_Bool bLock
)
170 const SwFrmFmts
& rTblFmts
= *pDoc
->GetTblFrmFmts();
171 for( USHORT n
= 0; n
< rTblFmts
.Count(); ++n
)
174 const SwTableNode
* pTblNd
;
175 SwFrmFmt
* pFmt
= rTblFmts
[ n
];
177 if( 0 != ( pTmpTbl
= SwTable::FindTable( pFmt
) ) &&
178 0 != ( pTblNd
= pTmpTbl
->GetTableNode() ) &&
179 pTblNd
->GetNodes().IsDocNodes() )
181 uno::Reference
< frame::XModel
> xRes
;
183 String
aName( pTmpTbl
->GetFrmFmt()->GetName() );
186 SwNodeIndex
aIdx( *pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
187 while( 0 != (pStNd
= aIdx
.GetNode().GetStartNode()) )
190 if (0 != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
191 pONd
->GetChartTblName().Len() > 0 /* is chart object? */)
193 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
194 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
196 xRes
= uno::Reference
< frame::XModel
>( xIP
->getComponent(), uno::UNO_QUERY
);
200 xRes
->lockControllers();
202 xRes
->unlockControllers();
206 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
215 IMPL_LINK( SwChartLockController_Helper
, DoUnlockAllCharts
, Timer
*, /*pTimer*/ )
222 //////////////////////////////////////////////////////////////////////
224 static osl::Mutex
& GetChartMutex()
226 static osl::Mutex aMutex
;
231 static void LaunchModifiedEvent(
232 ::cppu::OInterfaceContainerHelper
&rICH
,
233 const uno::Reference
< uno::XInterface
> &rxI
)
235 lang::EventObject
aEvtObj( rxI
);
236 cppu::OInterfaceIteratorHelper
aIt( rICH
);
237 while (aIt
.hasMoreElements())
239 uno::Reference
< util::XModifyListener
> xRef( aIt
.next(), uno::UNO_QUERY
);
241 xRef
->modified( aEvtObj
);
245 //////////////////////////////////////////////////////////////////////
247 // rCellRangeName needs to be of one of the following formats:
249 // - e.g. "Table1.A2:E5"
250 sal_Bool
FillRangeDescriptor(
251 SwRangeDescriptor
&rDesc
,
252 const String
&rCellRangeName
)
254 xub_StrLen nToken
= STRING_NOTFOUND
== rCellRangeName
.Search('.') ? 0 : 1;
255 String
aCellRangeNoTableName( rCellRangeName
.GetToken( nToken
, '.' ) );
256 String
aTLName( aCellRangeNoTableName
.GetToken(0, ':') ); // name of top left cell
257 String
aBRName( aCellRangeNoTableName
.GetToken(1, ':') ); // name of bottom right cell
258 if(!aTLName
.Len() || !aBRName
.Len())
261 rDesc
.nTop
= rDesc
.nLeft
= rDesc
.nBottom
= rDesc
.nRight
= -1;
262 lcl_GetCellPosition( aTLName
, rDesc
.nLeft
, rDesc
.nTop
);
263 lcl_GetCellPosition( aBRName
, rDesc
.nRight
, rDesc
.nBottom
);
265 DBG_ASSERT( rDesc
.nTop
!= -1 &&
267 rDesc
.nBottom
!= -1 &&
269 "failed to get range descriptor" );
270 DBG_ASSERT( rDesc
.nTop
<= rDesc
.nBottom
&& rDesc
.nLeft
<= rDesc
.nRight
,
271 "invalid range descriptor");
276 static String
GetCellRangeName( SwFrmFmt
&rTblFmt
, SwUnoCrsr
&rTblCrsr
)
280 //!! see also SwXTextTableCursor::getRangeName
282 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(&rTblCrsr
);
285 pUnoTblCrsr
->MakeBoxSels();
287 const SwStartNode
* pStart
;
288 const SwTableBox
* pStartBox
= 0;
289 const SwTableBox
* pEndBox
= 0;
291 pStart
= pUnoTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
294 const SwTable
* pTable
= SwTable::FindTable( &rTblFmt
);
295 pEndBox
= pTable
->GetTblBox( pStart
->GetIndex());
296 aRes
= pEndBox
->GetName();
298 if(pUnoTblCrsr
->HasMark())
300 pStart
= pUnoTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
301 pStartBox
= pTable
->GetTblBox( pStart
->GetIndex());
303 DBG_ASSERT( pStartBox
, "start box not found" );
304 DBG_ASSERT( pEndBox
, "end box not found" );
305 // need to switch start and end?
306 if (*pUnoTblCrsr
->GetPoint() < *pUnoTblCrsr
->GetMark())
308 const SwTableBox
* pTmpBox
= pStartBox
;
313 aRes
= pStartBox
->GetName();
314 aRes
+= (sal_Unicode
)':';
316 aRes
+= pEndBox
->GetName();
318 aRes
+= pStartBox
->GetName();
325 static String
GetRangeRepFromTableAndCells( const String
&rTableName
,
326 const String
&rStartCell
, const String
&rEndCell
,
327 sal_Bool bForceEndCellName
)
329 DBG_ASSERT( rTableName
.Len(), "table name missing" );
330 DBG_ASSERT( rStartCell
.Len(), "cell name missing" );
331 String
aRes( rTableName
);
332 aRes
+= (sal_Unicode
) '.';
337 aRes
+= (sal_Unicode
) ':';
340 else if (bForceEndCellName
)
342 aRes
+= (sal_Unicode
) ':';
350 static sal_Bool
GetTableAndCellsFromRangeRep(
351 const OUString
&rRangeRepresentation
,
355 sal_Bool bSortStartEndCells
= sal_True
)
357 // parse range representation for table name and cell/range names
358 // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2"
359 String aTblName
; // table name
360 OUString aRange
; // cell range
361 String aStartCell
; // name of top left cell
362 String aEndCell
; // name of bottom right cell
363 sal_Int32 nIdx
= rRangeRepresentation
.indexOf( '.' );
366 aTblName
= rRangeRepresentation
.copy( 0, nIdx
);
367 aRange
= rRangeRepresentation
.copy( nIdx
+ 1 );
368 sal_Int32 nPos
= aRange
.indexOf( ':' );
369 if (nPos
>= 0) // a cell-range like "Table1.A2:D4"
371 aStartCell
= aRange
.copy( 0, nPos
);
372 aEndCell
= aRange
.copy( nPos
+ 1 );
374 // need to switch start and end cell ?
375 // (does not check for normalization here)
376 if (bSortStartEndCells
&& 1 == lcl_CompareCellsByColFirst( aStartCell
, aEndCell
))
378 String
aTmp( aStartCell
);
379 aStartCell
= aEndCell
;
383 else // a single cell like in "Table1.B3"
385 aStartCell
= aEndCell
= aRange
;
389 sal_Bool bSuccess
= aTblName
.Len() != 0 &&
390 aStartCell
.Len() != 0 && aEndCell
.Len() != 0;
394 rStartCell
= aStartCell
;
401 static void GetTableByName( const SwDoc
&rDoc
, const String
&rTableName
,
402 SwFrmFmt
**ppTblFmt
, SwTable
**ppTable
)
404 SwFrmFmt
*pTblFmt
= NULL
;
406 // find frame format of table
407 //! see SwXTextTables::getByName
408 sal_uInt16 nCount
= rDoc
.GetTblFrmFmtCount(sal_True
);
409 for (sal_uInt16 i
= 0; i
< nCount
&& !pTblFmt
; ++i
)
411 SwFrmFmt
& rTblFmt
= rDoc
.GetTblFrmFmt(i
, sal_True
);
412 if(rTableName
== rTblFmt
.GetName())
420 *ppTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
424 static void GetFormatAndCreateCursorFromRangeRep(
426 const OUString
&rRangeRepresentation
, // must be a single range (i.e. so called sub-range)
427 SwFrmFmt
**ppTblFmt
, // will be set to the table format of the table used in the range representation
428 SwUnoCrsr
**ppUnoCrsr
) // will be set to cursor spanning the cell range
429 // (cursor will be created!)
431 String aTblName
; // table name
432 String aStartCell
; // name of top left cell
433 String aEndCell
; // name of bottom right cell
434 sal_Bool bNamesFound
= GetTableAndCellsFromRangeRep( rRangeRepresentation
,
435 aTblName
, aStartCell
, aEndCell
);
446 SwFrmFmt
*pTblFmt
= NULL
;
448 // is the correct table format already provided?
449 if (*ppTblFmt
!= NULL
&& (*ppTblFmt
)->GetName() == aTblName
)
452 GetTableByName( *pDoc
, aTblName
, &pTblFmt
, NULL
);
457 if (ppUnoCrsr
!= NULL
)
459 *ppUnoCrsr
= NULL
; // default result in case of failure
461 SwTable
*pTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
462 // create new SwUnoCrsr spanning the specified range
463 //! see also SwXTextTable::GetRangeByName
464 // --> OD 2007-08-03 #i80314#
465 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
466 const SwTableBox
* pTLBox
=
467 pTable
? pTable
->GetTblBox( aStartCell
, true ) : 0;
471 // hier muessen die Actions aufgehoben werden
472 UnoActionRemoveContext
aRemoveContext(pTblFmt
->GetDoc());
473 const SwStartNode
* pSttNd
= pTLBox
->GetSttNd();
474 SwPosition
aPos(*pSttNd
);
475 // set cursor to top left box of range
476 SwUnoCrsr
* pUnoCrsr
= pTblFmt
->GetDoc()->CreateUnoCrsr(aPos
, sal_True
);
477 pUnoCrsr
->Move( fnMoveForward
, fnGoNode
);
478 pUnoCrsr
->SetRemainInSection( sal_False
);
479 // --> OD 2007-08-03 #i80314#
480 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
481 const SwTableBox
* pBRBox
= pTable
->GetTblBox( aEndCell
, true );
486 pUnoCrsr
->GetPoint()->nNode
= *pBRBox
->GetSttNd();
487 pUnoCrsr
->Move( fnMoveForward
, fnGoNode
);
488 SwUnoTableCrsr
* pCrsr
=
489 dynamic_cast<SwUnoTableCrsr
*>(pUnoCrsr
);
490 pCrsr
->MakeBoxSels();
505 static sal_Bool
GetSubranges( const OUString
&rRangeRepresentation
,
506 uno::Sequence
< OUString
> &rSubRanges
, sal_Bool bNormalize
)
508 sal_Bool bRes
= sal_True
;
509 String
aRangesStr( rRangeRepresentation
);
510 xub_StrLen nLen
= aRangesStr
.GetTokenCount( ';' );
511 uno::Sequence
< OUString
> aRanges( nLen
);
516 OUString
*pRanges
= aRanges
.getArray();
518 for ( xub_StrLen i
= 0; i
< nLen
&& bRes
; ++i
)
520 String
aRange( aRangesStr
.GetToken( i
, ';' ) );
523 pRanges
[nCnt
] = aRange
;
525 String aTableName
, aStartCell
, aEndCell
;
526 bRes
&= GetTableAndCellsFromRangeRep( aRange
,
527 aTableName
, aStartCell
, aEndCell
);
531 lcl_NormalizeRange( aStartCell
, aEndCell
);
532 pRanges
[nCnt
] = GetRangeRepFromTableAndCells( aTableName
,
533 aStartCell
, aEndCell
, sal_True
);
536 // make sure to use only a single table
538 aFirstTable
= aTableName
;
540 bRes
&= aFirstTable
== aTableName
;
546 aRanges
.realloc( nCnt
);
548 rSubRanges
= aRanges
;
553 static void SortSubranges( uno::Sequence
< OUString
> &rSubRanges
, sal_Bool bCmpByColumn
)
555 sal_Int32 nLen
= rSubRanges
.getLength();
556 OUString
*pSubRanges
= rSubRanges
.getArray();
558 String aSmallestTblName
;
559 String aSmallestStartCell
;
560 String aSmallestEndCell
;
562 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
564 sal_Int32 nIdxOfSmallest
= i
;
565 GetTableAndCellsFromRangeRep( pSubRanges
[nIdxOfSmallest
],
566 aSmallestTblName
, aSmallestStartCell
, aSmallestEndCell
);
567 if (aSmallestEndCell
.Len() == 0)
568 aSmallestEndCell
= aSmallestStartCell
;
570 for (sal_Int32 k
= i
+1; k
< nLen
; ++k
)
572 // get cell names for sub range
576 GetTableAndCellsFromRangeRep( pSubRanges
[k
],
577 aTblName
, aStartCell
, aEndCell
);
578 if (aEndCell
.Len() == 0)
579 aEndCell
= aStartCell
;
581 // compare cell ranges ( is the new one smaller? )
582 if (-1 == lcl_CompareCellRanges( aStartCell
, aEndCell
,
583 aSmallestStartCell
, aSmallestEndCell
, bCmpByColumn
))
586 aSmallestTblName
= aTblName
;
587 aSmallestStartCell
= aStartCell
;
588 aSmallestEndCell
= aEndCell
;
592 // move smallest element to the start of the not sorted area
593 OUString
aTmp( pSubRanges
[ nIdxOfSmallest
] );
594 pSubRanges
[ nIdxOfSmallest
] = pSubRanges
[ i
];
595 pSubRanges
[ i
] = aTmp
;
599 //////////////////////////////////////////////////////////////////////
601 SwChartDataProvider::SwChartDataProvider( const SwDoc
* pSwDoc
) :
602 aEvtListeners( GetChartMutex() ),
605 bDisposed
= sal_False
;
609 SwChartDataProvider::~SwChartDataProvider()
613 uno::Reference
< chart2::data::XDataSource
> SwChartDataProvider::Impl_createDataSource(
614 const uno::Sequence
< beans::PropertyValue
>& rArguments
, sal_Bool bTestOnly
)
615 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
617 vos::OGuard
aGuard( Application::GetSolarMutex() );
619 throw lang::DisposedException();
621 uno::Reference
< chart2::data::XDataSource
> xRes
;
624 throw uno::RuntimeException();
627 OUString aRangeRepresentation
;
628 uno::Sequence
< sal_Int32
> aSequenceMapping
;
629 sal_Bool bFirstIsLabel
= sal_False
;
630 sal_Bool bDtaSrcIsColumns
= sal_True
; // true : DataSource will be sequence of columns
631 // false: DataSource will be sequence of rows
632 OUString aChartOleObjectName
;//work around wrong writer ranges ( see Issue 58464 )
633 sal_Int32 nArgs
= rArguments
.getLength();
634 DBG_ASSERT( nArgs
!= 0, "no properties provided" );
637 const beans::PropertyValue
*pArg
= rArguments
.getConstArray();
638 for (sal_Int32 i
= 0; i
< nArgs
; ++i
)
640 if (pArg
[i
].Name
.equalsAscii( "DataRowSource" ))
642 chart::ChartDataRowSource eSource
;
643 if (!(pArg
[i
].Value
>>= eSource
))
646 if (!(pArg
[i
].Value
>>= nTmp
))
647 throw lang::IllegalArgumentException();
648 eSource
= static_cast< chart::ChartDataRowSource
>( nTmp
);
650 bDtaSrcIsColumns
= eSource
== chart::ChartDataRowSource_COLUMNS
;
652 else if (pArg
[i
].Name
.equalsAscii( "FirstCellAsLabel" ))
654 if (!(pArg
[i
].Value
>>= bFirstIsLabel
))
655 throw lang::IllegalArgumentException();
657 else if (pArg
[i
].Name
.equalsAscii( "CellRangeRepresentation" ))
659 if (!(pArg
[i
].Value
>>= aRangeRepresentation
))
660 throw lang::IllegalArgumentException();
662 else if (pArg
[i
].Name
.equalsAscii( "SequenceMapping" ))
664 if (!(pArg
[i
].Value
>>= aSequenceMapping
))
665 throw lang::IllegalArgumentException();
667 else if (pArg
[i
].Name
.equalsAscii( "ChartOleObjectName" ))
669 if (!(pArg
[i
].Value
>>= aChartOleObjectName
))
670 throw lang::IllegalArgumentException();
674 uno::Sequence
< OUString
> aSubRanges
;
675 // get sub-ranges and check that they all are from the very same table
676 sal_Bool bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, sal_True
);
678 if (!bOk
&& pDoc
&& aChartOleObjectName
.getLength() )
680 //try to correct the range here
681 //work around wrong writer ranges ( see Issue 58464 )
682 String aChartTableName
;
684 const SwNodes
& rNodes
= pDoc
->GetNodes();
685 for( ULONG nN
= rNodes
.Count(); nN
--; )
687 SwNodePtr pNode
= rNodes
[nN
];
690 const SwOLENode
* pOleNode
= pNode
->GetOLENode();
693 const SwOLEObj
& rOObj
= pOleNode
->GetOLEObj();
694 if( aChartOleObjectName
.equals( rOObj
.GetCurrentPersistName() ) )
696 aChartTableName
= pOleNode
->GetChartTblName();
701 if( aChartTableName
.Len() )
703 //the wrong range is still shifted one row down
704 //thus the first row is missing and an invalid row at the end is added.
705 //Therefore we need to shift the range one row up
706 SwRangeDescriptor aDesc
;
707 if (aRangeRepresentation
.getLength() == 0)
708 return xRes
; // we cant handle this thus returning an empty references
709 aRangeRepresentation
= aRangeRepresentation
.copy( 1 ); // get rid of '.' to have only the cell range left
710 FillRangeDescriptor( aDesc
, aRangeRepresentation
);
712 if (aDesc
.nTop
<= 0) // no chance to shift the range one row up?
713 return xRes
; // we cant handle this thus returning an empty references
717 String
aNewStartCell( lcl_GetCellName( aDesc
.nLeft
, aDesc
.nTop
) );
718 String
aNewEndCell( lcl_GetCellName( aDesc
.nRight
, aDesc
.nBottom
) );
719 aRangeRepresentation
= GetRangeRepFromTableAndCells(
720 aChartTableName
, aNewStartCell
, aNewEndCell
, sal_True
);
721 bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, sal_True
);
724 if (!bOk
) // different tables used, or incorrect range specifiers
725 throw lang::IllegalArgumentException();
727 SortSubranges( aSubRanges
, bDtaSrcIsColumns
);
728 const OUString
*pSubRanges
= aSubRanges
.getConstArray();
729 #if OSL_DEBUG_LEVEL > 1
731 sal_Int32 nSR
= aSubRanges
.getLength();
732 OUString
*pSR
= aSubRanges
.getArray();
734 for (sal_Int32 i
= 0; i
< nSR
; ++i
)
741 // get table format for that single table from above
742 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
743 SwUnoCrsr
*pUnoCrsr
= 0; // here required to check if the cells in the range do actually exist
744 std::auto_ptr
< SwUnoCrsr
> pAuto( pUnoCrsr
); // to end lifetime of object pointed to by pUnoCrsr
745 if (aSubRanges
.getLength() > 0)
746 GetFormatAndCreateCursorFromRangeRep( pDoc
, pSubRanges
[0], &pTblFmt
, &pUnoCrsr
);
747 if (!pTblFmt
|| !pUnoCrsr
)
748 throw lang::IllegalArgumentException();
752 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
753 if(pTable
->IsTblComplex())
754 return xRes
; // we cant handle this thus returning an empty references
757 // get a character map in the size of the table to mark
758 // all the ranges to use in
759 sal_Int32 nRows
= pTable
->GetTabLines().Count();
760 sal_Int32 nCols
= pTable
->GetTabLines().GetObject(0)->GetTabBoxes().Count();
761 std::vector
< std::vector
< sal_Char
> > aMap( nRows
);
762 for (sal_Int32 i
= 0; i
< nRows
; ++i
)
763 aMap
[i
].resize( nCols
);
765 // iterate over subranges and mark used cells in above map
766 //!! by proceeding this way we automatically get rid of
767 //!! multiple listed or overlapping cell ranges which should
768 //!! just be ignored silently
769 sal_Int32 nSubRanges
= aSubRanges
.getLength();
770 for (sal_Int32 i
= 0; i
< nSubRanges
; ++i
)
772 String aTblName
, aStartCell
, aEndCell
;
773 sal_Bool bOk2
= GetTableAndCellsFromRangeRep(
774 pSubRanges
[i
], aTblName
, aStartCell
, aEndCell
);
776 DBG_ASSERT( bOk2
, "failed to get table and start/end cells" );
778 sal_Int32 nStartRow
, nStartCol
, nEndRow
, nEndCol
;
779 lcl_GetCellPosition( aStartCell
, nStartCol
, nStartRow
);
780 lcl_GetCellPosition( aEndCell
, nEndCol
, nEndRow
);
781 DBG_ASSERT( nStartRow
<= nEndRow
&& nStartCol
<= nEndCol
,
782 "cell range not normalized");
784 // test if the ranges span more than the available cells
785 if( nStartRow
< 0 || nEndRow
>= nRows
||
786 nStartCol
< 0 || nEndCol
>= nCols
)
788 throw lang::IllegalArgumentException();
790 for (sal_Int32 k1
= nStartRow
; k1
<= nEndRow
; ++k1
)
792 for (sal_Int32 k2
= nStartCol
; k2
<= nEndCol
; ++k2
)
798 // find label and data sequences to use
800 sal_Int32 oi
; // outer index (slower changing index)
801 sal_Int32 ii
; // inner index (faster changing index)
802 sal_Int32 oiEnd
= bDtaSrcIsColumns
? nCols
: nRows
;
803 sal_Int32 iiEnd
= bDtaSrcIsColumns
? nRows
: nCols
;
804 std::vector
< sal_Int32
> aLabelIdx( oiEnd
);
805 std::vector
< sal_Int32
> aDataStartIdx( oiEnd
);
806 std::vector
< sal_Int32
> aDataLen( oiEnd
);
807 for (oi
= 0; oi
< oiEnd
; ++oi
)
810 aDataStartIdx
[oi
] = -1;
814 for (oi
= 0; oi
< oiEnd
; ++oi
)
819 sal_Char
&rChar
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
];
821 // label should be used but is not yet found?
822 if (rChar
== 'x' && bFirstIsLabel
&& aLabelIdx
[oi
] == -1)
825 rChar
= 'L'; // setting a different char for labels here
826 // makes the test for the data sequence below
830 // find data sequence
831 if (rChar
== 'x' && aDataStartIdx
[oi
] == -1)
833 aDataStartIdx
[oi
] = ii
;
835 // get length of data sequence
838 while (ii
< iiEnd
&& 'x' == (c
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
844 // check that there is no other seperate sequence of data
845 // to be found because that is not supported
848 if ('x' == (c
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
849 throw lang::IllegalArgumentException();
858 // make some other consistency checks while calculating
859 // the number of XLabeledDataSequence to build:
860 // - labels should always be used or not at all
861 // - the data sequences should have equal non-zero length
862 sal_Int32 nNumLDS
= 0;
865 sal_Int32 nFirstSeqLen
= 0;
866 sal_Int32 nFirstSeqLabelIdx
= -1;
867 for (oi
= 0; oi
< oiEnd
; ++oi
)
869 sal_Bool bFirstFound
= sal_False
;
870 // row/col used at all?
871 if (aDataStartIdx
[oi
] != -1 &&
872 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1))
877 nFirstSeqLen
= aDataLen
[oi
];
878 nFirstSeqLabelIdx
= aLabelIdx
[oi
];
879 bFirstFound
= sal_True
;
883 if (nFirstSeqLen
!= aDataLen
[oi
] ||
884 nFirstSeqLabelIdx
!= aLabelIdx
[oi
])
885 throw lang::IllegalArgumentException();
891 throw lang::IllegalArgumentException();
893 // now we should have all necessary data to build a proper DataSource
894 // thus if we came this far there should be no further problem
896 return xRes
; // have createDataSourcePossible return true
898 // create data source from found label and data sequences
899 uno::Sequence
< uno::Reference
< chart2::data::XDataSequence
> > aLabelSeqs( nNumLDS
);
900 uno::Reference
< chart2::data::XDataSequence
> *pLabelSeqs
= aLabelSeqs
.getArray();
901 uno::Sequence
< uno::Reference
< chart2::data::XDataSequence
> > aDataSeqs( nNumLDS
);
902 uno::Reference
< chart2::data::XDataSequence
> *pDataSeqs
= aDataSeqs
.getArray();
903 sal_Int32 nSeqsIdx
= 0;
904 for (oi
= 0; oi
< oiEnd
; ++oi
)
906 // row/col not used? (see if-statement above where nNumLDS was counted)
907 if (!(aDataStartIdx
[oi
] != -1 &&
908 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1)))
911 // get cell ranges for label and data
913 SwRangeDescriptor aLabelDesc
;
914 SwRangeDescriptor aDataDesc
;
915 if (bDtaSrcIsColumns
) // use columns
917 aLabelDesc
.nTop
= aLabelIdx
[oi
];
918 aLabelDesc
.nLeft
= oi
;
919 aLabelDesc
.nBottom
= aLabelDesc
.nTop
;
920 aLabelDesc
.nRight
= oi
;
922 aDataDesc
.nTop
= aDataStartIdx
[oi
];
923 aDataDesc
.nLeft
= oi
;
924 aDataDesc
.nBottom
= aDataDesc
.nTop
+ aDataLen
[oi
] - 1;
925 aDataDesc
.nRight
= oi
;
929 aLabelDesc
.nTop
= oi
;
930 aLabelDesc
.nLeft
= aLabelIdx
[oi
];
931 aLabelDesc
.nBottom
= oi
;
932 aLabelDesc
.nRight
= aLabelDesc
.nLeft
;
935 aDataDesc
.nLeft
= aDataStartIdx
[oi
];
936 aDataDesc
.nBottom
= oi
;
937 aDataDesc
.nRight
= aDataDesc
.nLeft
+ aDataLen
[oi
] - 1;
939 String
aBaseName( pTblFmt
->GetName() );
943 if (aLabelIdx
[oi
] != -1)
945 aLabelRange
+= aBaseName
;
946 aLabelRange
+= lcl_GetCellName( aLabelDesc
.nLeft
, aLabelDesc
.nTop
);
948 aLabelRange
+= lcl_GetCellName( aLabelDesc
.nRight
, aLabelDesc
.nBottom
);
952 if (aDataStartIdx
[oi
] != -1)
954 aDataRange
+= aBaseName
;
955 aDataRange
+= lcl_GetCellName( aDataDesc
.nLeft
, aDataDesc
.nTop
);
957 aDataRange
+= lcl_GetCellName( aDataDesc
.nRight
, aDataDesc
.nBottom
);
960 // get cursors spanning the cell ranges for label and data
961 SwUnoCrsr
*pLabelUnoCrsr
= 0;
962 SwUnoCrsr
*pDataUnoCrsr
= 0;
963 GetFormatAndCreateCursorFromRangeRep( pDoc
, aLabelRange
, &pTblFmt
, &pLabelUnoCrsr
);
964 GetFormatAndCreateCursorFromRangeRep( pDoc
, aDataRange
, &pTblFmt
, &pDataUnoCrsr
);
966 // create XDataSequence's from cursors
968 pLabelSeqs
[ nSeqsIdx
] = new SwChartDataSequence( *this, *pTblFmt
, pLabelUnoCrsr
);
969 DBG_ASSERT( pDataUnoCrsr
, "pointer to data sequence missing" );
971 pDataSeqs
[ nSeqsIdx
] = new SwChartDataSequence( *this, *pTblFmt
, pDataUnoCrsr
);
972 if (pLabelUnoCrsr
|| pDataUnoCrsr
)
975 DBG_ASSERT( nSeqsIdx
== nNumLDS
,
976 "mismatch between sequence size and num,ber of entries" );
978 // build data source from data and label sequences
979 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aLDS( nNumLDS
);
980 uno::Reference
< chart2::data::XLabeledDataSequence
> *pLDS
= aLDS
.getArray();
981 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
983 SwChartLabeledDataSequence
*pLabeledDtaSeq
= new SwChartLabeledDataSequence
;
984 pLabeledDtaSeq
->setLabel( pLabelSeqs
[i
] );
985 pLabeledDtaSeq
->setValues( pDataSeqs
[i
] );
986 pLDS
[i
] = pLabeledDtaSeq
;
989 // apply 'SequenceMapping' if it was provided
990 sal_Int32 nSequenceMappingLen
= aSequenceMapping
.getLength();
991 if (nSequenceMappingLen
)
993 sal_Int32
*pSequenceMapping
= aSequenceMapping
.getArray();
994 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aOld_LDS( aLDS
);
995 uno::Reference
< chart2::data::XLabeledDataSequence
> *pOld_LDS
= aOld_LDS
.getArray();
997 sal_Int32 nNewCnt
= 0;
998 for (sal_Int32 i
= 0; i
< nSequenceMappingLen
; ++i
)
1000 // check that index to be used is valid
1001 // and has not yet been used
1002 sal_Int32 nIdx
= pSequenceMapping
[i
];
1003 if (0 <= nIdx
&& nIdx
< nNumLDS
&& pOld_LDS
[nIdx
].is())
1005 pLDS
[nNewCnt
++] = pOld_LDS
[nIdx
];
1007 // mark index as being used already (avoids duplicate entries)
1008 pOld_LDS
[nIdx
].clear();
1011 // add not yet used 'old' sequences to new one
1012 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
1014 #if OSL_DEBUG_LEVEL > 1
1015 if (!pOld_LDS
[i
].is())
1018 if (pOld_LDS
[i
].is())
1019 pLDS
[nNewCnt
++] = pOld_LDS
[i
];
1021 DBG_ASSERT( nNewCnt
== nNumLDS
, "unexpected size of resulting sequence" );
1024 xRes
= new SwChartDataSource( aLDS
);
1031 sal_Bool SAL_CALL
SwChartDataProvider::createDataSourcePossible(
1032 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
1033 throw (uno::RuntimeException
)
1035 vos::OGuard
aGuard( Application::GetSolarMutex() );
1037 sal_Bool bPossible
= sal_True
;
1040 Impl_createDataSource( rArguments
, sal_True
);
1042 catch (lang::IllegalArgumentException
&)
1044 bPossible
= sal_False
;
1050 uno::Reference
< chart2::data::XDataSource
> SAL_CALL
SwChartDataProvider::createDataSource(
1051 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
1052 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1054 vos::OGuard
aGuard( Application::GetSolarMutex() );
1055 return Impl_createDataSource( rArguments
);
1058 ////////////////////////////////////////////////////////////
1059 // SwChartDataProvider::GetBrokenCellRangeForExport
1062 // we need to return a property that has the same value as the property
1063 // 'CellRangeRepresentation' but for all rows which are increased by one.
1064 // E.g. Table1:A1:D5 -> Table1:A2:D6
1065 // Since the problem is only for old charts which did not support multiple
1066 // we do not need to provide that property/string if the 'CellRangeRepresentation'
1067 // contains multiple ranges.
1068 OUString
SwChartDataProvider::GetBrokenCellRangeForExport(
1069 const OUString
&rCellRangeRepresentation
)
1073 // check that we do not have multiple ranges
1074 if (-1 == rCellRangeRepresentation
.indexOf( ';' ))
1076 // get current cell and table names
1077 String aTblName
, aStartCell
, aEndCell
;
1078 GetTableAndCellsFromRangeRep( rCellRangeRepresentation
,
1079 aTblName
, aStartCell
, aEndCell
, sal_False
);
1080 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1081 lcl_GetCellPosition( aStartCell
, nStartCol
, nStartRow
);
1082 lcl_GetCellPosition( aEndCell
, nEndCol
, nEndRow
);
1084 // get new cell names
1087 aStartCell
= lcl_GetCellName( nStartCol
, nStartRow
);
1088 aEndCell
= lcl_GetCellName( nEndCol
, nEndRow
);
1090 aRes
= GetRangeRepFromTableAndCells( aTblName
,
1091 aStartCell
, aEndCell
, sal_False
);
1097 uno::Sequence
< beans::PropertyValue
> SAL_CALL
SwChartDataProvider::detectArguments(
1098 const uno::Reference
< chart2::data::XDataSource
>& xDataSource
)
1099 throw (uno::RuntimeException
)
1101 vos::OGuard
aGuard( Application::GetSolarMutex() );
1103 throw lang::DisposedException();
1105 uno::Sequence
< beans::PropertyValue
> aResult
;
1106 if (!xDataSource
.is())
1109 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aDS_LDS( xDataSource
->getDataSequences() );
1110 const uno::Reference
< chart2::data::XLabeledDataSequence
> *pDS_LDS
= aDS_LDS
.getConstArray();
1111 sal_Int32 nNumDS_LDS
= aDS_LDS
.getLength();
1113 if (nNumDS_LDS
== 0)
1115 DBG_WARNING( "XLabeledDataSequence in data source contains 0 entries" );
1119 SwFrmFmt
*pTableFmt
= 0;
1120 SwTable
*pTable
= 0;
1122 sal_Int32 nTableRows
= 0;
1123 sal_Int32 nTableCols
= 0;
1125 // data used to build 'CellRangeRepresentation' from later on
1126 std::vector
< std::vector
< sal_Char
> > aMap
;
1128 uno::Sequence
< sal_Int32
> aSequenceMapping( nNumDS_LDS
);
1129 sal_Int32
*pSequenceMapping
= aSequenceMapping
.getArray();
1132 sal_Int16 nDtaSrcIsColumns
= -1;// -1: don't know yet, 0: false, 1: true -2: neither
1133 sal_Int32 nLabelSeqLen
= -1; // used to see if labels are always used or not and have
1134 // the expected size of 1 (i.e. if FirstCellAsLabel can
1136 // -1: don't know yet, 0: not used, 1: always a single labe cell, ...
1137 // -2: neither/failed
1138 // sal_Int32 nValuesSeqLen = -1; // used to see if all value sequences have the same size
1139 for (sal_Int32 nDS1
= 0; nDS1
< nNumDS_LDS
; ++nDS1
)
1141 uno::Reference
< chart2::data::XLabeledDataSequence
> xLabeledDataSequence( pDS_LDS
[nDS1
] );
1142 if( !xLabeledDataSequence
.is() )
1144 DBG_ERROR("got NULL for XLabeledDataSequence from Data source");
1147 const uno::Reference
< chart2::data::XDataSequence
> xCurLabel( xLabeledDataSequence
->getLabel(), uno::UNO_QUERY
);
1148 const uno::Reference
< chart2::data::XDataSequence
> xCurValues( xLabeledDataSequence
->getValues(), uno::UNO_QUERY
);
1150 // get sequence lengths for label and values.
1152 sal_Int32 nCurLabelSeqLen
= -1;
1153 sal_Int32 nCurValuesSeqLen
= -1;
1155 nCurLabelSeqLen
= xCurLabel
->getData().getLength();
1156 if (xCurValues
.is())
1157 nCurValuesSeqLen
= xCurValues
->getData().getLength();
1159 // check for consistent use of 'first cell as label'
1160 if (nLabelSeqLen
== -1) // set initial value to compare with below further on
1161 nLabelSeqLen
= nCurLabelSeqLen
;
1162 if (nLabelSeqLen
!= nCurLabelSeqLen
)
1163 nLabelSeqLen
= -2; // failed / no consistent use of label cells
1165 // get table and cell names for label and values data sequences
1166 // (start and end cell will be sorted, i.e. start cell <= end cell)
1167 String aLabelTblName
, aLabelStartCell
, aLabelEndCell
;
1168 String aValuesTblName
, aValuesStartCell
, aValuesEndCell
;
1169 String aLabelRange
, aValuesRange
;
1171 aLabelRange
= xCurLabel
->getSourceRangeRepresentation();
1172 if (xCurValues
.is())
1173 aValuesRange
= xCurValues
->getSourceRangeRepresentation();
1174 if ((aLabelRange
.Len() && !GetTableAndCellsFromRangeRep( aLabelRange
,
1175 aLabelTblName
, aLabelStartCell
, aLabelEndCell
)) ||
1176 !GetTableAndCellsFromRangeRep( aValuesRange
,
1177 aValuesTblName
, aValuesStartCell
, aValuesEndCell
))
1179 return aResult
; // failed -> return empty property sequence
1182 // make sure all sequences use the same table
1183 if (!aTableName
.Len())
1184 aTableName
= aValuesTblName
; // get initial value to compare with
1185 if (!aTableName
.Len() ||
1186 aTableName
!= aValuesTblName
||
1187 (aLabelTblName
.Len() && aTableName
!= aLabelTblName
))
1189 return aResult
; // failed -> return empty property sequence
1193 // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting
1194 // first and last cell used in both sequences
1196 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1197 String
aCell( aLabelStartCell
.Len() ? aLabelStartCell
: aValuesStartCell
);
1198 DBG_ASSERT( aCell
.Len() , "start cell missing?" );
1199 lcl_GetCellPosition( aCell
, nFirstCol
, nFirstRow
);
1200 lcl_GetCellPosition( aValuesEndCell
, nLastCol
, nLastRow
);
1202 sal_Int16 nDirection
= -1; // -1: not yet set, 0: columns, 1: rows, -2: failed
1203 if (nFirstCol
== nLastCol
&& nFirstRow
== nLastRow
) // a single cell...
1205 DBG_ASSERT( nCurLabelSeqLen
== 0 && nCurValuesSeqLen
== 1,
1206 "trying to determine 'DataRowSource': something's fishy... should have been a single cell");
1207 nDirection
= 0; // default direction for a single cell should be 'columns'
1209 else // more than one cell is availabale (in values and label together!)
1211 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1213 else if (nFirstCol
!= nLastCol
&& nFirstRow
== nLastRow
)
1217 DBG_ERROR( "trying to determine 'DataRowSource': unexpected case found" );
1221 // check for consistent direction of data source
1222 if (nDtaSrcIsColumns
== -1) // set initial value to compare with below
1223 nDtaSrcIsColumns
= nDirection
;
1224 if (nDtaSrcIsColumns
!= nDirection
)
1226 nDtaSrcIsColumns
= -2; // failed
1230 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1232 // build data to obtain 'SequenceMapping' later on
1234 DBG_ASSERT( nDtaSrcIsColumns
== 0 || /* rows */
1235 nDtaSrcIsColumns
== 1, /* columns */
1236 "unexpected value for 'nDtaSrcIsColumns'" );
1237 pSequenceMapping
[nDS1
] = nDtaSrcIsColumns
? nFirstCol
: nFirstRow
;
1240 // build data used to determine 'CellRangeRepresentation' later on
1242 GetTableByName( *pDoc
, aTableName
, &pTableFmt
, &pTable
);
1243 if (!pTable
|| pTable
->IsTblComplex())
1244 return aResult
; // failed -> return empty property sequence
1245 nTableRows
= pTable
->GetTabLines().Count();
1246 nTableCols
= pTable
->GetTabLines().GetObject(0)->GetTabBoxes().Count();
1247 aMap
.resize( nTableRows
);
1248 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1249 aMap
[i
].resize( nTableCols
);
1251 if (aLabelStartCell
.Len() && aLabelEndCell
.Len())
1253 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1254 lcl_GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1255 lcl_GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1256 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1257 nStartCol
< 0 || nEndCol
>= nTableCols
)
1259 return aResult
; // failed -> return empty property sequence
1261 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1263 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1265 sal_Char
&rChar
= aMap
[i
][k
];
1266 if (rChar
== '\0') // check for overlapping values and/or labels
1269 return aResult
; // failed -> return empty property sequence
1273 if (aValuesStartCell
.Len() && aValuesEndCell
.Len())
1275 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1276 lcl_GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1277 lcl_GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1278 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1279 nStartCol
< 0 || nEndCol
>= nTableCols
)
1281 return aResult
; // failed -> return empty property sequence
1283 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1285 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1287 sal_Char
&rChar
= aMap
[i
][k
];
1288 if (rChar
== '\0') // check for overlapping values and/or labels
1291 return aResult
; // failed -> return empty property sequence
1297 #if OSL_DEBUG_LEVEL > 1
1298 // do some extra sanity checking that the length of the sequences
1299 // matches their range representation
1301 sal_Int32 nStartRow
= -1, nStartCol
= -1, nEndRow
= -1, nEndCol
= -1;
1304 lcl_GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1305 lcl_GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1306 DBG_ASSERT( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurLabel
->getData().getLength()) ||
1307 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurLabel
->getData().getLength()),
1308 "label sequence length does not match range representation!" );
1310 if (xCurValues
.is())
1312 lcl_GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1313 lcl_GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1314 DBG_ASSERT( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurValues
->getData().getLength()) ||
1315 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurValues
->getData().getLength()),
1316 "value sequence length does not match range representation!" );
1323 // build value for 'CellRangeRepresentation'
1325 String
aCellRangeBase( aTableName
);
1326 aCellRangeBase
+= '.';
1328 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1330 for (sal_Int32 k
= 0; k
< nTableCols
; ++k
)
1332 if (aMap
[i
][k
] != '\0') // top-left cell of a sub-range found
1334 // find rectangular sub-range to use
1335 sal_Int32 nRowIndex1
= i
; // row index
1336 sal_Int32 nColIndex1
= k
; // column index
1337 sal_Int32 nRowSubLen
= 0;
1338 sal_Int32 nColSubLen
= 0;
1339 while (nRowIndex1
< nTableRows
&& aMap
[nRowIndex1
++][k
] != '\0')
1341 // be aware of shifted sequences!
1342 // (according to the checks done prior the length should be ok)
1343 while (nColIndex1
< nTableCols
&& aMap
[i
][nColIndex1
] != '\0'
1344 && aMap
[i
+ nRowSubLen
-1][nColIndex1
] != '\0')
1349 String
aStartCell( lcl_GetCellName( k
, i
) );
1350 String
aEndCell( lcl_GetCellName( k
+ nColSubLen
- 1, i
+ nRowSubLen
- 1) );
1351 aCurRange
= aCellRangeBase
;
1352 aCurRange
+= aStartCell
;
1354 aCurRange
+= aEndCell
;
1355 if (aCellRanges
.Len())
1357 aCellRanges
+= aCurRange
;
1359 // clear already found sub-range from map
1360 for (sal_Int32 nRowIndex2
= 0; nRowIndex2
< nRowSubLen
; ++nRowIndex2
)
1361 for (sal_Int32 nColumnIndex2
= 0; nColumnIndex2
< nColSubLen
; ++nColumnIndex2
)
1362 aMap
[i
+ nRowIndex2
][k
+ nColumnIndex2
] = '\0';
1366 // to be nice to the user we now sort the cell ranges according to
1367 // rows or columns depending on the direction used in the data source
1368 uno::Sequence
< OUString
> aSortedRanges
;
1369 GetSubranges( aCellRanges
, aSortedRanges
, sal_False
/*sub ranges should already be normalized*/ );
1370 SortSubranges( aSortedRanges
, (nDtaSrcIsColumns
== 1) );
1371 sal_Int32 nSortedRanges
= aSortedRanges
.getLength();
1372 const OUString
*pSortedRanges
= aSortedRanges
.getConstArray();
1373 OUString aSortedCellRanges
;
1374 for (sal_Int32 i
= 0; i
< nSortedRanges
; ++i
)
1376 if (aSortedCellRanges
.getLength())
1377 aSortedCellRanges
+= OUString::valueOf( (sal_Unicode
) ';');
1378 aSortedCellRanges
+= pSortedRanges
[i
];
1382 // build value for 'SequenceMapping'
1384 uno::Sequence
< sal_Int32
> aSortedMapping( aSequenceMapping
);
1385 sal_Int32
*pSortedMapping
= aSortedMapping
.getArray();
1386 std::sort( pSortedMapping
, pSortedMapping
+ aSortedMapping
.getLength() );
1387 DBG_ASSERT( aSortedMapping
.getLength() == nNumDS_LDS
, "unexpected size of sequence" );
1388 sal_Bool bNeedSequenceMapping
= sal_False
;
1389 for (sal_Int32 i
= 0; i
< nNumDS_LDS
; ++i
)
1391 sal_Int32
*pIt
= std::find( pSortedMapping
, pSortedMapping
+ nNumDS_LDS
,
1392 pSequenceMapping
[i
] );
1393 DBG_ASSERT( pIt
, "index not found" );
1395 return aResult
; // failed -> return empty property sequence
1396 pSequenceMapping
[i
] = pIt
- pSortedMapping
;
1398 if (i
!= pSequenceMapping
[i
])
1399 bNeedSequenceMapping
= sal_True
;
1402 // check if 'SequenceMapping' is actually not required...
1403 // (don't write unnecessary properties to the XML file)
1404 if (!bNeedSequenceMapping
)
1405 aSequenceMapping
.realloc(0);
1408 #ifdef TL_NOT_USED // in the end chart2 did not want to have the sequence minimized
1409 // try to shorten the 'SequenceMapping' as much as possible
1411 for (k
= nNumDS_LDS
- 1; k
>= 0; --k
)
1413 if (pSequenceMapping
[k
] != k
)
1416 aSequenceMapping
.realloc( k
+ 1 );
1421 // build resulting properties
1423 DBG_ASSERT(nLabelSeqLen
>= 0 || nLabelSeqLen
== -2 /*not used*/,
1424 "unexpected value for 'nLabelSeqLen'" );
1425 sal_Bool bFirstCellIsLabel
= sal_False
; // default value if 'nLabelSeqLen' could not properly determined
1426 if (nLabelSeqLen
> 0) // == 0 means no label sequence in use
1427 bFirstCellIsLabel
= sal_True
;
1429 DBG_ASSERT( aSortedCellRanges
.getLength(), "CellRangeRepresentation missing" );
1430 OUString
aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges
) );
1433 sal_Int32 nProps
= 0;
1434 aResult
[nProps
].Name
= C2U("FirstCellAsLabel");
1435 aResult
[nProps
++].Value
<<= bFirstCellIsLabel
;
1436 aResult
[nProps
].Name
= C2U("CellRangeRepresentation");
1437 aResult
[nProps
++].Value
<<= aSortedCellRanges
;
1438 if (0 != aBrokenCellRangeForExport
.getLength())
1440 aResult
[nProps
].Name
= C2U("BrokenCellRangeForExport");
1441 aResult
[nProps
++].Value
<<= aBrokenCellRangeForExport
;
1443 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1445 chart::ChartDataRowSource eDataRowSource
= (nDtaSrcIsColumns
== 1) ?
1446 chart::ChartDataRowSource_COLUMNS
: chart::ChartDataRowSource_ROWS
;
1447 aResult
[nProps
].Name
= C2U("DataRowSource");
1448 aResult
[nProps
++].Value
<<= eDataRowSource
;
1450 if (aSequenceMapping
.getLength() != 0)
1452 aResult
[nProps
].Name
= C2U("SequenceMapping");
1453 aResult
[nProps
++].Value
<<= aSequenceMapping
;
1456 aResult
.realloc( nProps
);
1461 uno::Reference
< chart2::data::XDataSequence
> SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation(
1462 const OUString
& rRangeRepresentation
, sal_Bool bTestOnly
)
1463 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1466 throw lang::DisposedException();
1468 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
1469 SwUnoCrsr
*pUnoCrsr
= 0; // pointer to new created cursor spanning the cell range
1470 GetFormatAndCreateCursorFromRangeRep( pDoc
, rRangeRepresentation
,
1471 &pTblFmt
, &pUnoCrsr
);
1472 if (!pTblFmt
|| !pUnoCrsr
)
1473 throw lang::IllegalArgumentException();
1475 // check that cursors point and mark are in a single row or column.
1476 String
aCellRange( GetCellRangeName( *pTblFmt
, *pUnoCrsr
) );
1477 SwRangeDescriptor aDesc
;
1478 FillRangeDescriptor( aDesc
, aCellRange
);
1479 if (aDesc
.nTop
!= aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1480 throw lang::IllegalArgumentException();
1482 DBG_ASSERT( pTblFmt
&& pUnoCrsr
, "table format or cursor missing" );
1483 uno::Reference
< chart2::data::XDataSequence
> xDataSeq
;
1485 xDataSeq
= new SwChartDataSequence( *this, *pTblFmt
, pUnoCrsr
);
1490 sal_Bool SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentationPossible(
1491 const OUString
& rRangeRepresentation
)
1492 throw (uno::RuntimeException
)
1494 vos::OGuard
aGuard( Application::GetSolarMutex() );
1496 sal_Bool bPossible
= sal_True
;
1499 Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
, sal_True
);
1501 catch (lang::IllegalArgumentException
&)
1503 bPossible
= sal_False
;
1509 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentation(
1510 const OUString
& rRangeRepresentation
)
1511 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1513 vos::OGuard
aGuard( Application::GetSolarMutex() );
1514 return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
);
1518 uno::Reference
< sheet::XRangeSelection
> SAL_CALL
SwChartDataProvider::getRangeSelection( )
1519 throw (uno::RuntimeException
)
1521 // note: it is no error to return nothing here
1522 return uno::Reference
< sheet::XRangeSelection
>();
1526 void SAL_CALL
SwChartDataProvider::dispose( )
1527 throw (uno::RuntimeException
)
1529 sal_Bool
bMustDispose( sal_False
);
1531 osl::MutexGuard
aGuard( GetChartMutex() );
1532 bMustDispose
= !bDisposed
;
1534 bDisposed
= sal_True
;
1538 // dispose all data-sequences
1539 Map_Set_DataSequenceRef_t::iterator
aIt( aDataSequences
.begin() );
1540 while (aIt
!= aDataSequences
.end())
1542 DisposeAllDataSequences( (*aIt
).first
);
1545 // release all references to data-sequences
1546 aDataSequences
.clear();
1548 // require listeners to release references to this object
1549 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XDataSequence
* >(this) );
1550 aEvtListeners
.disposeAndClear( aEvtObj
);
1555 void SAL_CALL
SwChartDataProvider::addEventListener(
1556 const uno::Reference
< lang::XEventListener
>& rxListener
)
1557 throw (uno::RuntimeException
)
1559 osl::MutexGuard
aGuard( GetChartMutex() );
1560 if (!bDisposed
&& rxListener
.is())
1561 aEvtListeners
.addInterface( rxListener
);
1565 void SAL_CALL
SwChartDataProvider::removeEventListener(
1566 const uno::Reference
< lang::XEventListener
>& rxListener
)
1567 throw (uno::RuntimeException
)
1569 osl::MutexGuard
aGuard( GetChartMutex() );
1570 if (!bDisposed
&& rxListener
.is())
1571 aEvtListeners
.removeInterface( rxListener
);
1576 OUString SAL_CALL
SwChartDataProvider::getImplementationName( )
1577 throw (uno::RuntimeException
)
1579 return C2U("SwChartDataProvider");
1583 sal_Bool SAL_CALL
SwChartDataProvider::supportsService(
1584 const OUString
& rServiceName
)
1585 throw (uno::RuntimeException
)
1587 vos::OGuard
aGuard( Application::GetSolarMutex() );
1588 return rServiceName
.equalsAscii( SN_DATA_PROVIDER
);
1592 uno::Sequence
< OUString
> SAL_CALL
SwChartDataProvider::getSupportedServiceNames( )
1593 throw (uno::RuntimeException
)
1595 vos::OGuard
aGuard( Application::GetSolarMutex() );
1596 uno::Sequence
< OUString
> aRes(1);
1597 aRes
.getArray()[0] = C2U( SN_DATA_PROVIDER
);
1602 void SwChartDataProvider::Modify( SfxPoolItem
*pOld
, SfxPoolItem
*pNew
)
1604 // actually this function should be superfluous (need to check later)
1605 ClientModify(this, pOld
, pNew
);
1609 void SwChartDataProvider::AddDataSequence( const SwTable
&rTable
, uno::Reference
< chart2::data::XDataSequence
> &rxDataSequence
)
1611 aDataSequences
[ &rTable
].insert( rxDataSequence
);
1615 void SwChartDataProvider::RemoveDataSequence( const SwTable
&rTable
, uno::Reference
< chart2::data::XDataSequence
> &rxDataSequence
)
1617 aDataSequences
[ &rTable
].erase( rxDataSequence
);
1621 void SwChartDataProvider::InvalidateTable( const SwTable
*pTable
)
1623 DBG_ASSERT( pTable
, "table pointer is NULL" );
1627 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1629 const Set_DataSequenceRef_t
&rSet
= aDataSequences
[ pTable
];
1630 Set_DataSequenceRef_t::iterator
aIt( rSet
.begin() );
1631 while (aIt
!= rSet
.end())
1633 // uno::Reference< util::XModifiable > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY );
1634 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1635 uno::Reference
< util::XModifiable
> xRef( xTemp
, uno::UNO_QUERY
);
1638 // mark the sequence as 'dirty' and notify listeners
1639 xRef
->setModified( sal_True
);
1647 sal_Bool
SwChartDataProvider::DeleteBox( const SwTable
*pTable
, const SwTableBox
&rBox
)
1649 sal_Bool bRes
= sal_False
;
1650 DBG_ASSERT( pTable
, "table pointer is NULL" );
1654 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1656 Set_DataSequenceRef_t
&rSet
= aDataSequences
[ pTable
];
1658 // iterate over all data-sequences for that table...
1659 Set_DataSequenceRef_t::iterator
aIt( rSet
.begin() );
1660 Set_DataSequenceRef_t::iterator
aEndIt( rSet
.end() );
1661 Set_DataSequenceRef_t::iterator aDelIt
; // iterator used for deletion when appropriate
1662 while (aIt
!= aEndIt
)
1664 SwChartDataSequence
*pDataSeq
= 0;
1665 sal_Bool bNowEmpty
= sal_False
;
1667 // check if weak reference is still valid...
1668 // uno::Reference< chart2::data::XDataSequence > xRef( uno::Reference< chart2::data::XDataSequence>(*aIt), uno::UNO_QUERY );
1669 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1670 uno::Reference
< chart2::data::XDataSequence
> xRef( xTemp
, uno::UNO_QUERY
);
1673 // then delete that table box (check if implementation cursor needs to be adjusted)
1674 pDataSeq
= static_cast< SwChartDataSequence
* >( xRef
.get() );
1677 #if OSL_DEBUG_LEVEL > 1
1678 OUString
aRangeStr( pDataSeq
->getSourceRangeRepresentation() );
1680 bNowEmpty
= pDataSeq
->DeleteBox( rBox
);
1689 rSet
.erase( aDelIt
);
1691 pDataSeq
->dispose(); // the current way to tell chart that sth. got removed
1699 void SwChartDataProvider::DisposeAllDataSequences( const SwTable
*pTable
)
1701 DBG_ASSERT( pTable
, "table pointer is NULL" );
1705 pTable
->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1707 //! make a copy of the STL container!
1708 //! This is necessary since calling 'dispose' will implicitly remove an element
1709 //! of the original container, and thus any iterator in the original container
1710 //! would become invalid.
1711 const Set_DataSequenceRef_t
aSet( aDataSequences
[ pTable
] );
1713 Set_DataSequenceRef_t::iterator
aIt( aSet
.begin() );
1714 Set_DataSequenceRef_t::iterator
aEndIt( aSet
.end() );
1715 while (aIt
!= aEndIt
)
1717 // uno::Reference< lang::XComponent > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY );
1718 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1719 uno::Reference
< lang::XComponent
> xRef( xTemp
, uno::UNO_QUERY
);
1730 ////////////////////////////////////////
1731 // SwChartDataProvider::AddRowCols tries to notify charts of added columns
1732 // or rows and extends the value sequence respectively (if possible).
1733 // If those can be added to the end of existing value data-sequences those
1734 // sequences get mofdified accordingly and will send a modification
1735 // notification (calling 'setModified').
1737 // Since this function is a work-around for non existent Writer core functionality
1738 // (no arbitrary multi-selection in tables that can be used to define a
1739 // data-sequence) this function will be somewhat unreliable.
1740 // For example we will only try to adapt value sequences. For this we assume
1741 // that a sequence of length 1 is a label sequence and those with length >= 2
1742 // we presume to be value sequences. Also new cells can only be added in the
1743 // direction the value sequence is already pointing (rows / cols) and at the
1744 // start or end of the values data-sequence.
1745 // Nothing needs to be done if the new cells are in between the table cursors
1746 // point and mark since data-sequence are considered to consist of all cells
1748 // New rows/cols need to be added already to the table before calling
1751 void SwChartDataProvider::AddRowCols(
1752 const SwTable
&rTable
,
1753 const SwSelBoxes
& rBoxes
,
1754 USHORT nLines
, BOOL bBehind
)
1756 if (rTable
.IsTblComplex())
1759 const USHORT nBoxes
= rBoxes
.Count();
1760 if (nBoxes
< 1 || nLines
< 1)
1763 SwTableBox
* pFirstBox
= *( rBoxes
.GetData() + 0 );
1764 SwTableBox
* pLastBox
= *( rBoxes
.GetData() + nBoxes
- 1 );
1766 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1767 if (pFirstBox
&& pLastBox
)
1769 lcl_GetCellPosition( pFirstBox
->GetName(), nFirstCol
, nFirstRow
);
1770 lcl_GetCellPosition( pLastBox
->GetName(), nLastCol
, nLastRow
);
1772 bool bAddCols
= false; // default; also to be used if nBoxes == 1 :-/
1773 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1775 if (nFirstCol
== nLastCol
|| nFirstRow
== nLastRow
)
1777 //get range of indices in col/rows for new cells
1778 sal_Int32 nFirstNewCol
= nFirstCol
;
1779 sal_Int32 nLastNewCol
= nLastCol
;
1780 sal_Int32 nFirstNewRow
= bBehind
? nFirstRow
+ 1 : nFirstRow
- nLines
;
1781 sal_Int32 nLastNewRow
= nFirstNewRow
- 1 + nLines
;
1784 DBG_ASSERT( nFirstCol
== nLastCol
, "column indices seem broken" );
1785 nFirstNewCol
= bBehind
? nFirstCol
+ 1 : nFirstCol
- nLines
;
1786 nLastNewCol
= nFirstNewCol
- 1 + nLines
;
1787 nFirstNewRow
= nFirstRow
;
1788 nLastNewRow
= nLastRow
;
1791 // iterate over all data-sequences for the table
1792 const Set_DataSequenceRef_t
&rSet
= aDataSequences
[ &rTable
];
1793 Set_DataSequenceRef_t::iterator
aIt( rSet
.begin() );
1794 while (aIt
!= rSet
.end())
1796 // uno::Reference< chart2::data::XTextualDataSequence > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY );
1797 uno::Reference
< chart2::data::XDataSequence
> xTemp(*aIt
); // temporary needed for g++ 3.3.5
1798 uno::Reference
< chart2::data::XTextualDataSequence
> xRef( xTemp
, uno::UNO_QUERY
);
1801 const sal_Int32 nLen
= xRef
->getTextualData().getLength();
1802 if (nLen
> 1) // value data-sequence ?
1804 SwChartDataSequence
*pDataSeq
= 0;
1805 uno::Reference
< lang::XUnoTunnel
> xTunnel( xRef
, uno::UNO_QUERY
);
1808 pDataSeq
= reinterpret_cast< SwChartDataSequence
* >(
1809 sal::static_int_cast
< sal_IntPtr
>( xTunnel
->getSomething( SwChartDataSequence::getUnoTunnelId() )));
1813 SwRangeDescriptor aDesc
;
1814 pDataSeq
->FillRangeDesc( aDesc
);
1816 chart::ChartDataRowSource eDRSource
= chart::ChartDataRowSource_COLUMNS
;
1817 if (aDesc
.nTop
== aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1818 eDRSource
= chart::ChartDataRowSource_ROWS
;
1820 if (!bAddCols
&& eDRSource
== chart::ChartDataRowSource_COLUMNS
)
1822 // add rows: extend affected columns by newly added row cells
1823 pDataSeq
->ExtendTo( true, nFirstNewRow
, nLines
);
1825 else if (bAddCols
&& eDRSource
== chart::ChartDataRowSource_ROWS
)
1827 // add cols: extend affected rows by newly added column cells
1828 pDataSeq
->ExtendTo( false, nFirstNewCol
, nLines
);
1842 // XRangeXMLConversion ---------------------------------------------------
1844 rtl::OUString SAL_CALL
SwChartDataProvider::convertRangeToXML( const rtl::OUString
& rRangeRepresentation
)
1845 throw ( uno::RuntimeException
, lang::IllegalArgumentException
)
1847 vos::OGuard
aGuard( Application::GetSolarMutex() );
1849 throw lang::DisposedException();
1852 String
aRangeRepresentation( rRangeRepresentation
);
1854 // multiple ranges are delimeted by a ';' like in
1855 // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges!
1856 xub_StrLen nNumRanges
= aRangeRepresentation
.GetTokenCount( ';' );
1857 SwTable
* pFirstFoundTable
= 0; // to check that only one table will be used
1858 for (USHORT i
= 0; i
< nNumRanges
; ++i
)
1860 String
aRange( aRangeRepresentation
.GetToken(i
, ';') );
1861 SwFrmFmt
*pTblFmt
= 0; // pointer to table format
1862 // BM: For what should the check be necessary? for #i79009# it is required that NO check is done
1863 // SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist
1864 // std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr
1865 GetFormatAndCreateCursorFromRangeRep( pDoc
, aRange
, &pTblFmt
, NULL
);
1867 throw lang::IllegalArgumentException();
1869 // throw uno::RuntimeException();
1870 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
1871 if (pTable
->IsTblComplex())
1872 throw uno::RuntimeException();
1874 // check that there is only one table used in all ranges
1875 if (!pFirstFoundTable
)
1876 pFirstFoundTable
= pTable
;
1877 if (pTable
!= pFirstFoundTable
)
1878 throw lang::IllegalArgumentException();
1883 if (!GetTableAndCellsFromRangeRep( aRange
, aTblName
, aStartCell
, aEndCell
))
1884 throw lang::IllegalArgumentException();
1886 sal_Int32 nCol
, nRow
;
1887 lcl_GetCellPosition( aStartCell
, nCol
, nRow
);
1888 if (nCol
< 0 || nRow
< 0)
1889 throw uno::RuntimeException();
1891 //!! following objects/functions are implemented in XMLRangeHelper.?xx
1892 //!! which is a copy of the respective file from chart2 !!
1893 XMLRangeHelper::CellRange aCellRange
;
1894 aCellRange
.aTableName
= aTblName
;
1895 aCellRange
.aUpperLeft
.nColumn
= nCol
;
1896 aCellRange
.aUpperLeft
.nRow
= nRow
;
1897 aCellRange
.aUpperLeft
.bIsEmpty
= false;
1898 if (aStartCell
!= aEndCell
&& aEndCell
.Len() != 0)
1900 lcl_GetCellPosition( aEndCell
, nCol
, nRow
);
1901 if (nCol
< 0 || nRow
< 0)
1902 throw uno::RuntimeException();
1904 aCellRange
.aLowerRight
.nColumn
= nCol
;
1905 aCellRange
.aLowerRight
.nRow
= nRow
;
1906 aCellRange
.aLowerRight
.bIsEmpty
= false;
1908 String
aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange
) );
1909 if (aRes
.Len()) // in case of multiple ranges add delimeter
1910 aRes
.AppendAscii( " " );
1917 rtl::OUString SAL_CALL
SwChartDataProvider::convertRangeFromXML( const rtl::OUString
& rXMLRange
)
1918 throw ( uno::RuntimeException
, lang::IllegalArgumentException
)
1920 vos::OGuard
aGuard( Application::GetSolarMutex() );
1922 throw lang::DisposedException();
1925 String
aXMLRange( rXMLRange
);
1927 // multiple ranges are delimeted by a ' ' like in
1928 // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges!
1929 xub_StrLen nNumRanges
= aXMLRange
.GetTokenCount( ' ' );
1930 rtl::OUString aFirstFoundTable
; // to check that only one table will be used
1931 for (USHORT i
= 0; i
< nNumRanges
; ++i
)
1933 String
aRange( aXMLRange
.GetToken(i
, ' ') );
1935 //!! following objects and function are implemented in XMLRangeHelper.?xx
1936 //!! which is a copy of the respective file from chart2 !!
1937 XMLRangeHelper::CellRange
aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange
));
1939 // check that there is only one table used in all ranges
1940 if (aFirstFoundTable
.getLength() == 0)
1941 aFirstFoundTable
= aCellRange
.aTableName
;
1942 if (aCellRange
.aTableName
!= aFirstFoundTable
)
1943 throw lang::IllegalArgumentException();
1945 OUString
aTmp( aCellRange
.aTableName
);
1946 aTmp
+= OUString::valueOf((sal_Unicode
) '.');
1947 aTmp
+= lcl_GetCellName( aCellRange
.aUpperLeft
.nColumn
,
1948 aCellRange
.aUpperLeft
.nRow
);
1949 // does cell range consist of more than a single cell?
1950 if (!aCellRange
.aLowerRight
.bIsEmpty
)
1952 aTmp
+= OUString::valueOf((sal_Unicode
) ':');
1953 aTmp
+= lcl_GetCellName( aCellRange
.aLowerRight
.nColumn
,
1954 aCellRange
.aLowerRight
.nRow
);
1957 if (aRes
.Len()) // in case of multiple ranges add delimeter
1958 aRes
.AppendAscii( ";" );
1959 aRes
+= String(aTmp
);
1966 //////////////////////////////////////////////////////////////////////
1968 SwChartDataSource::SwChartDataSource(
1969 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > &rLDS
) :
1975 SwChartDataSource::~SwChartDataSource()
1981 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > SAL_CALL
SwChartDataSource::getDataSequences( )
1982 throw (uno::RuntimeException
)
1984 vos::OGuard
aGuard( Application::GetSolarMutex() );
1989 OUString SAL_CALL
SwChartDataSource::getImplementationName( )
1990 throw (uno::RuntimeException
)
1992 vos::OGuard
aGuard( Application::GetSolarMutex() );
1993 return C2U("SwChartDataSource");
1997 sal_Bool SAL_CALL
SwChartDataSource::supportsService(
1998 const OUString
& rServiceName
)
1999 throw (uno::RuntimeException
)
2001 vos::OGuard
aGuard( Application::GetSolarMutex() );
2002 return rServiceName
.equalsAscii( SN_DATA_SOURCE
);
2006 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSource::getSupportedServiceNames( )
2007 throw (uno::RuntimeException
)
2009 vos::OGuard
aGuard( Application::GetSolarMutex() );
2010 uno::Sequence
< OUString
> aRes(1);
2011 aRes
.getArray()[0] = C2U( SN_DATA_SOURCE
);
2015 //////////////////////////////////////////////////////////////////////
2017 SwChartDataSequence::SwChartDataSequence(
2018 SwChartDataProvider
&rProvider
,
2020 SwUnoCrsr
*pTableCursor
) :
2021 SwClient( &rTblFmt
),
2022 aEvtListeners( GetChartMutex() ),
2023 aModifyListeners( GetChartMutex() ),
2024 aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT
) ),
2025 aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT
) ),
2026 xDataProvider( &rProvider
),
2027 pDataProvider( &rProvider
),
2028 pTblCrsr( pTableCursor
),
2029 aCursorDepend( this, pTableCursor
),
2030 _pPropSet( aSwMapProvider
.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE
) )
2032 bDisposed
= sal_False
;
2037 const SwTable
* pTable
= SwTable::FindTable( &rTblFmt
);
2040 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
2041 pDataProvider
->AddDataSequence( *pTable
, xRef
);
2042 pDataProvider
->addEventListener( dynamic_cast< lang::XEventListener
* >(this) );
2045 DBG_ERROR( "table missing" );
2048 catch (uno::RuntimeException
&)
2052 catch (uno::Exception
&)
2057 #if OSL_DEBUG_LEVEL > 1
2058 OUString
aRangeStr( getSourceRangeRepresentation() );
2060 // check if it can properly convert into a SwUnoTableCrsr
2061 // which is required for some functions
2062 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
2063 DBG_ASSERT(pUnoTblCrsr
, "SwChartDataSequence: cursor not SwUnoTableCrsr");
2068 SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence
&rObj
) :
2069 SwChartDataSequenceBaseClass(),
2070 SwClient( rObj
.GetFrmFmt() ),
2071 aEvtListeners( GetChartMutex() ),
2072 aModifyListeners( GetChartMutex() ),
2073 aRole( rObj
.aRole
),
2074 aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT
) ),
2075 aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT
) ),
2076 xDataProvider( rObj
.pDataProvider
),
2077 pDataProvider( rObj
.pDataProvider
),
2078 pTblCrsr( rObj
.pTblCrsr
->Clone() ),
2079 aCursorDepend( this, pTblCrsr
),
2080 _pPropSet( rObj
._pPropSet
)
2082 bDisposed
= sal_False
;
2087 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2090 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
2091 pDataProvider
->AddDataSequence( *pTable
, xRef
);
2092 pDataProvider
->addEventListener( dynamic_cast< lang::XEventListener
* >(this) );
2095 DBG_ERROR( "table missing" );
2098 catch (uno::RuntimeException
&)
2102 catch (uno::Exception
&)
2107 #if OSL_DEBUG_LEVEL > 1
2108 OUString
aRangeStr( getSourceRangeRepresentation() );
2110 // check if it can properly convert into a SwUnoTableCrsr
2111 // which is required for some functions
2112 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
2113 DBG_ASSERT(pUnoTblCrsr
, "SwChartDataSequence: cursor not SwUnoTableCrsr");
2118 SwChartDataSequence::~SwChartDataSequence()
2120 // since the data-provider holds only weak references to the data-sequence
2121 // there should be no need here to release them explicitly...
2127 const uno::Sequence
< sal_Int8
> & SwChartDataSequence::getUnoTunnelId()
2129 static uno::Sequence
< sal_Int8
> aSeq
= ::CreateUnoTunnelId();
2134 sal_Int64 SAL_CALL
SwChartDataSequence::getSomething( const uno::Sequence
< sal_Int8
> &rId
)
2135 throw(uno::RuntimeException
)
2137 if( rId
.getLength() == 16
2138 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
2139 rId
.getConstArray(), 16 ) )
2141 return sal::static_int_cast
< sal_Int64
>( reinterpret_cast< sal_IntPtr
>(this) );
2147 uno::Sequence
< uno::Any
> SAL_CALL
SwChartDataSequence::getData( )
2148 throw (uno::RuntimeException
)
2150 vos::OGuard
aGuard( Application::GetSolarMutex() );
2152 throw lang::DisposedException();
2154 uno::Sequence
< uno::Any
> aRes
;
2155 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2158 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2159 if(!pTable
->IsTblComplex())
2161 SwRangeDescriptor aDesc
;
2162 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2164 //!! make copy of pTblCrsr (SwUnoCrsr )
2165 // keep original cursor and make copy of it that gets handed
2166 // over to the SwXCellRange object which takes ownership and
2167 // thus will destroy the copy later.
2168 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2169 aRange
.GetDataSequence( &aRes
, 0, 0 );
2177 OUString SAL_CALL
SwChartDataSequence::getSourceRangeRepresentation( )
2178 throw (uno::RuntimeException
)
2180 vos::OGuard
aGuard( Application::GetSolarMutex() );
2182 throw lang::DisposedException();
2185 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2188 aRes
= pTblFmt
->GetName();
2189 String
aCellRange( GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2190 DBG_ASSERT( aCellRange
.Len() != 0, "failed to get cell range" );
2191 aRes
+= (sal_Unicode
) '.';
2197 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::generateLabel(
2198 chart2::data::LabelOrigin eLabelOrigin
)
2199 throw (uno::RuntimeException
)
2201 vos::OGuard
aGuard( Application::GetSolarMutex() );
2203 throw lang::DisposedException();
2205 uno::Sequence
< OUString
> aLabels
;
2208 SwRangeDescriptor aDesc
;
2209 sal_Bool bOk sal_False
;
2210 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2211 SwTable
* pTable
= pTblFmt
? SwTable::FindTable( pTblFmt
) : 0;
2212 if (!pTblFmt
|| !pTable
|| pTable
->IsTblComplex())
2213 throw uno::RuntimeException();
2216 String
aCellRange( GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2217 DBG_ASSERT( aCellRange
.Len() != 0, "failed to get cell range" );
2218 bOk
= FillRangeDescriptor( aDesc
, aCellRange
);
2219 DBG_ASSERT( bOk
, "falied to get SwRangeDescriptor" );
2224 sal_Int32 nColSpan
= aDesc
.nRight
- aDesc
.nLeft
+ 1;
2225 sal_Int32 nRowSpan
= aDesc
.nBottom
- aDesc
.nTop
+ 1;
2226 DBG_ASSERT( nColSpan
== 1 || nRowSpan
== 1,
2227 "unexpected range of selected cells" );
2229 String aTxt
; // label text to be returned
2230 sal_Bool bReturnEmptyTxt
= sal_False
;
2231 sal_Bool bUseCol
= sal_True
;
2232 if (eLabelOrigin
== chart2::data::LabelOrigin_COLUMN
)
2234 else if (eLabelOrigin
== chart2::data::LabelOrigin_ROW
)
2235 bUseCol
= sal_False
;
2236 else if (eLabelOrigin
== chart2::data::LabelOrigin_SHORT_SIDE
)
2238 bUseCol
= nColSpan
< nRowSpan
;
2239 bReturnEmptyTxt
= nColSpan
== nRowSpan
;
2241 else if (eLabelOrigin
== chart2::data::LabelOrigin_LONG_SIDE
)
2243 bUseCol
= nColSpan
> nRowSpan
;
2244 bReturnEmptyTxt
= nColSpan
== nRowSpan
;
2247 DBG_ERROR( "unexpected case" );
2250 // build label sequence
2252 sal_Int32 nSeqLen
= bUseCol
? nColSpan
: nRowSpan
;
2253 aLabels
.realloc( nSeqLen
);
2254 OUString
*pLabels
= aLabels
.getArray();
2255 for (sal_Int32 i
= 0; i
< nSeqLen
; ++i
)
2257 if (!bReturnEmptyTxt
)
2259 aTxt
= bUseCol
? aColLabelText
: aRowLabelText
;
2260 sal_Int32 nCol
= aDesc
.nLeft
;
2261 sal_Int32 nRow
= aDesc
.nTop
;
2266 String
aCellName( lcl_GetCellName( nCol
, nRow
) );
2268 xub_StrLen nLen
= aCellName
.Len();
2271 const sal_Unicode
*pBuf
= aCellName
.GetBuffer();
2272 const sal_Unicode
*pEnd
= pBuf
+ nLen
;
2273 while (pBuf
< pEnd
&& !('0' <= *pBuf
&& *pBuf
<= '9'))
2275 // start of number found?
2276 if (pBuf
< pEnd
&& ('0' <= *pBuf
&& *pBuf
<= '9'))
2282 aRplc
= String::CreateFromAscii( "%COLUMNLETTER" );
2283 aNew
= String( aCellName
.GetBuffer(), static_cast<xub_StrLen
>(pBuf
- aCellName
.GetBuffer()) );
2287 aRplc
= String::CreateFromAscii( "%ROWNUMBER" );
2288 aNew
= String( pBuf
, static_cast<xub_StrLen
>((aCellName
.GetBuffer() + nLen
) - pBuf
) );
2290 xub_StrLen nPos
= aTxt
.Search( aRplc
);
2291 if (nPos
!= STRING_NOTFOUND
)
2292 aTxt
= aTxt
.Replace( nPos
, aRplc
.Len(), aNew
);
2304 ::sal_Int32 SAL_CALL
SwChartDataSequence::getNumberFormatKeyByIndex(
2305 ::sal_Int32
/*nIndex*/ )
2306 throw (lang::IndexOutOfBoundsException
,
2307 uno::RuntimeException
)
2314 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getTextualData( )
2315 throw (uno::RuntimeException
)
2317 vos::OGuard
aGuard( Application::GetSolarMutex() );
2319 throw lang::DisposedException();
2321 uno::Sequence
< OUString
> aRes
;
2322 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2325 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2326 if(!pTable
->IsTblComplex())
2328 SwRangeDescriptor aDesc
;
2329 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2331 //!! make copy of pTblCrsr (SwUnoCrsr )
2332 // keep original cursor and make copy of it that gets handed
2333 // over to the SwXCellRange object which takes ownership and
2334 // thus will destroy the copy later.
2335 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2336 aRange
.GetDataSequence( 0, &aRes
, 0 );
2344 uno::Sequence
< double > SAL_CALL
SwChartDataSequence::getNumericalData( )
2345 throw (uno::RuntimeException
)
2347 vos::OGuard
aGuard( Application::GetSolarMutex() );
2349 throw lang::DisposedException();
2351 uno::Sequence
< double > aRes
;
2352 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2355 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2356 if(!pTable
->IsTblComplex())
2358 SwRangeDescriptor aDesc
;
2359 if (FillRangeDescriptor( aDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) ))
2361 //!! make copy of pTblCrsr (SwUnoCrsr )
2362 // keep original cursor and make copy of it that gets handed
2363 // over to the SwXCellRange object which takes ownership and
2364 // thus will destroy the copy later.
2365 SwXCellRange
aRange( pTblCrsr
->Clone(), *pTblFmt
, aDesc
);
2367 // get numerical values and make an effort to return the
2368 // numerical value for text formatted cells
2369 aRange
.GetDataSequence( 0, 0, &aRes
, sal_True
);
2377 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartDataSequence::createClone( )
2378 throw (uno::RuntimeException
)
2380 vos::OGuard
aGuard( Application::GetSolarMutex() );
2382 throw lang::DisposedException();
2383 return new SwChartDataSequence( *this );
2387 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
SwChartDataSequence::getPropertySetInfo( )
2388 throw (uno::RuntimeException
)
2390 vos::OGuard
aGuard( Application::GetSolarMutex() );
2392 throw lang::DisposedException();
2394 static uno::Reference
< beans::XPropertySetInfo
> xRes
= _pPropSet
->getPropertySetInfo();
2399 void SAL_CALL
SwChartDataSequence::setPropertyValue(
2400 const OUString
& rPropertyName
,
2401 const uno::Any
& rValue
)
2402 throw (beans::UnknownPropertyException
, beans::PropertyVetoException
, lang::IllegalArgumentException
, lang::WrappedTargetException
, uno::RuntimeException
)
2404 vos::OGuard
aGuard( Application::GetSolarMutex() );
2406 throw lang::DisposedException();
2408 if (rPropertyName
.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE
)))
2410 if ( !(rValue
>>= aRole
) )
2411 throw lang::IllegalArgumentException();
2414 throw beans::UnknownPropertyException();
2418 uno::Any SAL_CALL
SwChartDataSequence::getPropertyValue(
2419 const OUString
& rPropertyName
)
2420 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2422 vos::OGuard
aGuard( Application::GetSolarMutex() );
2424 throw lang::DisposedException();
2427 if (rPropertyName
.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE
)))
2430 throw beans::UnknownPropertyException();
2436 void SAL_CALL
SwChartDataSequence::addPropertyChangeListener(
2437 const OUString
& /*rPropertyName*/,
2438 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2439 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2441 //vos::OGuard aGuard( Application::GetSolarMutex() );
2442 DBG_ERROR( "not implemented" );
2446 void SAL_CALL
SwChartDataSequence::removePropertyChangeListener(
2447 const OUString
& /*rPropertyName*/,
2448 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2449 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2451 //vos::OGuard aGuard( Application::GetSolarMutex() );
2452 DBG_ERROR( "not implemented" );
2456 void SAL_CALL
SwChartDataSequence::addVetoableChangeListener(
2457 const OUString
& /*rPropertyName*/,
2458 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2459 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2461 //vos::OGuard aGuard( Application::GetSolarMutex() );
2462 DBG_ERROR( "not implemented" );
2466 void SAL_CALL
SwChartDataSequence::removeVetoableChangeListener(
2467 const OUString
& /*rPropertyName*/,
2468 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2469 throw (beans::UnknownPropertyException
, lang::WrappedTargetException
, uno::RuntimeException
)
2471 //vos::OGuard aGuard( Application::GetSolarMutex() );
2472 DBG_ERROR( "not implemented" );
2476 OUString SAL_CALL
SwChartDataSequence::getImplementationName( )
2477 throw (uno::RuntimeException
)
2479 return C2U("SwChartDataSequence");
2483 sal_Bool SAL_CALL
SwChartDataSequence::supportsService(
2484 const OUString
& rServiceName
)
2485 throw (uno::RuntimeException
)
2487 return rServiceName
.equalsAscii( SN_DATA_SEQUENCE
);
2491 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getSupportedServiceNames( )
2492 throw (uno::RuntimeException
)
2494 vos::OGuard
aGuard( Application::GetSolarMutex() );
2495 uno::Sequence
< OUString
> aRes(1);
2496 aRes
.getArray()[0] = C2U( SN_DATA_SEQUENCE
);
2501 void SwChartDataSequence::Modify( SfxPoolItem
*pOld
, SfxPoolItem
*pNew
)
2503 ClientModify(this, pOld
, pNew
);
2505 // table was deleted or cursor was deleted
2506 if(!GetRegisteredIn() || !aCursorDepend
.GetRegisteredIn())
2513 setModified( sal_True
);
2518 sal_Bool SAL_CALL
SwChartDataSequence::isModified( )
2519 throw (uno::RuntimeException
)
2521 vos::OGuard
aGuard( Application::GetSolarMutex() );
2523 throw lang::DisposedException();
2529 void SAL_CALL
SwChartDataSequence::setModified(
2530 ::sal_Bool bModified
)
2531 throw (beans::PropertyVetoException
, uno::RuntimeException
)
2533 vos::OGuard
aGuard( Application::GetSolarMutex() );
2535 throw lang::DisposedException();
2538 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2542 void SAL_CALL
SwChartDataSequence::addModifyListener(
2543 const uno::Reference
< util::XModifyListener
>& rxListener
)
2544 throw (uno::RuntimeException
)
2546 osl::MutexGuard
aGuard( GetChartMutex() );
2547 if (!bDisposed
&& rxListener
.is())
2548 aModifyListeners
.addInterface( rxListener
);
2552 void SAL_CALL
SwChartDataSequence::removeModifyListener(
2553 const uno::Reference
< util::XModifyListener
>& rxListener
)
2554 throw (uno::RuntimeException
)
2556 osl::MutexGuard
aGuard( GetChartMutex() );
2557 if (!bDisposed
&& rxListener
.is())
2558 aModifyListeners
.removeInterface( rxListener
);
2562 void SAL_CALL
SwChartDataSequence::disposing( const lang::EventObject
& rSource
)
2563 throw (uno::RuntimeException
)
2566 throw lang::DisposedException();
2567 if (rSource
.Source
== xDataProvider
)
2570 xDataProvider
.clear();
2575 void SAL_CALL
SwChartDataSequence::dispose( )
2576 throw (uno::RuntimeException
)
2578 sal_Bool
bMustDispose( sal_False
);
2580 osl::MutexGuard
aGuard( GetChartMutex() );
2581 bMustDispose
= !bDisposed
;
2583 bDisposed
= sal_True
;
2587 bDisposed
= sal_True
;
2590 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2593 uno::Reference
< chart2::data::XDataSequence
> xRef( dynamic_cast< chart2::data::XDataSequence
* >(this), uno::UNO_QUERY
);
2594 pDataProvider
->RemoveDataSequence( *pTable
, xRef
);
2597 DBG_ERROR( "table missing" );
2601 // require listeners to release references to this object
2602 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XDataSequence
* >(this) );
2603 aModifyListeners
.disposeAndClear( aEvtObj
);
2604 aEvtListeners
.disposeAndClear( aEvtObj
);
2609 void SAL_CALL
SwChartDataSequence::addEventListener(
2610 const uno::Reference
< lang::XEventListener
>& rxListener
)
2611 throw (uno::RuntimeException
)
2613 osl::MutexGuard
aGuard( GetChartMutex() );
2614 if (!bDisposed
&& rxListener
.is())
2615 aEvtListeners
.addInterface( rxListener
);
2619 void SAL_CALL
SwChartDataSequence::removeEventListener(
2620 const uno::Reference
< lang::XEventListener
>& rxListener
)
2621 throw (uno::RuntimeException
)
2623 osl::MutexGuard
aGuard( GetChartMutex() );
2624 if (!bDisposed
&& rxListener
.is())
2625 aEvtListeners
.removeInterface( rxListener
);
2629 sal_Bool
SwChartDataSequence::DeleteBox( const SwTableBox
&rBox
)
2631 #if OSL_DEBUG_LEVEL > 1
2632 String
aBoxName( rBox
.GetName() );
2635 // to be set if the last box of the data-sequence was removed here
2636 sal_Bool bNowEmpty
= sal_False
;
2638 // if the implementation cursor gets affected (i.e. thew box where it is located
2639 // in gets removed) we need to move it before that... (otherwise it does not need to change)
2641 const SwStartNode
* pPointStartNode
= pTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
2642 const SwStartNode
* pMarkStartNode
= pTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
2644 if (!pTblCrsr
->HasMark() || (pPointStartNode
== rBox
.GetSttNd() && pMarkStartNode
== rBox
.GetSttNd()))
2646 bNowEmpty
= sal_True
;
2648 else if (pPointStartNode
== rBox
.GetSttNd() || pMarkStartNode
== rBox
.GetSttNd())
2650 sal_Int32 nPointRow
= -1, nPointCol
= -1;
2651 sal_Int32 nMarkRow
= -1, nMarkCol
= -1;
2652 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2653 String
aPointCellName( pTable
->GetTblBox( pPointStartNode
->GetIndex() )->GetName() );
2654 String
aMarkCellName( pTable
->GetTblBox( pMarkStartNode
->GetIndex() )->GetName() );
2656 lcl_GetCellPosition( aPointCellName
, nPointCol
, nPointRow
);
2657 lcl_GetCellPosition( aMarkCellName
, nMarkCol
, nMarkRow
);
2658 DBG_ASSERT( nPointRow
>= 0 && nPointCol
>= 0, "invalid row and col" );
2659 DBG_ASSERT( nMarkRow
>= 0 && nMarkCol
>= 0, "invalid row and col" );
2661 // move vertical or horizontal?
2662 DBG_ASSERT( nPointRow
== nMarkRow
|| nPointCol
== nMarkCol
,
2663 "row/col indices not matching" );
2664 DBG_ASSERT( nPointRow
!= nMarkRow
|| nPointCol
!= nMarkCol
,
2665 "point and mark are identical" );
2666 sal_Bool bMoveVertical
= (nPointCol
== nMarkCol
);
2667 sal_Bool bMoveHorizontal
= (nPointRow
== nMarkRow
);
2669 // get movement direction
2670 sal_Bool bMoveLeft
= sal_False
; // move left or right?
2671 sal_Bool bMoveUp
= sal_False
; // move up or down?
2674 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2675 bMoveUp
= nPointRow
> nMarkRow
;
2677 bMoveUp
= nMarkRow
> nPointRow
;
2679 else if (bMoveHorizontal
)
2681 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2682 bMoveLeft
= nPointCol
> nMarkCol
;
2684 bMoveLeft
= nMarkCol
> nPointCol
;
2687 DBG_ERROR( "neither vertical nor horizontal movement" );
2690 // get new box (position) to use...
2691 sal_Int32 nRow
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointRow
: nMarkRow
;
2692 sal_Int32 nCol
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointCol
: nMarkCol
;
2694 nRow
+= bMoveUp
? -1 : +1;
2695 if (bMoveHorizontal
)
2696 nCol
+= bMoveLeft
? -1 : +1;
2697 String aNewCellName
= lcl_GetCellName( nCol
, nRow
);
2698 SwTableBox
* pNewBox
= (SwTableBox
*) pTable
->GetTblBox( aNewCellName
);
2700 if (pNewBox
) // set new position (cell range) to use
2702 // So erhält man den ersten Inhaltsnode in einer gegebenen Zelle:
2703 // Zunächst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box...
2704 SwNodeIndex
aIdx( *pNewBox
->GetSttNd(), +1 );
2705 // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein,
2706 // deshalb das GoNext;
2707 SwCntntNode
*pCNd
= aIdx
.GetNode().GetCntntNode();
2709 pCNd
= GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx
);
2710 //und damit kann man z.B. eine SwPosition erzeugen:
2711 SwPosition
aNewPos( *pCNd
); // new position to beused with cursor
2713 // if the mark is to be changed make sure there is one...
2714 if (pMarkStartNode
== rBox
.GetSttNd() && !pTblCrsr
->HasMark())
2715 pTblCrsr
->SetMark();
2717 // set cursor to new position...
2718 SwPosition
*pPos
= (pPointStartNode
== rBox
.GetSttNd()) ?
2719 pTblCrsr
->GetPoint() : pTblCrsr
->GetMark();
2722 pPos
->nNode
= aNewPos
.nNode
;
2723 pPos
->nContent
= aNewPos
.nContent
;
2726 DBG_ERROR( "neither point nor mark available for change" );
2730 DBG_ERROR( "failed to get position" );
2738 void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor
&rRangeDesc
) const
2740 SwFrmFmt
* pTblFmt
= GetFrmFmt();
2743 SwTable
* pTable
= SwTable::FindTable( pTblFmt
);
2744 if(!pTable
->IsTblComplex())
2746 FillRangeDescriptor( rRangeDesc
, GetCellRangeName( *pTblFmt
, *pTblCrsr
) );
2752 SwChartDataSequence::ExtendTo
2754 extends the data-sequence by new cells added at the end of the direction
2755 the data-sequence points to.
2756 If the cells are already within the range of the sequence nothing needs
2758 If the cells are beyond the end of the sequence (are not adjacent to the
2759 current last cell) nothing can be done. Only if the cells are adjacent to
2760 the last cell they can be added.
2762 @returns true if the data-sequence was changed.
2764 specifies if columns or rows are to be extended
2766 index of first new row/col to be included in data-sequence
2768 index of last new row/col to be included in data-sequence
2770 bool SwChartDataSequence::ExtendTo( bool bExtendCol
,
2771 sal_Int32 nFirstNew
, sal_Int32 nCount
)
2773 bool bChanged
= false;
2775 SwUnoTableCrsr
* pUnoTblCrsr
= dynamic_cast<SwUnoTableCrsr
*>(pTblCrsr
);
2776 //pUnoTblCrsr->MakeBoxSels();
2778 const SwStartNode
*pStartNd
= 0;
2779 const SwTableBox
*pStartBox
= 0;
2780 const SwTableBox
*pEndBox
= 0;
2782 const SwTable
* pTable
= SwTable::FindTable( GetFrmFmt() );
2783 DBG_ASSERT( !pTable
->IsTblComplex(), "table too complex" );
2784 if (nCount
< 1 || nFirstNew
< 0 || pTable
->IsTblComplex())
2788 // get range descriptor (cell range) for current data-sequence
2790 pStartNd
= pUnoTblCrsr
->GetPoint()->nNode
.GetNode().FindTableBoxStartNode();
2791 pEndBox
= pTable
->GetTblBox( pStartNd
->GetIndex() );
2792 const String
aEndBox( pEndBox
->GetName() );
2794 pStartNd
= pUnoTblCrsr
->GetMark()->nNode
.GetNode().FindTableBoxStartNode();
2795 pStartBox
= pTable
->GetTblBox( pStartNd
->GetIndex() );
2796 const String
aStartBox( pStartBox
->GetName() );
2798 String
aCellRange( aStartBox
); // note that cell range here takes the newly added rows/cols already into account
2799 aCellRange
.AppendAscii( ":" );
2800 aCellRange
+= aEndBox
;
2801 SwRangeDescriptor aDesc
;
2802 FillRangeDescriptor( aDesc
, aCellRange
);
2804 String aNewStartCell
;
2806 if (bExtendCol
&& aDesc
.nBottom
+ 1 == nFirstNew
)
2808 // new column cells adjacent to the bottom of the
2809 // current data-sequence to be added...
2810 DBG_ASSERT( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2811 aNewStartCell
= lcl_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2812 aNewEndCell
= lcl_GetCellName(aDesc
.nRight
, aDesc
.nBottom
+ nCount
);
2815 else if (bExtendCol
&& aDesc
.nTop
- nCount
== nFirstNew
)
2817 // new column cells adjacent to the top of the
2818 // current data-sequence to be added...
2819 DBG_ASSERT( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2820 aNewStartCell
= lcl_GetCellName(aDesc
.nLeft
, aDesc
.nTop
- nCount
);
2821 aNewEndCell
= lcl_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2824 else if (!bExtendCol
&& aDesc
.nRight
+ 1 == nFirstNew
)
2826 // new row cells adjacent to the right of the
2827 // current data-sequence to be added...
2828 DBG_ASSERT( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2829 aNewStartCell
= lcl_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2830 aNewEndCell
= lcl_GetCellName(aDesc
.nRight
+ nCount
, aDesc
.nBottom
);
2833 else if (!bExtendCol
&& aDesc
.nLeft
- nCount
== nFirstNew
)
2835 // new row cells adjacent to the left of the
2836 // current data-sequence to be added...
2837 DBG_ASSERT( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2838 aNewStartCell
= lcl_GetCellName(aDesc
.nLeft
- nCount
, aDesc
.nTop
);
2839 aNewEndCell
= lcl_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2845 // move table cursor to new start and end of data-sequence
2846 const SwTableBox
*pNewStartBox
= pTable
->GetTblBox( aNewStartCell
);
2847 const SwTableBox
*pNewEndBox
= pTable
->GetTblBox( aNewEndCell
);
2848 pUnoTblCrsr
->SetMark();
2849 pUnoTblCrsr
->GetPoint()->nNode
= *pNewEndBox
->GetSttNd();
2850 pUnoTblCrsr
->GetMark()->nNode
= *pNewStartBox
->GetSttNd();
2851 pUnoTblCrsr
->Move( fnMoveForward
, fnGoNode
);
2852 pUnoTblCrsr
->MakeBoxSels();
2858 //////////////////////////////////////////////////////////////////////
2860 SwChartLabeledDataSequence::SwChartLabeledDataSequence() :
2861 aEvtListeners( GetChartMutex() ),
2862 aModifyListeners( GetChartMutex() )
2864 bDisposed
= sal_False
;
2868 SwChartLabeledDataSequence::~SwChartLabeledDataSequence()
2873 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getValues( )
2874 throw (uno::RuntimeException
)
2876 vos::OGuard
aGuard( Application::GetSolarMutex() );
2878 throw lang::DisposedException();
2883 void SwChartLabeledDataSequence::SetDataSequence(
2884 uno::Reference
< chart2::data::XDataSequence
>& rxDest
,
2885 const uno::Reference
< chart2::data::XDataSequence
>& rxSource
)
2887 uno::Reference
< util::XModifyListener
> xML( dynamic_cast< util::XModifyListener
* >(this), uno::UNO_QUERY
);
2888 uno::Reference
< lang::XEventListener
> xEL( dynamic_cast< lang::XEventListener
* >(this), uno::UNO_QUERY
);
2890 // stop listening to old data-sequence
2891 uno::Reference
< util::XModifyBroadcaster
> xMB( rxDest
, uno::UNO_QUERY
);
2893 xMB
->removeModifyListener( xML
);
2894 uno::Reference
< lang::XComponent
> xC( rxDest
, uno::UNO_QUERY
);
2896 xC
->removeEventListener( xEL
);
2900 // start listening to new data-sequence
2901 xC
= uno::Reference
< lang::XComponent
>( rxDest
, uno::UNO_QUERY
);
2903 xC
->addEventListener( xEL
);
2904 xMB
= uno::Reference
< util::XModifyBroadcaster
>( rxDest
, uno::UNO_QUERY
);
2906 xMB
->addModifyListener( xML
);
2910 void SAL_CALL
SwChartLabeledDataSequence::setValues(
2911 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2912 throw (uno::RuntimeException
)
2914 vos::OGuard
aGuard( Application::GetSolarMutex() );
2916 throw lang::DisposedException();
2918 if (xData
!= rxSequence
)
2920 SetDataSequence( xData
, rxSequence
);
2921 // inform listeners of changes
2922 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2927 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getLabel( )
2928 throw (uno::RuntimeException
)
2930 vos::OGuard
aGuard( Application::GetSolarMutex() );
2932 throw lang::DisposedException();
2937 void SAL_CALL
SwChartLabeledDataSequence::setLabel(
2938 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2939 throw (uno::RuntimeException
)
2941 vos::OGuard
aGuard( Application::GetSolarMutex() );
2943 throw lang::DisposedException();
2945 if (xLabels
!= rxSequence
)
2947 SetDataSequence( xLabels
, rxSequence
);
2948 // inform listeners of changes
2949 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
2954 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartLabeledDataSequence::createClone( )
2955 throw (uno::RuntimeException
)
2957 vos::OGuard
aGuard( Application::GetSolarMutex() );
2959 throw lang::DisposedException();
2961 uno::Reference
< util::XCloneable
> xRes
;
2963 uno::Reference
< util::XCloneable
> xDataCloneable( xData
, uno::UNO_QUERY
);
2964 uno::Reference
< util::XCloneable
> xLabelsCloneable( xLabels
, uno::UNO_QUERY
);
2965 SwChartLabeledDataSequence
*pRes
= new SwChartLabeledDataSequence();
2966 if (xDataCloneable
.is())
2968 uno::Reference
< chart2::data::XDataSequence
> xDataClone( xDataCloneable
->createClone(), uno::UNO_QUERY
);
2969 pRes
->setValues( xDataClone
);
2972 if (xLabelsCloneable
.is())
2974 uno::Reference
< chart2::data::XDataSequence
> xLabelsClone( xLabelsCloneable
->createClone(), uno::UNO_QUERY
);
2975 pRes
->setLabel( xLabelsClone
);
2982 OUString SAL_CALL
SwChartLabeledDataSequence::getImplementationName( )
2983 throw (uno::RuntimeException
)
2985 return C2U("SwChartLabeledDataSequence");
2989 sal_Bool SAL_CALL
SwChartLabeledDataSequence::supportsService(
2990 const OUString
& rServiceName
)
2991 throw (uno::RuntimeException
)
2993 return rServiceName
.equalsAscii( SN_LABELED_DATA_SEQUENCE
);
2997 uno::Sequence
< OUString
> SAL_CALL
SwChartLabeledDataSequence::getSupportedServiceNames( )
2998 throw (uno::RuntimeException
)
3000 vos::OGuard
aGuard( Application::GetSolarMutex() );
3001 uno::Sequence
< OUString
> aRes(1);
3002 aRes
.getArray()[0] = C2U( SN_LABELED_DATA_SEQUENCE
);
3007 void SAL_CALL
SwChartLabeledDataSequence::disposing(
3008 const lang::EventObject
& rSource
)
3009 throw (uno::RuntimeException
)
3011 osl::MutexGuard
aGuard( GetChartMutex() );
3012 uno::Reference
< uno::XInterface
> xRef( rSource
.Source
);
3015 if (xRef
== xLabels
)
3017 if (!xData
.is() && !xLabels
.is())
3022 void SAL_CALL
SwChartLabeledDataSequence::modified(
3023 const lang::EventObject
& rEvent
)
3024 throw (uno::RuntimeException
)
3026 if (rEvent
.Source
== xData
|| rEvent
.Source
== xLabels
)
3028 LaunchModifiedEvent( aModifyListeners
, dynamic_cast< XModifyBroadcaster
* >(this) );
3033 void SAL_CALL
SwChartLabeledDataSequence::addModifyListener(
3034 const uno::Reference
< util::XModifyListener
>& rxListener
)
3035 throw (uno::RuntimeException
)
3037 osl::MutexGuard
aGuard( GetChartMutex() );
3038 if (!bDisposed
&& rxListener
.is())
3039 aModifyListeners
.addInterface( rxListener
);
3043 void SAL_CALL
SwChartLabeledDataSequence::removeModifyListener(
3044 const uno::Reference
< util::XModifyListener
>& rxListener
)
3045 throw (uno::RuntimeException
)
3047 osl::MutexGuard
aGuard( GetChartMutex() );
3048 if (!bDisposed
&& rxListener
.is())
3049 aModifyListeners
.removeInterface( rxListener
);
3053 void SAL_CALL
SwChartLabeledDataSequence::dispose( )
3054 throw (uno::RuntimeException
)
3056 sal_Bool
bMustDispose( sal_False
);
3058 osl::MutexGuard
aGuard( GetChartMutex() );
3059 bMustDispose
= !bDisposed
;
3061 bDisposed
= sal_True
;
3065 bDisposed
= sal_True
;
3067 // require listeners to release references to this object
3068 lang::EventObject
aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence
* >(this) );
3069 aModifyListeners
.disposeAndClear( aEvtObj
);
3070 aEvtListeners
.disposeAndClear( aEvtObj
);
3075 void SAL_CALL
SwChartLabeledDataSequence::addEventListener(
3076 const uno::Reference
< lang::XEventListener
>& rxListener
)
3077 throw (uno::RuntimeException
)
3079 osl::MutexGuard
aGuard( GetChartMutex() );
3080 if (!bDisposed
&& rxListener
.is())
3081 aEvtListeners
.addInterface( rxListener
);
3085 void SAL_CALL
SwChartLabeledDataSequence::removeEventListener(
3086 const uno::Reference
< lang::XEventListener
>& rxListener
)
3087 throw (uno::RuntimeException
)
3089 osl::MutexGuard
aGuard( GetChartMutex() );
3090 if (!bDisposed
&& rxListener
.is())
3091 aEvtListeners
.removeInterface( rxListener
);
3094 //////////////////////////////////////////////////////////////////////