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