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