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