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