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