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