1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <string_view>
23 #include <com/sun/star/chart/ChartDataRowSource.hpp>
24 #include <com/sun/star/chart2/data/LabelOrigin.hpp>
25 #include <com/sun/star/embed/XEmbeddedObject.hpp>
26 #include <com/sun/star/frame/XModel.hpp>
27 #include <comphelper/diagnose_ex.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <o3tl/deleter.hxx>
30 #include <o3tl/string_view.hxx>
32 #include <vcl/svapp.hxx>
34 #include "XMLRangeHelper.hxx"
35 #include <unochart.hxx>
36 #include <swtable.hxx>
37 #include <unoprnms.hxx>
39 #include <unocrsr.hxx>
42 #include <IDocumentChartDataProviderAccess.hxx>
45 #include <swtypes.hxx>
46 #include <strings.hrc>
47 #include <comphelper/servicehelper.hxx>
48 #include <comphelper/string.hxx>
49 #include <svl/itemprop.hxx>
51 using namespace ::com::sun::star
;
53 void SwChartHelper::DoUpdateAllCharts( SwDoc
* pDoc
)
60 SwNodeIndex
aIdx( *pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
61 while( nullptr != (pStNd
= aIdx
.GetNode().GetStartNode()) )
64 if (nullptr != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
65 pONd
->GetOLEObj().GetObject().IsChart() )
67 // Load the object and set modified
69 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
70 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
74 uno::Reference
< util::XModifiable
> xModif( xIP
->getComponent(), uno::UNO_QUERY
);
76 xModif
->setModified( true );
78 catch ( uno::Exception
& )
84 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
88 SwChartLockController_Helper::SwChartLockController_Helper( SwDoc
*pDocument
) :
90 , m_aUnlockTimer( "sw::SwChartLockController_Helper aUnlockTimer" )
91 , m_bIsLocked( false )
93 m_aUnlockTimer
.SetTimeout( 1500 );
94 m_aUnlockTimer
.SetInvokeHandler( LINK( this, SwChartLockController_Helper
, DoUnlockAllCharts
));
97 SwChartLockController_Helper::~SwChartLockController_Helper()
99 if (m_pDoc
) // still connected?
100 suppress_fun_call_w_exception(Disconnect());
103 void SwChartLockController_Helper::StartOrContinueLocking()
107 m_aUnlockTimer
.Start(); // start or continue time of locking
110 void SwChartLockController_Helper::Disconnect()
112 m_aUnlockTimer
.Stop();
117 void SwChartLockController_Helper::LockUnlockAllCharts( bool bLock
)
122 uno::Reference
< frame::XModel
> xRes
;
125 SwNodeIndex
aIdx( *m_pDoc
->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
126 while( nullptr != (pStNd
= aIdx
.GetNode().GetStartNode()) )
129 if (nullptr != ( pONd
= aIdx
.GetNode().GetOLENode() ) &&
130 !pONd
->GetChartTableName().isEmpty() /* is chart object? */)
132 uno::Reference
< embed::XEmbeddedObject
> xIP
= pONd
->GetOLEObj().GetOleRef();
133 if ( svt::EmbeddedObjectRef::TryRunningState( xIP
) )
135 xRes
.set( xIP
->getComponent(), uno::UNO_QUERY
);
139 xRes
->lockControllers();
141 xRes
->unlockControllers();
145 aIdx
.Assign( *pStNd
->EndOfSectionNode(), + 1 );
151 IMPL_LINK_NOARG( SwChartLockController_Helper
, DoUnlockAllCharts
, Timer
*, void )
156 static std::mutex
& GetChartMutex()
158 static std::mutex aMutex
;
162 static void LaunchModifiedEvent(
163 ::comphelper::OInterfaceContainerHelper4
<util::XModifyListener
> &rICH
,
164 const uno::Reference
< uno::XInterface
> &rxI
)
166 lang::EventObject
aEvtObj( rxI
);
167 std::unique_lock
aGuard(GetChartMutex());
168 rICH
.notifyEach( aGuard
, &util::XModifyListener::modified
, aEvtObj
);
172 * rCellRangeName needs to be of one of the following formats:
174 * - e.g. "Table1.A2:E5"
176 bool FillRangeDescriptor(
177 SwRangeDescriptor
&rDesc
,
178 std::u16string_view rCellRangeName
)
180 sal_Int32 nToken
= std::u16string_view::npos
== rCellRangeName
.find('.') ? 0 : 1;
181 std::u16string_view
aCellRangeNoTableName( o3tl::getToken(rCellRangeName
, nToken
, '.' ) );
182 OUString
aTLName( o3tl::getToken(aCellRangeNoTableName
, 0, ':') ); // name of top left cell
183 OUString
aBRName( o3tl::getToken(aCellRangeNoTableName
, 1, ':') ); // name of bottom right cell
184 if(aTLName
.isEmpty() || aBRName
.isEmpty())
187 rDesc
.nTop
= rDesc
.nLeft
= rDesc
.nBottom
= rDesc
.nRight
= -1;
188 SwXTextTable::GetCellPosition( aTLName
, rDesc
.nLeft
, rDesc
.nTop
);
189 SwXTextTable::GetCellPosition( aBRName
, rDesc
.nRight
, rDesc
.nBottom
);
191 OSL_ENSURE( rDesc
.nTop
!= -1 &&
193 rDesc
.nBottom
!= -1 &&
195 "failed to get range descriptor" );
196 OSL_ENSURE( rDesc
.nTop
<= rDesc
.nBottom
&& rDesc
.nLeft
<= rDesc
.nRight
,
197 "invalid range descriptor");
201 static OUString
GetCellRangeName( const SwFrameFormat
&rTableFormat
, SwUnoCursor
&rTableCursor
)
205 //!! see also SwXTextTableCursor::getRangeName
207 SwUnoTableCursor
* pUnoTableCursor
= dynamic_cast<SwUnoTableCursor
*>(&rTableCursor
);
208 if (!pUnoTableCursor
)
211 // tdf#132714 empty outdated selection cache to avoid crashing in ActualizeSelection()
212 size_t nCount
= pUnoTableCursor
->GetSelectedBoxesCount();
214 pUnoTableCursor
->DeleteBox(nCount
);
216 pUnoTableCursor
->MakeBoxSels();
218 const SwStartNode
* pStart
;
219 const SwTableBox
* pStartBox
= nullptr;
220 const SwTableBox
* pEndBox
= nullptr;
222 pStart
= pUnoTableCursor
->GetPoint()->GetNode().FindTableBoxStartNode();
225 const SwTable
* pTable
= SwTable::FindTable( &rTableFormat
);
226 pEndBox
= pTable
->GetTableBox( pStart
->GetIndex());
227 aRes
= pEndBox
->GetName();
229 if(pUnoTableCursor
->HasMark())
231 pStart
= pUnoTableCursor
->GetMark()->GetNode().FindTableBoxStartNode();
232 pStartBox
= pTable
->GetTableBox( pStart
->GetIndex());
234 OSL_ENSURE( pStartBox
, "start box not found" );
235 OSL_ENSURE( pEndBox
, "end box not found" );
237 // need to switch start and end?
238 if (*pUnoTableCursor
->GetPoint() < *pUnoTableCursor
->GetMark())
240 const SwTableBox
* pTmpBox
= pStartBox
;
248 aRes
= pStartBox
->GetName() + ":";
250 aRes
+= pEndBox
->GetName();
252 aRes
+= pStartBox
->GetName();
258 static OUString
GetRangeRepFromTableAndCells( std::u16string_view rTableName
,
259 std::u16string_view rStartCell
, std::u16string_view rEndCell
,
260 bool bForceEndCellName
)
262 OSL_ENSURE( !rTableName
.empty(), "table name missing" );
263 OSL_ENSURE( !rStartCell
.empty(), "cell name missing" );
264 OUString aRes
= OUString::Concat(rTableName
) + "." + rStartCell
;
266 if (!rEndCell
.empty())
268 aRes
+= OUString::Concat(":") + rEndCell
;
270 else if (bForceEndCellName
)
272 aRes
+= OUString::Concat(":") + rStartCell
;
278 static bool GetTableAndCellsFromRangeRep(
279 std::u16string_view rRangeRepresentation
,
280 OUString
&rTableName
,
281 OUString
&rStartCell
,
283 bool bSortStartEndCells
= true )
285 // parse range representation for table name and cell/range names
286 // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2"
287 OUString aTableName
; // table name
288 OUString aStartCell
; // name of top left cell
289 OUString aEndCell
; // name of bottom right cell
290 size_t nIdx
= rRangeRepresentation
.find( '.' );
291 if (nIdx
!= std::u16string_view::npos
)
293 aTableName
= rRangeRepresentation
.substr( 0, nIdx
);
294 std::u16string_view aRange
= rRangeRepresentation
.substr( nIdx
+ 1 ); // cell range
295 size_t nPos
= aRange
.find( ':' );
296 if (nPos
!= std::u16string_view::npos
) // a cell-range like "Table1.A2:D4"
298 aStartCell
= aRange
.substr( 0, nPos
);
299 aEndCell
= aRange
.substr( nPos
+ 1 );
301 // need to switch start and end cell ?
302 // (does not check for normalization here)
303 if (bSortStartEndCells
&& 1 == sw_CompareCellsByColFirst( aStartCell
, aEndCell
))
304 std::swap(aStartCell
, aEndCell
);
306 else // a single cell like in "Table1.B3"
308 aStartCell
= aEndCell
= aRange
;
312 bool bSuccess
= !aTableName
.isEmpty() &&
313 !aStartCell
.isEmpty() && !aEndCell
.isEmpty();
316 rTableName
= aTableName
;
317 rStartCell
= aStartCell
;
323 static void GetTableByName( const SwDoc
&rDoc
, std::u16string_view rTableName
,
324 SwFrameFormat
**ppTableFormat
, SwTable
**ppTable
)
326 SwFrameFormat
*pTableFormat
= nullptr;
328 // find frame format of table
329 //! see SwXTextTables::getByName
330 const size_t nCount
= rDoc
.GetTableFrameFormatCount(true);
331 for (size_t i
= 0; i
< nCount
&& !pTableFormat
; ++i
)
333 SwFrameFormat
& rTableFormat
= rDoc
.GetTableFrameFormat(i
, true);
334 if(rTableName
== rTableFormat
.GetName())
335 pTableFormat
= &rTableFormat
;
339 *ppTableFormat
= pTableFormat
;
342 *ppTable
= pTableFormat
? SwTable::FindTable( pTableFormat
) : nullptr;
345 static void GetFormatAndCreateCursorFromRangeRep(
347 std::u16string_view rRangeRepresentation
, // must be a single range (i.e. so called sub-range)
348 SwFrameFormat
**ppTableFormat
, // will be set to the table format of the table used in the range representation
349 std::shared_ptr
<SwUnoCursor
>& rpUnoCursor
) // will be set to cursor spanning the cell range (cursor will be created!)
351 OUString aTableName
; // table name
352 OUString aStartCell
; // name of top left cell
353 OUString aEndCell
; // name of bottom right cell
354 bool bNamesFound
= GetTableAndCellsFromRangeRep( rRangeRepresentation
,
355 aTableName
, aStartCell
, aEndCell
);
360 *ppTableFormat
= nullptr;
365 SwFrameFormat
*pTableFormat
= nullptr;
367 // is the correct table format already provided?
368 if (*ppTableFormat
!= nullptr && (*ppTableFormat
)->GetName() == aTableName
)
369 pTableFormat
= *ppTableFormat
;
371 GetTableByName( *pDoc
, aTableName
, &pTableFormat
, nullptr );
373 *ppTableFormat
= pTableFormat
;
375 rpUnoCursor
.reset(); // default result in case of failure
377 SwTable
*pTable
= pTableFormat
? SwTable::FindTable( pTableFormat
) : nullptr;
378 // create new SwUnoCursor spanning the specified range
379 //! see also SwXTextTable::GetRangeByName
381 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTableBox(..)>
382 const SwTableBox
* pTLBox
=
383 pTable
? pTable
->GetTableBox( aStartCell
, true ) : nullptr;
386 const SwStartNode
* pSttNd
= pTLBox
->GetSttNd();
387 SwPosition
aPos(*pSttNd
);
389 // set cursor to top left box of range
390 auto pUnoCursor
= pTableFormat
->GetDoc()->CreateUnoCursor(aPos
, true);
391 pUnoCursor
->Move( fnMoveForward
, GoInNode
);
392 pUnoCursor
->SetRemainInSection( false );
395 // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTableBox(..)>
396 const SwTableBox
* pBRBox
= pTable
->GetTableBox( aEndCell
, true );
399 pUnoCursor
->SetMark();
400 pUnoCursor
->GetPoint()->Assign( *pBRBox
->GetSttNd() );
401 pUnoCursor
->Move( fnMoveForward
, GoInNode
);
402 SwUnoTableCursor
& rCursor
=
403 dynamic_cast<SwUnoTableCursor
&>(*pUnoCursor
);
404 // HACK: remove pending actions for old style tables
405 UnoActionRemoveContext
aRemoveContext(rCursor
);
406 rCursor
.MakeBoxSels();
407 rpUnoCursor
= std::move(pUnoCursor
);
413 static bool GetSubranges( std::u16string_view rRangeRepresentation
,
414 uno::Sequence
< OUString
> &rSubRanges
, bool bNormalize
)
417 const sal_Int32 nLen
= comphelper::string::getTokenCount(rRangeRepresentation
, ';');
418 uno::Sequence
< OUString
> aRanges( nLen
);
423 OUString
*pRanges
= aRanges
.getArray();
424 OUString aFirstTable
;
426 for( sal_Int32 i
= 0; i
< nLen
&& bRes
; ++i
)
428 const OUString
aRange( o3tl::getToken(rRangeRepresentation
, 0, ';', nPos
) );
429 if (!aRange
.isEmpty())
431 pRanges
[nCnt
] = aRange
;
433 OUString aTableName
, aStartCell
, aEndCell
;
434 if (!GetTableAndCellsFromRangeRep( aRange
,
435 aTableName
, aStartCell
, aEndCell
))
440 sw_NormalizeRange( aStartCell
, aEndCell
);
441 pRanges
[nCnt
] = GetRangeRepFromTableAndCells( aTableName
,
442 aStartCell
, aEndCell
, true );
445 // make sure to use only a single table
447 aFirstTable
= aTableName
;
449 if (aFirstTable
!= aTableName
) bRes
= false;
455 aRanges
.realloc( nCnt
);
457 rSubRanges
= std::move(aRanges
);
461 static void SortSubranges( uno::Sequence
< OUString
> &rSubRanges
, bool bCmpByColumn
)
463 sal_Int32 nLen
= rSubRanges
.getLength();
464 OUString
*pSubRanges
= rSubRanges
.getArray();
466 OUString aSmallestTableName
;
467 OUString aSmallestStartCell
;
468 OUString aSmallestEndCell
;
470 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
472 sal_Int32 nIdxOfSmallest
= i
;
473 GetTableAndCellsFromRangeRep( pSubRanges
[nIdxOfSmallest
],
474 aSmallestTableName
, aSmallestStartCell
, aSmallestEndCell
);
475 if (aSmallestEndCell
.isEmpty())
476 aSmallestEndCell
= aSmallestStartCell
;
478 for (sal_Int32 k
= i
+1; k
< nLen
; ++k
)
480 // get cell names for sub range
484 GetTableAndCellsFromRangeRep( pSubRanges
[k
],
485 aTableName
, aStartCell
, aEndCell
);
486 if (aEndCell
.isEmpty())
487 aEndCell
= aStartCell
;
489 // compare cell ranges ( is the new one smaller? )
490 if (-1 == sw_CompareCellRanges( aStartCell
, aEndCell
,
491 aSmallestStartCell
, aSmallestEndCell
, bCmpByColumn
))
494 aSmallestTableName
= aTableName
;
495 aSmallestStartCell
= aStartCell
;
496 aSmallestEndCell
= aEndCell
;
500 // move smallest element to the start of the not sorted area
501 const OUString
aTmp( pSubRanges
[ nIdxOfSmallest
] );
502 pSubRanges
[ nIdxOfSmallest
] = pSubRanges
[ i
];
503 pSubRanges
[ i
] = aTmp
;
507 SwChartDataProvider::SwChartDataProvider( const SwDoc
& rSwDoc
) :
513 SwChartDataProvider::~SwChartDataProvider()
517 uno::Reference
< chart2::data::XDataSource
> SwChartDataProvider::Impl_createDataSource(
518 const uno::Sequence
< beans::PropertyValue
>& rArguments
, bool bTestOnly
)
520 SolarMutexGuard aGuard
;
522 throw lang::DisposedException();
524 uno::Reference
< chart2::data::XDataSource
> xRes
;
527 throw uno::RuntimeException(u
"Not connected to a document."_ustr
);
530 OUString aRangeRepresentation
;
531 uno::Sequence
< sal_Int32
> aSequenceMapping
;
532 bool bFirstIsLabel
= false;
533 bool bDtaSrcIsColumns
= true; // true : DataSource will be sequence of columns
534 // false: DataSource will be sequence of rows
536 OUString aChartOleObjectName
; //work around wrong writer ranges ( see Issue 58464 )
537 sal_Int32 nArgs
= rArguments
.getLength();
538 OSL_ENSURE( nArgs
!= 0, "no properties provided" );
541 for (const beans::PropertyValue
& rArg
: rArguments
)
543 if ( rArg
.Name
== "DataRowSource" )
545 chart::ChartDataRowSource eSource
;
546 if (!(rArg
.Value
>>= eSource
))
549 if (!(rArg
.Value
>>= nTmp
))
550 throw lang::IllegalArgumentException();
551 eSource
= static_cast< chart::ChartDataRowSource
>( nTmp
);
553 bDtaSrcIsColumns
= eSource
== chart::ChartDataRowSource_COLUMNS
;
555 else if ( rArg
.Name
== "FirstCellAsLabel" )
557 if (!(rArg
.Value
>>= bFirstIsLabel
))
558 throw lang::IllegalArgumentException();
560 else if ( rArg
.Name
== "CellRangeRepresentation" )
562 if (!(rArg
.Value
>>= aRangeRepresentation
))
563 throw lang::IllegalArgumentException();
565 else if ( rArg
.Name
== "SequenceMapping" )
567 if (!(rArg
.Value
>>= aSequenceMapping
))
568 throw lang::IllegalArgumentException();
570 else if ( rArg
.Name
== "ChartOleObjectName" )
572 if (!(rArg
.Value
>>= aChartOleObjectName
))
573 throw lang::IllegalArgumentException();
577 uno::Sequence
< OUString
> aSubRanges
;
578 // get sub-ranges and check that they all are from the very same table
579 bool bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, true );
581 if (!bOk
&& m_pDoc
&& !aChartOleObjectName
.isEmpty() )
583 //try to correct the range here
584 //work around wrong writer ranges ( see Issue 58464 )
585 OUString aChartTableName
;
587 const SwNodes
& rNodes
= m_pDoc
->GetNodes();
588 for( SwNodeOffset nN
= rNodes
.Count(); nN
--; )
590 SwNode
* pNode
= rNodes
[nN
];
593 const SwOLENode
* pOleNode
= pNode
->GetOLENode();
596 const SwOLEObj
& rOObj
= pOleNode
->GetOLEObj();
597 if( aChartOleObjectName
== rOObj
.GetCurrentPersistName() )
599 aChartTableName
= pOleNode
->GetChartTableName();
604 if( !aChartTableName
.isEmpty() )
606 //the wrong range is still shifted one row down
607 //thus the first row is missing and an invalid row at the end is added.
608 //Therefore we need to shift the range one row up
609 SwRangeDescriptor aDesc
;
610 if (aRangeRepresentation
.isEmpty())
611 return xRes
; // we can't handle this thus returning an empty references
613 aRangeRepresentation
= aRangeRepresentation
.copy( 1 ); // get rid of '.' to have only the cell range left
614 FillRangeDescriptor( aDesc
, aRangeRepresentation
);
617 if (aDesc
.nTop
<= 0) // no chance to shift the range one row up?
618 return xRes
; // we can't handle this thus returning an empty references
623 OUString
aNewStartCell( sw_GetCellName( aDesc
.nLeft
, aDesc
.nTop
) );
624 OUString
aNewEndCell( sw_GetCellName( aDesc
.nRight
, aDesc
.nBottom
) );
625 aRangeRepresentation
= GetRangeRepFromTableAndCells(
626 aChartTableName
, aNewStartCell
, aNewEndCell
, true );
627 bOk
= GetSubranges( aRangeRepresentation
, aSubRanges
, true );
630 if (!bOk
) // different tables used, or incorrect range specifiers
631 throw lang::IllegalArgumentException();
633 SortSubranges( aSubRanges
, bDtaSrcIsColumns
);
635 // get table format for that single table from above
636 SwFrameFormat
*pTableFormat
= nullptr; // pointer to table format
637 std::shared_ptr
<SwUnoCursor
> pUnoCursor
; // here required to check if the cells in the range do actually exist
638 if (aSubRanges
.hasElements())
639 GetFormatAndCreateCursorFromRangeRep( m_pDoc
, aSubRanges
[0], &pTableFormat
, pUnoCursor
);
641 if (!pTableFormat
|| !pUnoCursor
)
642 throw lang::IllegalArgumentException();
644 SwTable
* pTable
= SwTable::FindTable(pTableFormat
);
645 if (pTable
->IsTableComplex())
646 return xRes
; // we can't handle this thus returning an empty references
648 // get a character map in the size of the table to mark
649 // all the ranges to use in
650 sal_Int32 nRows
= pTable
->GetTabLines().size();
652 // As per tdf#149718 one should know that some cells can be merged together.
653 // Therefore, the number of columns (boxes in each row) are not necessarily
654 // equal. Here, we calculate the maximum number of columns in all rows.
655 for (sal_Int32 i
= 0; i
< nRows
; ++i
)
656 nCols
= std::max(nCols
, static_cast<sal_Int32
>(pTable
->GetTabLines()[i
]->GetTabBoxes().size()));
658 std::vector
<std::vector
<char>> aMap(nRows
);
659 for (sal_Int32 i
= 0; i
< nRows
; ++i
)
660 aMap
[i
].resize(nCols
);
662 // iterate over subranges and mark used cells in above map
663 //!! by proceeding this way we automatically get rid of
664 //!! multiple listed or overlapping cell ranges which should
665 //!! just be ignored silently
666 for (const OUString
& rSubRange
: aSubRanges
)
668 OUString aTableName
, aStartCell
, aEndCell
;
669 bool bOk2
= GetTableAndCellsFromRangeRep(
670 rSubRange
, aTableName
, aStartCell
, aEndCell
);
671 OSL_ENSURE(bOk2
, "failed to get table and start/end cells");
673 sal_Int32 nStartRow
, nStartCol
, nEndRow
, nEndCol
;
674 SwXTextTable::GetCellPosition(aStartCell
, nStartCol
, nStartRow
);
675 SwXTextTable::GetCellPosition(aEndCell
, nEndCol
, nEndRow
);
676 OSL_ENSURE( nStartRow
<= nEndRow
&& nStartCol
<= nEndCol
,
677 "cell range not normalized");
679 // test if the ranges span more than the available cells
680 if( nStartRow
< 0 || nEndRow
>= nRows
||
681 nStartCol
< 0 || nEndCol
>= nCols
)
683 throw lang::IllegalArgumentException();
685 for (sal_Int32 k1
= nStartRow
; k1
<= nEndRow
; ++k1
)
687 for (sal_Int32 k2
= nStartCol
; k2
<= nEndCol
; ++k2
)
692 // find label and data sequences to use
694 sal_Int32 oi
; // outer index (slower changing index)
695 sal_Int32 ii
; // inner index (faster changing index)
696 sal_Int32 oiEnd
= bDtaSrcIsColumns
? nCols
: nRows
;
697 sal_Int32 iiEnd
= bDtaSrcIsColumns
? nRows
: nCols
;
698 std::vector
<sal_Int32
> aLabelIdx(oiEnd
);
699 std::vector
<sal_Int32
> aDataStartIdx(oiEnd
);
700 std::vector
<sal_Int32
> aDataLen(oiEnd
);
701 for (oi
= 0; oi
< oiEnd
; ++oi
)
704 aDataStartIdx
[oi
] = -1;
708 for (oi
= 0; oi
< oiEnd
; ++oi
)
713 char &rChar
= bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
];
715 // label should be used but is not yet found?
716 if (rChar
== 'x' && bFirstIsLabel
&& aLabelIdx
[oi
] == -1)
719 rChar
= 'L'; // setting a different char for labels here
720 // makes the test for the data sequence below
724 // find data sequence
725 if (rChar
== 'x' && aDataStartIdx
[oi
] == -1)
727 aDataStartIdx
[oi
] = ii
;
729 // get length of data sequence
731 while (ii
< iiEnd
&& 'x' == (bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
737 // check that there is no other separate sequence of data
738 // to be found because that is not supported
741 if ('x' == (bDtaSrcIsColumns
? aMap
[ii
][oi
] : aMap
[oi
][ii
]))
742 throw lang::IllegalArgumentException();
751 // make some other consistency checks while calculating
752 // the number of XLabeledDataSequence to build:
753 // - labels should always be used or not at all
754 // - the data sequences should have equal non-zero length
755 sal_Int32 nNumLDS
= 0;
758 for (oi
= 0; oi
< oiEnd
; ++oi
)
760 // row/col used at all?
761 if (aDataStartIdx
[oi
] != -1 &&
762 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1))
769 throw lang::IllegalArgumentException();
771 // now we should have all necessary data to build a proper DataSource
772 // thus if we came this far there should be no further problem
774 return xRes
; // have createDataSourcePossible return true
776 // create data source from found label and data sequences
777 uno::Sequence
<uno::Reference
<chart2::data::XDataSequence
>> aLabelSeqs(nNumLDS
);
778 uno::Reference
<chart2::data::XDataSequence
>* pLabelSeqs
= aLabelSeqs
.getArray();
779 uno::Sequence
<uno::Reference
<chart2::data::XDataSequence
>> aDataSeqs(nNumLDS
);
780 uno::Reference
<chart2::data::XDataSequence
>* pDataSeqs
= aDataSeqs
.getArray();
781 sal_Int32 nSeqsIdx
= 0;
782 for (oi
= 0; oi
< oiEnd
; ++oi
)
784 // row/col not used? (see if-statement above where nNumLDS was counted)
785 if (!(aDataStartIdx
[oi
] != -1 &&
786 (!bFirstIsLabel
|| aLabelIdx
[oi
] != -1)))
789 // get cell ranges for label and data
791 SwRangeDescriptor aLabelDesc
;
792 SwRangeDescriptor aDataDesc
;
793 if (bDtaSrcIsColumns
) // use columns
795 aLabelDesc
.nTop
= aLabelIdx
[oi
];
796 aLabelDesc
.nLeft
= oi
;
797 aLabelDesc
.nBottom
= aLabelDesc
.nTop
;
798 aLabelDesc
.nRight
= oi
;
800 aDataDesc
.nTop
= aDataStartIdx
[oi
];
801 aDataDesc
.nLeft
= oi
;
802 aDataDesc
.nBottom
= aDataDesc
.nTop
+ aDataLen
[oi
] - 1;
803 aDataDesc
.nRight
= oi
;
807 aLabelDesc
.nTop
= oi
;
808 aLabelDesc
.nLeft
= aLabelIdx
[oi
];
809 aLabelDesc
.nBottom
= oi
;
810 aLabelDesc
.nRight
= aLabelDesc
.nLeft
;
813 aDataDesc
.nLeft
= aDataStartIdx
[oi
];
814 aDataDesc
.nBottom
= oi
;
815 aDataDesc
.nRight
= aDataDesc
.nLeft
+ aDataLen
[oi
] - 1;
817 const OUString aBaseName
= pTableFormat
->GetName() + ".";
819 OUString aLabelRange
;
820 if (aLabelIdx
[oi
] != -1)
822 aLabelRange
= aBaseName
823 + sw_GetCellName( aLabelDesc
.nLeft
, aLabelDesc
.nTop
)
824 + ":" + sw_GetCellName( aLabelDesc
.nRight
, aLabelDesc
.nBottom
);
827 OUString aDataRange
= aBaseName
828 + sw_GetCellName( aDataDesc
.nLeft
, aDataDesc
.nTop
)
829 + ":" + sw_GetCellName( aDataDesc
.nRight
, aDataDesc
.nBottom
);
831 // get cursors spanning the cell ranges for label and data
832 std::shared_ptr
<SwUnoCursor
> pLabelUnoCursor
;
833 std::shared_ptr
<SwUnoCursor
> pDataUnoCursor
;
834 GetFormatAndCreateCursorFromRangeRep(m_pDoc
, aLabelRange
, &pTableFormat
, pLabelUnoCursor
);
835 GetFormatAndCreateCursorFromRangeRep(m_pDoc
, aDataRange
, &pTableFormat
, pDataUnoCursor
);
837 // create XDataSequence's from cursors
839 pLabelSeqs
[nSeqsIdx
] = new SwChartDataSequence(*this, *pTableFormat
, pLabelUnoCursor
);
840 OSL_ENSURE(pDataUnoCursor
, "pointer to data sequence missing");
842 pDataSeqs
[nSeqsIdx
] = new SwChartDataSequence(*this, *pTableFormat
, pDataUnoCursor
);
843 if (pLabelUnoCursor
|| pDataUnoCursor
)
846 OSL_ENSURE(nSeqsIdx
== nNumLDS
, "mismatch between sequence size and num,ber of entries");
848 // build data source from data and label sequences
849 uno::Sequence
<uno::Reference
<chart2::data::XLabeledDataSequence
>> aLDS(nNumLDS
);
850 uno::Reference
<chart2::data::XLabeledDataSequence
>* pLDS
= aLDS
.getArray();
851 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
853 rtl::Reference
<SwChartLabeledDataSequence
> pLabeledDtaSeq
= new SwChartLabeledDataSequence
;
854 pLabeledDtaSeq
->setLabel(pLabelSeqs
[i
]);
855 pLabeledDtaSeq
->setValues(pDataSeqs
[i
]);
856 pLDS
[i
] = pLabeledDtaSeq
;
859 // apply 'SequenceMapping' if it was provided
860 if (aSequenceMapping
.hasElements())
862 uno::Sequence
<uno::Reference
<chart2::data::XLabeledDataSequence
>> aOld_LDS(aLDS
);
863 uno::Reference
<chart2::data::XLabeledDataSequence
>* pOld_LDS
= aOld_LDS
.getArray();
865 sal_Int32 nNewCnt
= 0;
866 for (sal_Int32 nIdx
: aSequenceMapping
)
868 // check that index to be used is valid
869 // and has not yet been used
870 if (0 <= nIdx
&& nIdx
< nNumLDS
&& pOld_LDS
[nIdx
].is())
872 pLDS
[nNewCnt
++] = pOld_LDS
[nIdx
];
874 // mark index as being used already (avoids duplicate entries)
875 pOld_LDS
[nIdx
].clear();
878 // add not yet used 'old' sequences to new one
879 for (sal_Int32 i
= 0; i
< nNumLDS
; ++i
)
881 if (pOld_LDS
[i
].is())
882 pLDS
[nNewCnt
++] = pOld_LDS
[i
];
884 OSL_ENSURE(nNewCnt
== nNumLDS
, "unexpected size of resulting sequence");
887 xRes
= new SwChartDataSource(aLDS
);
891 sal_Bool SAL_CALL
SwChartDataProvider::createDataSourcePossible(
892 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
894 SolarMutexGuard aGuard
;
896 bool bPossible
= true;
899 Impl_createDataSource( rArguments
, true );
901 catch (lang::IllegalArgumentException
&)
909 uno::Reference
< chart2::data::XDataSource
> SAL_CALL
SwChartDataProvider::createDataSource(
910 const uno::Sequence
< beans::PropertyValue
>& rArguments
)
912 SolarMutexGuard aGuard
;
913 return Impl_createDataSource( rArguments
);
918 * we need to return a property that has the same value as the property
919 * 'CellRangeRepresentation' but for all rows which are increased by one.
920 * E.g. Table1.A1:D5 -> Table1,A2:D6
921 * Since the problem is only for old charts which did not support multiple
922 * we do not need to provide that property/string if the 'CellRangeRepresentation'
923 * contains multiple ranges.
925 OUString
SwChartDataProvider::GetBrokenCellRangeForExport(
926 std::u16string_view rCellRangeRepresentation
)
928 // check that we do not have multiple ranges
929 if (std::u16string_view::npos
== rCellRangeRepresentation
.find( ';' ))
931 // get current cell and table names
932 OUString aTableName
, aStartCell
, aEndCell
;
933 GetTableAndCellsFromRangeRep( rCellRangeRepresentation
,
934 aTableName
, aStartCell
, aEndCell
, false );
935 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
936 SwXTextTable::GetCellPosition( aStartCell
, nStartCol
, nStartRow
);
937 SwXTextTable::GetCellPosition( aEndCell
, nEndCol
, nEndRow
);
939 // get new cell names
942 aStartCell
= sw_GetCellName( nStartCol
, nStartRow
);
943 aEndCell
= sw_GetCellName( nEndCol
, nEndRow
);
945 return GetRangeRepFromTableAndCells( aTableName
,
946 aStartCell
, aEndCell
, false );
952 uno::Sequence
< beans::PropertyValue
> SAL_CALL
SwChartDataProvider::detectArguments(
953 const uno::Reference
< chart2::data::XDataSource
>& xDataSource
)
955 SolarMutexGuard aGuard
;
957 throw lang::DisposedException();
959 uno::Sequence
< beans::PropertyValue
> aResult
;
960 if (!xDataSource
.is())
963 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aDS_LDS( xDataSource
->getDataSequences() );
964 const uno::Reference
< chart2::data::XLabeledDataSequence
> *pDS_LDS
= aDS_LDS
.getConstArray();
965 sal_Int32 nNumDS_LDS
= aDS_LDS
.getLength();
969 OSL_FAIL( "XLabeledDataSequence in data source contains 0 entries" );
973 SwFrameFormat
*pTableFormat
= nullptr;
974 SwTable
*pTable
= nullptr;
976 sal_Int32 nTableRows
= 0;
977 sal_Int32 nTableCols
= 0;
979 // data used to build 'CellRangeRepresentation' from later on
980 std::vector
< std::vector
< char > > aMap
;
982 uno::Sequence
< sal_Int32
> aSequenceMapping( nNumDS_LDS
);
983 sal_Int32
*pSequenceMapping
= aSequenceMapping
.getArray();
985 OUString aCellRanges
;
986 sal_Int16 nDtaSrcIsColumns
= -1;// -1: don't know yet, 0: false, 1: true -2: neither
987 sal_Int32 nLabelSeqLen
= -1; // used to see if labels are always used or not and have
988 // the expected size of 1 (i.e. if FirstCellAsLabel can
990 // -1: don't know yet, 0: not used, 1: always a single labe cell, ...
991 // -2: neither/failed
992 for (sal_Int32 nDS1
= 0; nDS1
< nNumDS_LDS
; ++nDS1
)
994 uno::Reference
< chart2::data::XLabeledDataSequence
> xLabeledDataSequence( pDS_LDS
[nDS1
] );
995 if( !xLabeledDataSequence
.is() )
997 OSL_FAIL("got NULL for XLabeledDataSequence from Data source");
1000 const uno::Reference
< chart2::data::XDataSequence
> xCurLabel
= xLabeledDataSequence
->getLabel();
1001 const uno::Reference
< chart2::data::XDataSequence
> xCurValues
= xLabeledDataSequence
->getValues();
1003 // get sequence lengths for label and values.
1005 sal_Int32 nCurLabelSeqLen
= -1;
1006 sal_Int32 nCurValuesSeqLen
= -1;
1008 nCurLabelSeqLen
= xCurLabel
->getData().getLength();
1009 if (xCurValues
.is())
1010 nCurValuesSeqLen
= xCurValues
->getData().getLength();
1012 // check for consistent use of 'first cell as label'
1013 if (nLabelSeqLen
== -1) // set initial value to compare with below further on
1014 nLabelSeqLen
= nCurLabelSeqLen
;
1015 if (nLabelSeqLen
!= nCurLabelSeqLen
)
1016 nLabelSeqLen
= -2; // failed / no consistent use of label cells
1018 // get table and cell names for label and values data sequences
1019 // (start and end cell will be sorted, i.e. start cell <= end cell)
1020 OUString aLabelTableName
, aLabelStartCell
, aLabelEndCell
;
1021 OUString aValuesTableName
, aValuesStartCell
, aValuesEndCell
;
1022 OUString aLabelRange
, aValuesRange
;
1024 aLabelRange
= xCurLabel
->getSourceRangeRepresentation();
1025 if (xCurValues
.is())
1026 aValuesRange
= xCurValues
->getSourceRangeRepresentation();
1027 if ((!aLabelRange
.isEmpty() && !GetTableAndCellsFromRangeRep( aLabelRange
,
1028 aLabelTableName
, aLabelStartCell
, aLabelEndCell
)) ||
1029 !GetTableAndCellsFromRangeRep( aValuesRange
,
1030 aValuesTableName
, aValuesStartCell
, aValuesEndCell
))
1032 return aResult
; // failed -> return empty property sequence
1035 // make sure all sequences use the same table
1036 if (aTableName
.isEmpty())
1037 aTableName
= aValuesTableName
; // get initial value to compare with
1038 if (aTableName
.isEmpty() ||
1039 aTableName
!= aValuesTableName
||
1040 (!aLabelTableName
.isEmpty() && aTableName
!= aLabelTableName
))
1042 return aResult
; // failed -> return empty property sequence
1045 // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting
1046 // first and last cell used in both sequences
1048 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1049 const OUString
aCell( !aLabelStartCell
.isEmpty() ? aLabelStartCell
: aValuesStartCell
);
1050 OSL_ENSURE( !aCell
.isEmpty() , "start cell missing?" );
1051 SwXTextTable::GetCellPosition( aCell
, nFirstCol
, nFirstRow
);
1052 SwXTextTable::GetCellPosition( aValuesEndCell
, nLastCol
, nLastRow
);
1054 sal_Int16 nDirection
= -1; // -1: not yet set, 0: columns, 1: rows, -2: failed
1055 if (nFirstCol
== nLastCol
&& nFirstRow
== nLastRow
) // a single cell...
1057 OSL_ENSURE( nCurLabelSeqLen
== 0 && nCurValuesSeqLen
== 1,
1058 "trying to determine 'DataRowSource': something's fishy... should have been a single cell");
1059 nDirection
= 0; // default direction for a single cell should be 'columns'
1061 else // more than one cell is available (in values and label together!)
1063 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1065 else if (nFirstCol
!= nLastCol
&& nFirstRow
== nLastRow
)
1069 OSL_FAIL( "trying to determine 'DataRowSource': unexpected case found" );
1073 // check for consistent direction of data source
1074 if (nDtaSrcIsColumns
== -1) // set initial value to compare with below
1075 nDtaSrcIsColumns
= nDirection
;
1076 if (nDtaSrcIsColumns
!= nDirection
)
1078 nDtaSrcIsColumns
= -2; // failed
1081 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1083 // build data to obtain 'SequenceMapping' later on
1085 OSL_ENSURE( nDtaSrcIsColumns
== 0 || /* rows */
1086 nDtaSrcIsColumns
== 1, /* columns */
1087 "unexpected value for 'nDtaSrcIsColumns'" );
1088 pSequenceMapping
[nDS1
] = nDtaSrcIsColumns
? nFirstCol
: nFirstRow
;
1090 // build data used to determine 'CellRangeRepresentation' later on
1092 GetTableByName( *m_pDoc
, aTableName
, &pTableFormat
, &pTable
);
1093 if (!pTable
|| pTable
->IsTableComplex())
1094 return aResult
; // failed -> return empty property sequence
1095 nTableRows
= pTable
->GetTabLines().size();
1096 nTableCols
= pTable
->GetTabLines().front()->GetTabBoxes().size();
1097 aMap
.resize( nTableRows
);
1098 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1099 aMap
[i
].resize( nTableCols
);
1101 if (!aLabelStartCell
.isEmpty() && !aLabelEndCell
.isEmpty())
1103 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1104 SwXTextTable::GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1105 SwXTextTable::GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1106 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1107 nStartCol
< 0 || nEndCol
>= nTableCols
)
1109 return aResult
; // failed -> return empty property sequence
1111 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1113 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1115 char &rChar
= aMap
[i
][k
];
1116 if (rChar
== '\0') // check for overlapping values and/or labels
1119 return aResult
; // failed -> return empty property sequence
1123 if (!aValuesStartCell
.isEmpty() && !aValuesEndCell
.isEmpty())
1125 sal_Int32 nStartCol
= -1, nStartRow
= -1, nEndCol
= -1, nEndRow
= -1;
1126 SwXTextTable::GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1127 SwXTextTable::GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1128 if (nStartRow
< 0 || nEndRow
>= nTableRows
||
1129 nStartCol
< 0 || nEndCol
>= nTableCols
)
1131 return aResult
; // failed -> return empty property sequence
1133 for (sal_Int32 i
= nStartRow
; i
<= nEndRow
; ++i
)
1135 for (sal_Int32 k
= nStartCol
; k
<= nEndCol
; ++k
)
1137 char &rChar
= aMap
[i
][k
];
1138 if (rChar
== '\0') // check for overlapping values and/or labels
1141 return aResult
; // failed -> return empty property sequence
1147 #if OSL_DEBUG_LEVEL > 0
1148 // do some extra sanity checking that the length of the sequences
1149 // matches their range representation
1151 sal_Int32 nStartRow
= -1, nStartCol
= -1, nEndRow
= -1, nEndCol
= -1;
1154 SwXTextTable::GetCellPosition( aLabelStartCell
, nStartCol
, nStartRow
);
1155 SwXTextTable::GetCellPosition( aLabelEndCell
, nEndCol
, nEndRow
);
1156 OSL_ENSURE( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurLabel
->getData().getLength()) ||
1157 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurLabel
->getData().getLength()),
1158 "label sequence length does not match range representation!" );
1160 if (xCurValues
.is())
1162 SwXTextTable::GetCellPosition( aValuesStartCell
, nStartCol
, nStartRow
);
1163 SwXTextTable::GetCellPosition( aValuesEndCell
, nEndCol
, nEndRow
);
1164 OSL_ENSURE( (nStartCol
== nEndCol
&& (nEndRow
- nStartRow
+ 1) == xCurValues
->getData().getLength()) ||
1165 (nStartRow
== nEndRow
&& (nEndCol
- nStartCol
+ 1) == xCurValues
->getData().getLength()),
1166 "value sequence length does not match range representation!" );
1172 // build value for 'CellRangeRepresentation'
1174 const OUString aCellRangeBase
= aTableName
+ ".";
1176 for (sal_Int32 i
= 0; i
< nTableRows
; ++i
)
1178 for (sal_Int32 k
= 0; k
< nTableCols
; ++k
)
1180 if (aMap
[i
][k
] != '\0') // top-left cell of a sub-range found
1182 // find rectangular sub-range to use
1183 sal_Int32 nRowIndex1
= i
; // row index
1184 sal_Int32 nColIndex1
= k
; // column index
1185 sal_Int32 nRowSubLen
= 0;
1186 sal_Int32 nColSubLen
= 0;
1187 while (nRowIndex1
< nTableRows
&& aMap
[nRowIndex1
++][k
] != '\0')
1189 // be aware of shifted sequences!
1190 // (according to the checks done prior the length should be ok)
1191 while (nColIndex1
< nTableCols
&& aMap
[i
][nColIndex1
] != '\0'
1192 && aMap
[i
+ nRowSubLen
-1][nColIndex1
] != '\0')
1197 OUString
aStartCell( sw_GetCellName( k
, i
) );
1198 OUString
aEndCell( sw_GetCellName( k
+ nColSubLen
- 1, i
+ nRowSubLen
- 1) );
1199 aCurRange
= aCellRangeBase
+ aStartCell
+ ":" + aEndCell
;
1200 if (!aCellRanges
.isEmpty())
1202 aCellRanges
+= aCurRange
;
1204 // clear already found sub-range from map
1205 for (sal_Int32 nRowIndex2
= 0; nRowIndex2
< nRowSubLen
; ++nRowIndex2
)
1206 for (sal_Int32 nColumnIndex2
= 0; nColumnIndex2
< nColSubLen
; ++nColumnIndex2
)
1207 aMap
[i
+ nRowIndex2
][k
+ nColumnIndex2
] = '\0';
1211 // to be nice to the user we now sort the cell ranges according to
1212 // rows or columns depending on the direction used in the data source
1213 uno::Sequence
< OUString
> aSortedRanges
;
1214 GetSubranges( aCellRanges
, aSortedRanges
, false /*sub ranges should already be normalized*/ );
1215 SortSubranges( aSortedRanges
, (nDtaSrcIsColumns
== 1) );
1216 OUString aSortedCellRanges
;
1217 for (const OUString
& rSortedRange
: aSortedRanges
)
1219 if (!aSortedCellRanges
.isEmpty())
1220 aSortedCellRanges
+= ";";
1221 aSortedCellRanges
+= rSortedRange
;
1224 // build value for 'SequenceMapping'
1226 uno::Sequence
< sal_Int32
> aSortedMapping( aSequenceMapping
);
1227 auto [begin
, end
] = asNonConstRange(aSortedMapping
);
1228 std::sort(begin
, end
);
1229 bool bNeedSequenceMapping
= false;
1230 for (sal_Int32 i
= 0; i
< aSequenceMapping
.getLength(); ++i
)
1232 auto it
= std::find( std::cbegin(aSortedMapping
), std::cend(aSortedMapping
),
1233 aSequenceMapping
[i
] );
1234 pSequenceMapping
[i
] = std::distance(std::cbegin(aSortedMapping
), it
);
1236 if (i
!= aSequenceMapping
[i
])
1237 bNeedSequenceMapping
= true;
1240 // check if 'SequenceMapping' is actually not required...
1241 // (don't write unnecessary properties to the XML file)
1242 if (!bNeedSequenceMapping
)
1243 aSequenceMapping
.realloc(0);
1245 // build resulting properties
1247 OSL_ENSURE(nLabelSeqLen
>= 0 || nLabelSeqLen
== -2 /*not used*/,
1248 "unexpected value for 'nLabelSeqLen'" );
1249 bool bFirstCellIsLabel
= false; // default value if 'nLabelSeqLen' could not properly determined
1250 if (nLabelSeqLen
> 0) // == 0 means no label sequence in use
1251 bFirstCellIsLabel
= true;
1253 OSL_ENSURE( !aSortedCellRanges
.isEmpty(), "CellRangeRepresentation missing" );
1254 const OUString
aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges
) );
1257 auto pResult
= aResult
.getArray();
1258 sal_Int32 nProps
= 0;
1259 pResult
[nProps
].Name
= "FirstCellAsLabel";
1260 pResult
[nProps
++].Value
<<= bFirstCellIsLabel
;
1261 pResult
[nProps
].Name
= "CellRangeRepresentation";
1262 pResult
[nProps
++].Value
<<= aSortedCellRanges
;
1263 if (!aBrokenCellRangeForExport
.isEmpty())
1265 pResult
[nProps
].Name
= "BrokenCellRangeForExport";
1266 pResult
[nProps
++].Value
<<= aBrokenCellRangeForExport
;
1268 if (nDtaSrcIsColumns
== 0 || nDtaSrcIsColumns
== 1)
1270 chart::ChartDataRowSource eDataRowSource
= (nDtaSrcIsColumns
== 1) ?
1271 chart::ChartDataRowSource_COLUMNS
: chart::ChartDataRowSource_ROWS
;
1272 pResult
[nProps
].Name
= "DataRowSource";
1273 pResult
[nProps
++].Value
<<= eDataRowSource
;
1275 if (aSequenceMapping
.hasElements())
1277 pResult
[nProps
].Name
= "SequenceMapping";
1278 pResult
[nProps
++].Value
<<= aSequenceMapping
;
1281 aResult
.realloc( nProps
);
1286 uno::Reference
< chart2::data::XDataSequence
> SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation(
1287 std::u16string_view rRangeRepresentation
, bool bTestOnly
)
1290 throw lang::DisposedException();
1292 SwFrameFormat
*pTableFormat
= nullptr; // pointer to table format
1293 std::shared_ptr
<SwUnoCursor
> pUnoCursor
; // pointer to new created cursor spanning the cell range
1294 GetFormatAndCreateCursorFromRangeRep( m_pDoc
, rRangeRepresentation
,
1295 &pTableFormat
, pUnoCursor
);
1296 if (!pTableFormat
|| !pUnoCursor
)
1297 throw lang::IllegalArgumentException();
1299 // check that cursors point and mark are in a single row or column.
1300 OUString
aCellRange( GetCellRangeName( *pTableFormat
, *pUnoCursor
) );
1301 SwRangeDescriptor aDesc
;
1302 FillRangeDescriptor( aDesc
, aCellRange
);
1303 if (aDesc
.nTop
!= aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1304 throw lang::IllegalArgumentException();
1306 uno::Reference
< chart2::data::XDataSequence
> xDataSeq
;
1308 xDataSeq
= new SwChartDataSequence( *this, *pTableFormat
, pUnoCursor
);
1313 sal_Bool SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentationPossible(
1314 const OUString
& rRangeRepresentation
)
1316 SolarMutexGuard aGuard
;
1318 bool bPossible
= true;
1321 Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
, true );
1323 catch (lang::IllegalArgumentException
&)
1331 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartDataProvider::createDataSequenceByRangeRepresentation(
1332 const OUString
& rRangeRepresentation
)
1334 SolarMutexGuard aGuard
;
1335 return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation
);
1338 uno::Reference
< sheet::XRangeSelection
> SAL_CALL
SwChartDataProvider::getRangeSelection( )
1340 // note: it is no error to return nothing here
1341 return uno::Reference
< sheet::XRangeSelection
>();
1344 uno::Reference
<css::chart2::data::XDataSequence
> SAL_CALL
1345 SwChartDataProvider::createDataSequenceByValueArray(
1346 const OUString
& /*aRole*/, const OUString
& /*aRangeRepresentation*/,
1347 const OUString
& /*aRoleQualifier*/ )
1349 return uno::Reference
<css::chart2::data::XDataSequence
>();
1352 void SAL_CALL
SwChartDataProvider::dispose( )
1354 bool bMustDispose( false );
1356 std::unique_lock
aGuard( GetChartMutex() );
1357 bMustDispose
= !m_bDisposed
;
1364 // dispose all data-sequences
1365 for (const auto& rEntry
: m_aDataSequences
)
1367 DisposeAllDataSequences( rEntry
.first
);
1369 // release all references to data-sequences
1370 m_aDataSequences
.clear();
1372 // require listeners to release references to this object
1373 lang::EventObject
aEvtObj( static_cast< chart2::data::XDataProvider
* >(this) );
1374 std::unique_lock
aGuard( GetChartMutex() );
1375 m_aEventListeners
.disposeAndClear( aGuard
, aEvtObj
);
1378 void SAL_CALL
SwChartDataProvider::addEventListener(
1379 const uno::Reference
< lang::XEventListener
>& rxListener
)
1381 std::unique_lock
aGuard( GetChartMutex() );
1382 if (!m_bDisposed
&& rxListener
.is())
1383 m_aEventListeners
.addInterface( aGuard
, rxListener
);
1386 void SAL_CALL
SwChartDataProvider::removeEventListener(
1387 const uno::Reference
< lang::XEventListener
>& rxListener
)
1389 std::unique_lock
aGuard( GetChartMutex() );
1390 if (!m_bDisposed
&& rxListener
.is())
1391 m_aEventListeners
.removeInterface( aGuard
, rxListener
);
1394 OUString SAL_CALL
SwChartDataProvider::getImplementationName( )
1396 return u
"SwChartDataProvider"_ustr
;
1399 sal_Bool SAL_CALL
SwChartDataProvider::supportsService(const OUString
& rServiceName
)
1401 return cppu::supportsService(this, rServiceName
);
1404 uno::Sequence
< OUString
> SAL_CALL
SwChartDataProvider::getSupportedServiceNames( )
1406 return { u
"com.sun.star.chart2.data.DataProvider"_ustr
};
1409 void SwChartDataProvider::AddDataSequence( const SwTable
&rTable
, rtl::Reference
< SwChartDataSequence
> const &rxDataSequence
)
1411 Vec_DataSequenceRef_t
& rVec
= m_aDataSequences
[ &rTable
];
1412 assert(std::find_if(rVec
.begin(), rVec
.end(),
1413 [&rxDataSequence
](const unotools::WeakReference
< SwChartDataSequence
>& i
)
1415 return i
.get() == rxDataSequence
;
1416 }) == rVec
.end() && "duplicate insert");
1417 rVec
.push_back( rxDataSequence
);
1420 void SwChartDataProvider::RemoveDataSequence( const SwTable
&rTable
, rtl::Reference
< SwChartDataSequence
> const &rxDataSequence
)
1422 Vec_DataSequenceRef_t
& rVec
= m_aDataSequences
[ &rTable
];
1424 [&rxDataSequence
](const unotools::WeakReference
< SwChartDataSequence
>& i
)
1426 return i
.get() == rxDataSequence
;
1430 void SwChartDataProvider::InvalidateTable( const SwTable
*pTable
, bool bImmediate
)
1432 OSL_ENSURE( pTable
, "table pointer is NULL" );
1437 pTable
->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking();
1439 const Vec_DataSequenceRef_t
&rVec
= m_aDataSequences
[ pTable
];
1440 for (const unotools::WeakReference
<SwChartDataSequence
>& rItem
: rVec
)
1442 rtl::Reference
< SwChartDataSequence
> xRef(rItem
);
1445 // mark the sequence as 'dirty' and notify listeners
1446 xRef
->setModified( true );
1450 // tdf#122995 added Immediate-mode to allow non-timer-delayed Chart invalidation
1451 if (bImmediate
&& !m_bDisposed
)
1452 pTable
->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().Disconnect();
1455 void SwChartDataProvider::DeleteBox( const SwTable
*pTable
, const SwTableBox
&rBox
)
1457 OSL_ENSURE( pTable
, "table pointer is NULL" );
1462 pTable
->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking();
1464 Vec_DataSequenceRef_t
&rVec
= m_aDataSequences
[ pTable
];
1466 // iterate over all data-sequences for that table...
1467 auto aIt( rVec
.begin() );
1468 while (aIt
!= rVec
.end())
1470 bool bNowEmpty
= false;
1471 bool bSeqDisposed
= false;
1473 // check if weak reference is still valid...
1474 rtl::Reference
< SwChartDataSequence
> pDataSeq(*aIt
);
1477 // then delete that table box (check if implementation cursor needs to be adjusted)
1480 bNowEmpty
= pDataSeq
->DeleteBox( rBox
);
1482 catch (const lang::DisposedException
&)
1485 bSeqDisposed
= true;
1491 aIt
= rVec
.erase( aIt
);
1492 if (pDataSeq
&& !bSeqDisposed
)
1493 pDataSeq
->dispose(); // the current way to tell chart that sth. got removed
1500 void SwChartDataProvider::DisposeAllDataSequences( const SwTable
*pTable
)
1502 OSL_ENSURE( pTable
, "table pointer is NULL" );
1507 pTable
->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking();
1509 //! make a copy of the STL container!
1510 //! This is necessary since calling 'dispose' will implicitly remove an element
1511 //! of the original container, and thus any iterator in the original container
1512 //! would become invalid.
1513 const Vec_DataSequenceRef_t
aVec( m_aDataSequences
[ pTable
] );
1515 for (const unotools::WeakReference
<SwChartDataSequence
>& rItem
: aVec
)
1517 rtl::Reference
< SwChartDataSequence
> xRef(rItem
);
1526 * SwChartDataProvider::AddRowCols tries to notify charts of added columns
1527 * or rows and extends the value sequence respectively (if possible).
1528 * If those can be added to the end of existing value data-sequences those
1529 * sequences get modified accordingly and will send a modification
1530 * notification (calling 'setModified
1532 * Since this function is a work-around for non existent Writer core functionality
1533 * (no arbitrary multi-selection in tables that can be used to define a
1534 * data-sequence) this function will be somewhat unreliable.
1535 * For example we will only try to adapt value sequences. For this we assume
1536 * that a sequence of length 1 is a label sequence and those with length >= 2
1537 * we presume to be value sequences. Also new cells can only be added in the
1538 * direction the value sequence is already pointing (rows / cols) and at the
1539 * start or end of the values data-sequence.
1540 * Nothing needs to be done if the new cells are in between the table cursors
1541 * point and mark since data-sequence are considered to consist of all cells
1543 * New rows/cols need to be added already to the table before calling
1546 void SwChartDataProvider::AddRowCols(
1547 const SwTable
&rTable
,
1548 const SwSelBoxes
& rBoxes
,
1549 sal_uInt16 nLines
, bool bBehind
)
1551 if (rTable
.IsTableComplex())
1554 const size_t nBoxes
= rBoxes
.size();
1555 if (nBoxes
< 1 || nLines
< 1)
1558 SwTableBox
* pFirstBox
= rBoxes
[0];
1559 SwTableBox
* pLastBox
= rBoxes
.back();
1561 if (!(pFirstBox
&& pLastBox
))
1564 sal_Int32 nFirstCol
= -1, nFirstRow
= -1, nLastCol
= -1, nLastRow
= -1;
1565 SwXTextTable::GetCellPosition( pFirstBox
->GetName(), nFirstCol
, nFirstRow
);
1566 SwXTextTable::GetCellPosition( pLastBox
->GetName(), nLastCol
, nLastRow
);
1568 bool bAddCols
= false; // default; also to be used if nBoxes == 1 :-/
1569 if (nFirstCol
== nLastCol
&& nFirstRow
!= nLastRow
)
1571 if (nFirstCol
!= nLastCol
&& nFirstRow
!= nLastRow
)
1574 //get range of indices in col/rows for new cells
1575 sal_Int32 nFirstNewCol
= nFirstCol
;
1576 sal_Int32 nFirstNewRow
= bBehind
? nFirstRow
+ 1 : nFirstRow
- nLines
;
1579 OSL_ENSURE( nFirstCol
== nLastCol
, "column indices seem broken" );
1580 nFirstNewCol
= bBehind
? nFirstCol
+ 1 : nFirstCol
- nLines
;
1581 nFirstNewRow
= nFirstRow
;
1584 // iterate over all data-sequences for the table
1585 const Vec_DataSequenceRef_t
&rVec
= m_aDataSequences
[ &rTable
];
1586 for (const unotools::WeakReference
<SwChartDataSequence
>& rItem
: rVec
)
1588 rtl::Reference
< SwChartDataSequence
> pDataSeq(rItem
);
1591 const sal_Int32 nLen
= pDataSeq
->getTextualData().getLength();
1592 if (nLen
> 1) // value data-sequence ?
1594 SwRangeDescriptor aDesc
;
1595 pDataSeq
->FillRangeDesc( aDesc
);
1597 chart::ChartDataRowSource eDRSource
= chart::ChartDataRowSource_COLUMNS
;
1598 if (aDesc
.nTop
== aDesc
.nBottom
&& aDesc
.nLeft
!= aDesc
.nRight
)
1599 eDRSource
= chart::ChartDataRowSource_ROWS
;
1601 if (!bAddCols
&& eDRSource
== chart::ChartDataRowSource_COLUMNS
)
1603 // add rows: extend affected columns by newly added row cells
1604 pDataSeq
->ExtendTo( true, nFirstNewRow
, nLines
);
1606 else if (bAddCols
&& eDRSource
== chart::ChartDataRowSource_ROWS
)
1608 // add cols: extend affected rows by newly added column cells
1609 pDataSeq
->ExtendTo( false, nFirstNewCol
, nLines
);
1616 // XRangeXMLConversion
1617 OUString SAL_CALL
SwChartDataProvider::convertRangeToXML( const OUString
& rRangeRepresentation
)
1619 SolarMutexGuard aGuard
;
1621 throw lang::DisposedException();
1623 if (rRangeRepresentation
.isEmpty())
1626 OUStringBuffer aRes
;
1628 // multiple ranges are delimited by a ';' like in
1629 // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges!
1630 SwTable
* pFirstFoundTable
= nullptr; // to check that only one table will be used
1633 const OUString
aRange( rRangeRepresentation
.getToken(0, ';', nPos
) );
1634 SwFrameFormat
*pTableFormat
= nullptr; // pointer to table format
1635 std::shared_ptr
<SwUnoCursor
> pCursor
;
1636 GetFormatAndCreateCursorFromRangeRep( m_pDoc
, aRange
, &pTableFormat
, pCursor
);
1638 throw lang::IllegalArgumentException();
1639 SwTable
* pTable
= SwTable::FindTable( pTableFormat
);
1640 if (pTable
->IsTableComplex())
1641 throw uno::RuntimeException(u
"Table too complex."_ustr
);
1643 // check that there is only one table used in all ranges
1644 if (!pFirstFoundTable
)
1645 pFirstFoundTable
= pTable
;
1646 if (pTable
!= pFirstFoundTable
)
1647 throw lang::IllegalArgumentException();
1649 OUString aTableName
;
1650 OUString aStartCell
;
1652 if (!GetTableAndCellsFromRangeRep( aRange
, aTableName
, aStartCell
, aEndCell
))
1653 throw lang::IllegalArgumentException();
1655 sal_Int32 nCol
, nRow
;
1656 SwXTextTable::GetCellPosition( aStartCell
, nCol
, nRow
);
1657 if (nCol
< 0 || nRow
< 0)
1658 throw uno::RuntimeException(u
"Cell not found."_ustr
);
1660 //!! following objects/functions are implemented in XMLRangeHelper.?xx
1661 //!! which is a copy of the respective file from chart2 !!
1662 XMLRangeHelper::CellRange aCellRange
;
1663 aCellRange
.aTableName
= aTableName
;
1664 aCellRange
.aUpperLeft
.nColumn
= nCol
;
1665 aCellRange
.aUpperLeft
.nRow
= nRow
;
1666 aCellRange
.aUpperLeft
.bIsEmpty
= false;
1667 if (aStartCell
!= aEndCell
&& !aEndCell
.isEmpty())
1669 SwXTextTable::GetCellPosition( aEndCell
, nCol
, nRow
);
1670 if (nCol
< 0 || nRow
< 0)
1671 throw uno::RuntimeException(u
"Cell not found."_ustr
);
1673 aCellRange
.aLowerRight
.nColumn
= nCol
;
1674 aCellRange
.aLowerRight
.nRow
= nRow
;
1675 aCellRange
.aLowerRight
.bIsEmpty
= false;
1677 OUString
aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange
) );
1678 if (!aRes
.isEmpty()) // in case of multiple ranges add delimiter
1684 return aRes
.makeStringAndClear();
1687 OUString SAL_CALL
SwChartDataProvider::convertRangeFromXML( const OUString
& rXMLRange
)
1689 SolarMutexGuard aGuard
;
1691 throw lang::DisposedException();
1693 if (rXMLRange
.isEmpty())
1696 OUStringBuffer aRes
;
1698 // multiple ranges are delimited by a ' ' like in
1699 // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges!
1700 OUString aFirstFoundTable
; // to check that only one table will be used
1704 OUString
aRange( rXMLRange
.getToken(0, ' ', nPos
) );
1706 //!! following objects and function are implemented in XMLRangeHelper.?xx
1707 //!! which is a copy of the respective file from chart2 !!
1708 XMLRangeHelper::CellRange
aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange
));
1710 // check that there is only one table used in all ranges
1711 if (aFirstFoundTable
.isEmpty())
1712 aFirstFoundTable
= aCellRange
.aTableName
;
1713 if (aCellRange
.aTableName
!= aFirstFoundTable
)
1714 throw lang::IllegalArgumentException();
1716 OUString aTmp
= aCellRange
.aTableName
+ "." +
1717 sw_GetCellName( aCellRange
.aUpperLeft
.nColumn
,
1718 aCellRange
.aUpperLeft
.nRow
);
1719 // does cell range consist of more than a single cell?
1720 if (!aCellRange
.aLowerRight
.bIsEmpty
)
1722 aTmp
+= ":" + sw_GetCellName( aCellRange
.aLowerRight
.nColumn
,
1723 aCellRange
.aLowerRight
.nRow
);
1726 if (!aRes
.isEmpty()) // in case of multiple ranges add delimiter
1732 return aRes
.makeStringAndClear();
1735 SwChartDataSource::SwChartDataSource(
1736 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > &rLDS
) :
1741 SwChartDataSource::~SwChartDataSource()
1745 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > SAL_CALL
SwChartDataSource::getDataSequences( )
1747 SolarMutexGuard aGuard
;
1751 OUString SAL_CALL
SwChartDataSource::getImplementationName( )
1753 return u
"SwChartDataSource"_ustr
;
1756 sal_Bool SAL_CALL
SwChartDataSource::supportsService(const OUString
& rServiceName
)
1758 return cppu::supportsService(this, rServiceName
);
1761 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSource::getSupportedServiceNames( )
1763 return { u
"com.sun.star.chart2.data.DataSource"_ustr
};
1766 SwChartDataSequence::SwChartDataSequence(
1767 SwChartDataProvider
& rProvider
,
1768 SwFrameFormat
& rTableFormat
,
1769 const std::shared_ptr
<SwUnoCursor
>& pTableCursor
) :
1770 m_pFormat(&rTableFormat
),
1771 m_aRowLabelText( SwResId( STR_CHART2_ROW_LABEL_TEXT
) ),
1772 m_aColLabelText( SwResId( STR_CHART2_COL_LABEL_TEXT
) ),
1773 m_xDataProvider( &rProvider
),
1774 m_pTableCursor( pTableCursor
),
1775 m_pPropSet( aSwMapProvider
.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE
) )
1777 StartListening(rTableFormat
.GetNotifier());
1778 m_bDisposed
= false;
1783 const SwTable
* pTable
= SwTable::FindTable( &rTableFormat
);
1786 m_xDataProvider
->AddDataSequence( *pTable
, this );
1787 m_xDataProvider
->addEventListener( static_cast< lang::XEventListener
* >(this) );
1790 OSL_FAIL( "table missing" );
1793 catch (uno::RuntimeException
&)
1795 // TODO: shouldn't there be a call to release() here?
1798 catch (uno::Exception
&)
1803 #if OSL_DEBUG_LEVEL > 0
1804 // check if it can properly convert into a SwUnoTableCursor
1805 // which is required for some functions
1806 SwUnoTableCursor
* pUnoTableCursor
= dynamic_cast<SwUnoTableCursor
*>(&(*m_pTableCursor
));
1807 OSL_ENSURE(pUnoTableCursor
, "SwChartDataSequence: cursor not SwUnoTableCursor");
1811 SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence
&rObj
) :
1812 SwChartDataSequenceBaseClass(rObj
),
1814 m_pFormat( rObj
.m_pFormat
),
1815 m_aRole( rObj
.m_aRole
),
1816 m_aRowLabelText( SwResId(STR_CHART2_ROW_LABEL_TEXT
) ),
1817 m_aColLabelText( SwResId(STR_CHART2_COL_LABEL_TEXT
) ),
1818 m_xDataProvider( rObj
.m_xDataProvider
),
1819 m_pTableCursor( rObj
.m_pTableCursor
),
1820 m_pPropSet( rObj
.m_pPropSet
)
1823 StartListening(m_pFormat
->GetNotifier());
1824 m_bDisposed
= false;
1829 const SwTable
* pTable
= SwTable::FindTable( GetFrameFormat() );
1832 m_xDataProvider
->AddDataSequence( *pTable
, this );
1833 m_xDataProvider
->addEventListener( static_cast< lang::XEventListener
* >(this) );
1836 OSL_FAIL( "table missing" );
1839 catch (uno::RuntimeException
&)
1841 // TODO: shouldn't there be a call to release() here?
1844 catch (uno::Exception
&)
1849 #if OSL_DEBUG_LEVEL > 0
1850 // check if it can properly convert into a SwUnoTableCursor
1851 // which is required for some functions
1852 SwUnoTableCursor
* pUnoTableCursor
= dynamic_cast<SwUnoTableCursor
*>(&(*m_pTableCursor
));
1853 OSL_ENSURE(pUnoTableCursor
, "SwChartDataSequence: cursor not SwUnoTableCursor");
1857 SwChartDataSequence::~SwChartDataSequence()
1861 OUString SAL_CALL
SwChartDataSequence::getSourceRangeRepresentation( )
1863 SolarMutexGuard aGuard
;
1865 throw lang::DisposedException();
1868 SwFrameFormat
* pTableFormat
= GetFrameFormat();
1871 const OUString
aCellRange( GetCellRangeName( *pTableFormat
, *m_pTableCursor
) );
1872 OSL_ENSURE( !aCellRange
.isEmpty(), "failed to get cell range" );
1873 aRes
= pTableFormat
->GetName() + "." + aCellRange
;
1878 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::generateLabel(
1879 chart2::data::LabelOrigin eLabelOrigin
)
1881 SolarMutexGuard aGuard
;
1883 throw lang::DisposedException();
1885 uno::Sequence
< OUString
> aLabels
;
1888 SwRangeDescriptor aDesc
;
1890 SwFrameFormat
* pTableFormat
= GetFrameFormat();
1892 throw uno::RuntimeException(u
"No table format found."_ustr
);
1893 SwTable
* pTable
= SwTable::FindTable( pTableFormat
);
1895 throw uno::RuntimeException(u
"No table found."_ustr
);
1896 if (pTable
->IsTableComplex())
1897 throw uno::RuntimeException(u
"Table too complex."_ustr
);
1899 const OUString
aCellRange( GetCellRangeName( *pTableFormat
, *m_pTableCursor
) );
1900 OSL_ENSURE( !aCellRange
.isEmpty(), "failed to get cell range" );
1901 bOk
= FillRangeDescriptor( aDesc
, aCellRange
);
1902 OSL_ENSURE( bOk
, "failed to get SwRangeDescriptor" );
1907 sal_Int32 nColSpan
= aDesc
.nRight
- aDesc
.nLeft
+ 1;
1908 sal_Int32 nRowSpan
= aDesc
.nBottom
- aDesc
.nTop
+ 1;
1909 OSL_ENSURE( nColSpan
== 1 || nRowSpan
== 1,
1910 "unexpected range of selected cells" );
1912 OUString aText
; // label text to be returned
1913 bool bReturnEmptyText
= false;
1914 bool bUseCol
= true;
1915 if (eLabelOrigin
== chart2::data::LabelOrigin_COLUMN
)
1917 else if (eLabelOrigin
== chart2::data::LabelOrigin_ROW
)
1919 else if (eLabelOrigin
== chart2::data::LabelOrigin_SHORT_SIDE
)
1921 bUseCol
= nColSpan
< nRowSpan
;
1922 bReturnEmptyText
= nColSpan
== nRowSpan
;
1924 else if (eLabelOrigin
== chart2::data::LabelOrigin_LONG_SIDE
)
1926 bUseCol
= nColSpan
> nRowSpan
;
1927 bReturnEmptyText
= nColSpan
== nRowSpan
;
1930 OSL_FAIL( "unexpected case" );
1933 // build label sequence
1935 sal_Int32 nSeqLen
= bUseCol
? nColSpan
: nRowSpan
;
1936 aLabels
.realloc( nSeqLen
);
1937 OUString
*pLabels
= aLabels
.getArray();
1938 for (sal_Int32 i
= 0; i
< nSeqLen
; ++i
)
1940 if (!bReturnEmptyText
)
1942 aText
= bUseCol
? m_aColLabelText
: m_aRowLabelText
;
1943 sal_Int32 nCol
= aDesc
.nLeft
;
1944 sal_Int32 nRow
= aDesc
.nTop
;
1949 OUString
aCellName( sw_GetCellName( nCol
, nRow
) );
1951 sal_Int32 nLen
= aCellName
.getLength();
1954 const sal_Unicode
*pBuf
= aCellName
.getStr();
1955 const sal_Unicode
*pEnd
= pBuf
+ nLen
;
1956 while (pBuf
< pEnd
&& ('0' > *pBuf
|| *pBuf
> '9'))
1958 // start of number found?
1959 if (pBuf
< pEnd
&& ('0' <= *pBuf
&& *pBuf
<= '9'))
1962 std::u16string_view aNew
;
1965 aRplc
= "%COLUMNLETTER";
1966 aNew
= aCellName
.subView(0, pBuf
- aCellName
.getStr());
1970 aRplc
= "%ROWNUMBER";
1971 aNew
= std::u16string_view(pBuf
, (aCellName
.getStr() + nLen
) - pBuf
);
1973 aText
= aText
.replaceFirst( aRplc
, aNew
);
1985 ::sal_Int32 SAL_CALL
SwChartDataSequence::getNumberFormatKeyByIndex(
1986 ::sal_Int32
/*nIndex*/ )
1991 std::vector
< css::uno::Reference
< css::table::XCell
> > SwChartDataSequence::GetCells()
1994 throw lang::DisposedException();
1995 auto pTableFormat(GetFrameFormat());
1997 return std::vector
< css::uno::Reference
< css::table::XCell
> >();
1998 auto pTable(SwTable::FindTable(pTableFormat
));
1999 if(pTable
->IsTableComplex())
2000 return std::vector
< css::uno::Reference
< css::table::XCell
> >();
2001 SwRangeDescriptor aDesc
;
2002 if(!FillRangeDescriptor(aDesc
, GetCellRangeName(*pTableFormat
, *m_pTableCursor
)))
2003 return std::vector
< css::uno::Reference
< css::table::XCell
> >();
2004 return SwXCellRange::CreateXCellRange(m_pTableCursor
, *pTableFormat
, aDesc
)->GetCells();
2007 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getTextualData()
2009 SolarMutexGuard aGuard
;
2010 auto vCells(GetCells());
2011 uno::Sequence
< OUString
> vTextData(vCells
.size());
2012 std::transform(vCells
.begin(),
2014 vTextData
.getArray(),
2015 [] (decltype(vCells
)::value_type
& xCell
)
2016 { return static_cast<SwXCell
*>(xCell
.get())->getString(); });
2020 uno::Sequence
< uno::Any
> SAL_CALL
SwChartDataSequence::getData()
2022 SolarMutexGuard aGuard
;
2025 auto vCells(GetCells());
2026 uno::Sequence
< uno::Any
> vAnyData(vCells
.size());
2027 std::transform(vCells
.begin(),
2029 vAnyData
.getArray(),
2030 [] (decltype(vCells
)::value_type
& xCell
)
2031 { return static_cast<SwXCell
*>(xCell
.get())->GetAny(); });
2034 catch (const lang::DisposedException
&)
2036 TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" );
2038 return uno::Sequence
< uno::Any
>{};
2041 uno::Sequence
< double > SAL_CALL
SwChartDataSequence::getNumericalData()
2043 SolarMutexGuard aGuard
;
2044 auto vCells(GetCells());
2045 uno::Sequence
< double > vNumData(vCells
.size());
2046 std::transform(vCells
.begin(),
2048 vNumData
.getArray(),
2049 [] (decltype(vCells
)::value_type
& xCell
)
2050 { return static_cast<SwXCell
*>(xCell
.get())->GetForcedNumericalValue(); });
2054 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartDataSequence::createClone( )
2056 SolarMutexGuard aGuard
;
2058 throw lang::DisposedException();
2059 return new SwChartDataSequence( *this );
2062 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
SwChartDataSequence::getPropertySetInfo( )
2064 SolarMutexGuard aGuard
;
2066 throw lang::DisposedException();
2068 static uno::Reference
< beans::XPropertySetInfo
> xRes
= m_pPropSet
->getPropertySetInfo();
2072 void SAL_CALL
SwChartDataSequence::setPropertyValue(
2073 const OUString
& rPropertyName
,
2074 const uno::Any
& rValue
)
2076 SolarMutexGuard aGuard
;
2078 throw lang::DisposedException();
2080 if (rPropertyName
!= UNO_NAME_ROLE
)
2081 throw beans::UnknownPropertyException(rPropertyName
);
2083 if ( !(rValue
>>= m_aRole
) )
2084 throw lang::IllegalArgumentException();
2087 uno::Any SAL_CALL
SwChartDataSequence::getPropertyValue(
2088 const OUString
& rPropertyName
)
2090 SolarMutexGuard aGuard
;
2092 throw lang::DisposedException();
2094 if (!(rPropertyName
== UNO_NAME_ROLE
))
2095 throw beans::UnknownPropertyException(rPropertyName
);
2097 return uno::Any(m_aRole
);
2100 void SAL_CALL
SwChartDataSequence::addPropertyChangeListener(
2101 const OUString
& /*rPropertyName*/,
2102 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2104 OSL_FAIL( "not implemented" );
2107 void SAL_CALL
SwChartDataSequence::removePropertyChangeListener(
2108 const OUString
& /*rPropertyName*/,
2109 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/ )
2111 OSL_FAIL( "not implemented" );
2114 void SAL_CALL
SwChartDataSequence::addVetoableChangeListener(
2115 const OUString
& /*rPropertyName*/,
2116 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2118 OSL_FAIL( "not implemented" );
2121 void SAL_CALL
SwChartDataSequence::removeVetoableChangeListener(
2122 const OUString
& /*rPropertyName*/,
2123 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/ )
2125 OSL_FAIL( "not implemented" );
2128 OUString SAL_CALL
SwChartDataSequence::getImplementationName( )
2130 return u
"SwChartDataSequence"_ustr
;
2133 sal_Bool SAL_CALL
SwChartDataSequence::supportsService(const OUString
& rServiceName
)
2135 return cppu::supportsService(this, rServiceName
);
2138 uno::Sequence
< OUString
> SAL_CALL
SwChartDataSequence::getSupportedServiceNames( )
2140 return { u
"com.sun.star.chart2.data.DataSequence"_ustr
};
2143 void SwChartDataSequence::Notify( const SfxHint
& rHint
)
2145 if(rHint
.GetId() == SfxHintId::Dying
)
2146 m_pFormat
= nullptr;
2147 if(!m_pFormat
|| !m_pTableCursor
)
2149 m_pFormat
= nullptr;
2150 m_pTableCursor
.reset(nullptr);
2153 else if (rHint
.GetId() == SfxHintId::SwLegacyModify
2154 || rHint
.GetId() == SfxHintId::SwFormatChange
2155 || rHint
.GetId() == SfxHintId::SwAttrSetChange
2156 || rHint
.GetId() == SfxHintId::SwObjectDying
2157 || rHint
.GetId() == SfxHintId::SwUpdateAttr
)
2159 setModified( true );
2163 sal_Bool SAL_CALL
SwChartDataSequence::isModified( )
2165 SolarMutexGuard aGuard
;
2167 throw lang::DisposedException();
2172 void SAL_CALL
SwChartDataSequence::setModified(
2173 sal_Bool bModified
)
2175 SolarMutexGuard aGuard
;
2177 throw lang::DisposedException();
2180 LaunchModifiedEvent( m_aModifyListeners
, static_cast< XModifyBroadcaster
* >(this) );
2183 void SAL_CALL
SwChartDataSequence::addModifyListener(
2184 const uno::Reference
< util::XModifyListener
>& rxListener
)
2186 std::unique_lock
aGuard( GetChartMutex() );
2187 if (!m_bDisposed
&& rxListener
.is())
2188 m_aModifyListeners
.addInterface( aGuard
, rxListener
);
2191 void SAL_CALL
SwChartDataSequence::removeModifyListener(
2192 const uno::Reference
< util::XModifyListener
>& rxListener
)
2194 std::unique_lock
aGuard( GetChartMutex() );
2195 if (!m_bDisposed
&& rxListener
.is())
2196 m_aModifyListeners
.removeInterface( aGuard
, rxListener
);
2199 void SAL_CALL
SwChartDataSequence::disposing( const lang::EventObject
& rSource
)
2202 throw lang::DisposedException();
2203 if (rSource
.Source
== cppu::getXWeak(m_xDataProvider
.get()))
2205 m_xDataProvider
.clear();
2209 void SAL_CALL
SwChartDataSequence::dispose( )
2212 std::unique_lock
aGuard( GetChartMutex() );
2218 if (m_xDataProvider
.is())
2220 const SwTable
* pTable
= SwTable::FindTable( GetFrameFormat() );
2223 m_xDataProvider
->RemoveDataSequence( *pTable
, this );
2226 OSL_FAIL( "table missing" );
2229 //#i119653# The bug is crashed for an exception thrown by
2230 //SwCharDataSequence::setModified() because
2231 //the SwCharDataSequence object has been disposed.
2233 //Actually, the former design of SwClient will disconnect itself
2234 //from the notification list in its destructor.
2236 //But the SwCharDataSequence won't be destructed but disposed in code
2237 //(the data member SwChartDataSequence::bDisposed will be set to
2238 //TRUE), the relationship between client and modification is not
2241 //So any notification from modify object will lead to said
2242 //exception threw out. Recorrect the logic of code in
2243 //SwChartDataSequence::Dispose(), release the relationship
2245 if (m_pFormat
&& m_pFormat
->HasWriterListeners())
2248 m_pFormat
= nullptr;
2249 m_pTableCursor
.reset(nullptr);
2253 // require listeners to release references to this object
2254 lang::EventObject
aEvtObj( static_cast< chart2::data::XDataSequence
* >(this) );
2255 std::unique_lock
aGuard( GetChartMutex() );
2256 m_aModifyListeners
.disposeAndClear( aGuard
, aEvtObj
);
2257 m_aEvtListeners
.disposeAndClear( aGuard
, aEvtObj
);
2260 void SAL_CALL
SwChartDataSequence::addEventListener(
2261 const uno::Reference
< lang::XEventListener
>& rxListener
)
2263 std::unique_lock
aGuard( GetChartMutex() );
2264 if (!m_bDisposed
&& rxListener
.is())
2265 m_aEvtListeners
.addInterface( aGuard
, rxListener
);
2268 void SAL_CALL
SwChartDataSequence::removeEventListener(
2269 const uno::Reference
< lang::XEventListener
>& rxListener
)
2271 std::unique_lock
aGuard( GetChartMutex() );
2272 if (!m_bDisposed
&& rxListener
.is())
2273 m_aEvtListeners
.removeInterface( aGuard
, rxListener
);
2276 bool SwChartDataSequence::DeleteBox( const SwTableBox
&rBox
)
2279 throw lang::DisposedException();
2281 // to be set if the last box of the data-sequence was removed here
2282 bool bNowEmpty
= false;
2284 // if the implementation cursor gets affected (i.e. the box where it is located
2285 // in gets removed) we need to move it before that... (otherwise it does not need to change)
2287 const SwStartNode
* pPointStartNode
= m_pTableCursor
->GetPoint()->GetNode().FindTableBoxStartNode();
2288 const SwStartNode
* pMarkStartNode
= m_pTableCursor
->GetMark()->GetNode().FindTableBoxStartNode();
2290 if (!m_pTableCursor
->HasMark() || (pPointStartNode
== rBox
.GetSttNd() && pMarkStartNode
== rBox
.GetSttNd()))
2294 else if (pPointStartNode
== rBox
.GetSttNd() || pMarkStartNode
== rBox
.GetSttNd())
2296 sal_Int32 nPointRow
= -1, nPointCol
= -1;
2297 sal_Int32 nMarkRow
= -1, nMarkCol
= -1;
2298 const SwTable
* pTable
= SwTable::FindTable( GetFrameFormat() );
2299 OUString
aPointCellName( pTable
->GetTableBox( pPointStartNode
->GetIndex() )->GetName() );
2300 OUString
aMarkCellName( pTable
->GetTableBox( pMarkStartNode
->GetIndex() )->GetName() );
2302 SwXTextTable::GetCellPosition( aPointCellName
, nPointCol
, nPointRow
);
2303 SwXTextTable::GetCellPosition( aMarkCellName
, nMarkCol
, nMarkRow
);
2304 OSL_ENSURE( nPointRow
>= 0 && nPointCol
>= 0, "invalid row and col" );
2305 OSL_ENSURE( nMarkRow
>= 0 && nMarkCol
>= 0, "invalid row and col" );
2307 // move vertical or horizontal?
2308 OSL_ENSURE( nPointRow
== nMarkRow
|| nPointCol
== nMarkCol
,
2309 "row/col indices not matching" );
2310 OSL_ENSURE( nPointRow
!= nMarkRow
|| nPointCol
!= nMarkCol
,
2311 "point and mark are identical" );
2312 bool bMoveVertical
= (nPointCol
== nMarkCol
);
2313 bool bMoveHorizontal
= (nPointRow
== nMarkRow
);
2315 // get movement direction
2316 bool bMoveLeft
= false; // move left or right?
2317 bool bMoveUp
= false; // move up or down?
2320 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2321 bMoveUp
= nPointRow
> nMarkRow
;
2323 bMoveUp
= nMarkRow
> nPointRow
;
2325 else if (bMoveHorizontal
)
2327 if (pPointStartNode
== rBox
.GetSttNd()) // move point?
2328 bMoveLeft
= nPointCol
> nMarkCol
;
2330 bMoveLeft
= nMarkCol
> nPointCol
;
2333 OSL_FAIL( "neither vertical nor horizontal movement" );
2336 // get new box (position) to use...
2337 sal_Int32 nRow
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointRow
: nMarkRow
;
2338 sal_Int32 nCol
= (pPointStartNode
== rBox
.GetSttNd()) ? nPointCol
: nMarkCol
;
2340 nRow
+= bMoveUp
? -1 : +1;
2341 if (bMoveHorizontal
)
2342 nCol
+= bMoveLeft
? -1 : +1;
2343 const OUString aNewCellName
= sw_GetCellName( nCol
, nRow
);
2344 SwTableBox
* pNewBox
= const_cast<SwTableBox
*>(pTable
->GetTableBox( aNewCellName
));
2346 if (pNewBox
) // set new position (cell range) to use
2348 // This is how you get the first content node of a row:
2349 // First get a SwNodeIndex pointing to the node after SwStartNode of the box...
2350 SwNodeIndex
aIdx( *pNewBox
->GetSttNd(), +1 );
2351 // This can be a SwContentNode, but might also be a table or section node,
2352 // therefore call GoNext
2353 SwContentNode
*pCNd
= aIdx
.GetNode().GetContentNode();
2355 pCNd
= SwNodes::GoNext(&aIdx
);
2356 // and then one can e.g. create a SwPosition:
2357 SwPosition
aNewPos( *pCNd
); // new position to be used with cursor
2359 // if the mark is to be changed, make sure there is one
2360 if (pMarkStartNode
== rBox
.GetSttNd() && !m_pTableCursor
->HasMark())
2361 m_pTableCursor
->SetMark();
2363 // set cursor to new position
2364 SwPosition
*pPos
= (pPointStartNode
== rBox
.GetSttNd()) ?
2365 m_pTableCursor
->GetPoint() : m_pTableCursor
->GetMark();
2368 *pPos
= std::move(aNewPos
);
2371 OSL_FAIL( "neither point nor mark available for change" );
2375 OSL_FAIL( "failed to get position" );
2382 void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor
&rRangeDesc
) const
2384 SwFrameFormat
* pTableFormat
= GetFrameFormat();
2387 SwTable
* pTable
= SwTable::FindTable( pTableFormat
);
2388 if(!pTable
->IsTableComplex())
2390 FillRangeDescriptor( rRangeDesc
, GetCellRangeName( *pTableFormat
, *m_pTableCursor
) );
2396 * Extends the data-sequence by new cells added at the end of the direction
2397 * the data-sequence points to.
2398 * If the cells are already within the range of the sequence nothing needs
2400 * If the cells are beyond the end of the sequence (are not adjacent to the
2401 * current last cell) nothing can be done. Only if the cells are adjacent to
2402 * the last cell they can be added.
2404 * @returns true if the data-sequence was changed.
2405 * @param bExtendCols - specifies if columns or rows are to be extended
2406 * @param nFirstNew - index of first new row/col to be included in data-sequence
2407 * @param nLastNew - index of last new row/col to be included in data-sequence
2409 void SwChartDataSequence::ExtendTo( bool bExtendCol
,
2410 sal_Int32 nFirstNew
, sal_Int32 nCount
)
2412 SwUnoTableCursor
* pUnoTableCursor
= dynamic_cast<SwUnoTableCursor
*>(&(*m_pTableCursor
));
2413 if (!pUnoTableCursor
)
2416 const SwStartNode
*pStartNd
= nullptr;
2417 const SwTableBox
*pStartBox
= nullptr;
2418 const SwTableBox
*pEndBox
= nullptr;
2420 const SwTable
* pTable
= SwTable::FindTable( GetFrameFormat() );
2421 OSL_ENSURE( !pTable
->IsTableComplex(), "table too complex" );
2422 if (nCount
< 1 || nFirstNew
< 0 || pTable
->IsTableComplex())
2425 // get range descriptor (cell range) for current data-sequence
2427 pStartNd
= pUnoTableCursor
->GetPoint()->GetNode().FindTableBoxStartNode();
2428 pEndBox
= pTable
->GetTableBox( pStartNd
->GetIndex() );
2429 const OUString
aEndBox( pEndBox
->GetName() );
2431 pStartNd
= pUnoTableCursor
->GetMark()->GetNode().FindTableBoxStartNode();
2432 pStartBox
= pTable
->GetTableBox( pStartNd
->GetIndex() );
2433 const OUString
aStartBox( pStartBox
->GetName() );
2435 SwRangeDescriptor aDesc
;
2436 // note that cell range here takes the newly added rows/cols already into account
2437 OUString sDescrip
= aStartBox
+ ":" + aEndBox
;
2438 FillRangeDescriptor( aDesc
, sDescrip
);
2440 bool bChanged
= false;
2441 OUString aNewStartCell
;
2442 OUString aNewEndCell
;
2443 if (bExtendCol
&& aDesc
.nBottom
+ 1 == nFirstNew
)
2445 // new column cells adjacent to the bottom of the
2446 // current data-sequence to be added...
2447 OSL_ENSURE( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2448 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2449 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
+ nCount
);
2452 else if (bExtendCol
&& aDesc
.nTop
- nCount
== nFirstNew
)
2454 // new column cells adjacent to the top of the
2455 // current data-sequence to be added...
2456 OSL_ENSURE( aDesc
.nLeft
== aDesc
.nRight
, "data-sequence is not a column" );
2457 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
- nCount
);
2458 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2461 else if (!bExtendCol
&& aDesc
.nRight
+ 1 == nFirstNew
)
2463 // new row cells adjacent to the right of the
2464 // current data-sequence to be added...
2465 OSL_ENSURE( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2466 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
, aDesc
.nTop
);
2467 aNewEndCell
= sw_GetCellName(aDesc
.nRight
+ nCount
, aDesc
.nBottom
);
2470 else if (!bExtendCol
&& aDesc
.nLeft
- nCount
== nFirstNew
)
2472 // new row cells adjacent to the left of the
2473 // current data-sequence to be added...
2474 OSL_ENSURE( aDesc
.nTop
== aDesc
.nBottom
, "data-sequence is not a row" );
2475 aNewStartCell
= sw_GetCellName(aDesc
.nLeft
- nCount
, aDesc
.nTop
);
2476 aNewEndCell
= sw_GetCellName(aDesc
.nRight
, aDesc
.nBottom
);
2482 // move table cursor to new start and end of data-sequence
2483 const SwTableBox
*pNewStartBox
= pTable
->GetTableBox( aNewStartCell
);
2484 const SwTableBox
*pNewEndBox
= pTable
->GetTableBox( aNewEndCell
);
2485 pUnoTableCursor
->SetMark();
2486 pUnoTableCursor
->GetPoint()->Assign( *pNewEndBox
->GetSttNd() );
2487 pUnoTableCursor
->GetMark()->Assign( *pNewStartBox
->GetSttNd() );
2488 pUnoTableCursor
->Move( fnMoveForward
, GoInNode
);
2489 pUnoTableCursor
->MakeBoxSels();
2493 SwChartLabeledDataSequence::SwChartLabeledDataSequence()
2495 m_bDisposed
= false;
2498 SwChartLabeledDataSequence::~SwChartLabeledDataSequence()
2502 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getValues( )
2504 SolarMutexGuard aGuard
;
2506 throw lang::DisposedException();
2510 void SwChartLabeledDataSequence::SetDataSequence(
2511 uno::Reference
< chart2::data::XDataSequence
>& rxDest
,
2512 const uno::Reference
< chart2::data::XDataSequence
>& rxSource
)
2514 uno::Reference
< util::XModifyListener
> xML(this);
2515 uno::Reference
< lang::XEventListener
> xEL(this);
2517 // stop listening to old data-sequence
2518 uno::Reference
< util::XModifyBroadcaster
> xMB( rxDest
, uno::UNO_QUERY
);
2520 xMB
->removeModifyListener( xML
);
2521 uno::Reference
< lang::XComponent
> xC( rxDest
, uno::UNO_QUERY
);
2523 xC
->removeEventListener( xEL
);
2527 // start listening to new data-sequence
2528 xC
.set( rxDest
, uno::UNO_QUERY
);
2530 xC
->addEventListener( xEL
);
2531 xMB
.set( rxDest
, uno::UNO_QUERY
);
2533 xMB
->addModifyListener( xML
);
2536 void SAL_CALL
SwChartLabeledDataSequence::setValues(
2537 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2539 SolarMutexGuard aGuard
;
2541 throw lang::DisposedException();
2543 if (m_xData
!= rxSequence
)
2545 SetDataSequence( m_xData
, rxSequence
);
2546 // inform listeners of changes
2547 LaunchModifiedEvent( m_aModifyListeners
, static_cast< XModifyBroadcaster
* >(this) );
2551 uno::Reference
< chart2::data::XDataSequence
> SAL_CALL
SwChartLabeledDataSequence::getLabel( )
2553 SolarMutexGuard aGuard
;
2555 throw lang::DisposedException();
2559 void SAL_CALL
SwChartLabeledDataSequence::setLabel(
2560 const uno::Reference
< chart2::data::XDataSequence
>& rxSequence
)
2562 SolarMutexGuard aGuard
;
2564 throw lang::DisposedException();
2566 if (m_xLabels
!= rxSequence
)
2568 SetDataSequence( m_xLabels
, rxSequence
);
2569 // inform listeners of changes
2570 LaunchModifiedEvent( m_aModifyListeners
, static_cast< XModifyBroadcaster
* >(this) );
2574 uno::Reference
< util::XCloneable
> SAL_CALL
SwChartLabeledDataSequence::createClone( )
2576 SolarMutexGuard aGuard
;
2578 throw lang::DisposedException();
2580 uno::Reference
< util::XCloneable
> xDataCloneable( m_xData
, uno::UNO_QUERY
);
2581 uno::Reference
< util::XCloneable
> xLabelsCloneable( m_xLabels
, uno::UNO_QUERY
);
2582 rtl::Reference
<SwChartLabeledDataSequence
> pRes
= new SwChartLabeledDataSequence();
2583 if (xDataCloneable
.is())
2585 uno::Reference
< chart2::data::XDataSequence
> xDataClone( xDataCloneable
->createClone(), uno::UNO_QUERY
);
2586 pRes
->setValues( xDataClone
);
2589 if (xLabelsCloneable
.is())
2591 uno::Reference
< chart2::data::XDataSequence
> xLabelsClone( xLabelsCloneable
->createClone(), uno::UNO_QUERY
);
2592 pRes
->setLabel( xLabelsClone
);
2597 OUString SAL_CALL
SwChartLabeledDataSequence::getImplementationName( )
2599 return u
"SwChartLabeledDataSequence"_ustr
;
2602 sal_Bool SAL_CALL
SwChartLabeledDataSequence::supportsService(
2603 const OUString
& rServiceName
)
2605 return cppu::supportsService(this, rServiceName
);
2608 uno::Sequence
< OUString
> SAL_CALL
SwChartLabeledDataSequence::getSupportedServiceNames( )
2610 return { u
"com.sun.star.chart2.data.LabeledDataSequence"_ustr
};
2613 void SAL_CALL
SwChartLabeledDataSequence::disposing(
2614 const lang::EventObject
& rSource
)
2616 std::unique_lock
aGuard( GetChartMutex() );
2617 uno::Reference
< uno::XInterface
> xRef( rSource
.Source
);
2618 if (xRef
== m_xData
)
2620 if (xRef
== m_xLabels
)
2622 if (!m_xData
.is() && !m_xLabels
.is())
2629 void SAL_CALL
SwChartLabeledDataSequence::modified(
2630 const lang::EventObject
& rEvent
)
2632 if (rEvent
.Source
== m_xData
|| rEvent
.Source
== m_xLabels
)
2634 LaunchModifiedEvent( m_aModifyListeners
, static_cast< XModifyBroadcaster
* >(this) );
2638 void SAL_CALL
SwChartLabeledDataSequence::addModifyListener(
2639 const uno::Reference
< util::XModifyListener
>& rxListener
)
2641 std::unique_lock
aGuard( GetChartMutex() );
2642 if (!m_bDisposed
&& rxListener
.is())
2643 m_aModifyListeners
.addInterface( aGuard
, rxListener
);
2646 void SAL_CALL
SwChartLabeledDataSequence::removeModifyListener(
2647 const uno::Reference
< util::XModifyListener
>& rxListener
)
2649 std::unique_lock
aGuard( GetChartMutex() );
2650 if (!m_bDisposed
&& rxListener
.is())
2651 m_aModifyListeners
.removeInterface( aGuard
, rxListener
);
2654 void SAL_CALL
SwChartLabeledDataSequence::dispose( )
2656 std::unique_lock
aGuard( GetChartMutex() );
2661 // require listeners to release references to this object
2662 lang::EventObject
aEvtObj( static_cast< chart2::data::XLabeledDataSequence
* >(this) );
2663 m_aModifyListeners
.disposeAndClear( aGuard
, aEvtObj
);
2664 m_aEventListeners
.disposeAndClear( aGuard
, aEvtObj
);
2667 void SAL_CALL
SwChartLabeledDataSequence::addEventListener(
2668 const uno::Reference
< lang::XEventListener
>& rxListener
)
2670 std::unique_lock
aGuard( GetChartMutex() );
2671 if (!m_bDisposed
&& rxListener
.is())
2672 m_aEventListeners
.addInterface( aGuard
, rxListener
);
2675 void SAL_CALL
SwChartLabeledDataSequence::removeEventListener(
2676 const uno::Reference
< lang::XEventListener
>& rxListener
)
2678 std::unique_lock
aGuard( GetChartMutex() );
2679 if (!m_bDisposed
&& rxListener
.is())
2680 m_aEventListeners
.removeInterface( aGuard
, rxListener
);
2683 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */