LibreOffice Module sc (master)  1
charthelper.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 <charthelper.hxx>
21 #include <document.hxx>
22 #include <drwlayer.hxx>
23 #include <rangelst.hxx>
24 #include <chartlis.hxx>
25 #include <docuno.hxx>
26 
28 #include <svx/svditer.hxx>
29 #include <svx/svdoole2.hxx>
30 #include <svx/svdpage.hxx>
31 #include <svtools/embedhlp.hxx>
32 #include <tools/diagnose_ex.h>
33 
34 #include <com/sun/star/chart2/XChartDocument.hpp>
35 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
36 #include <com/sun/star/embed/XEmbeddedObject.hpp>
37 #include <com/sun/star/util/XModifiable.hpp>
38 
39 using namespace com::sun::star;
40 using ::com::sun::star::uno::Reference;
41 
42 namespace
43 {
44 
45 sal_uInt16 lcl_DoUpdateCharts( ScDocument& rDoc )
46 {
47  ScDrawLayer* pModel = rDoc.GetDrawLayer();
48  if (!pModel)
49  return 0;
50 
51  sal_uInt16 nFound = 0;
52 
53  sal_uInt16 nPageCount = pModel->GetPageCount();
54  for (sal_uInt16 nPageNo=0; nPageNo<nPageCount; nPageNo++)
55  {
56  SdrPage* pPage = pModel->GetPage(nPageNo);
57  OSL_ENSURE(pPage,"Page ?");
58 
59  SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
60  SdrObject* pObject = aIter.Next();
61  while (pObject)
62  {
63  if ( pObject->GetObjIdentifier() == OBJ_OLE2 && ScDocument::IsChart( pObject ) )
64  {
65  OUString aName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName();
66  rDoc.UpdateChart( aName );
67  ++nFound;
68  }
69  pObject = aIter.Next();
70  }
71  }
72  return nFound;
73 }
74 
75 bool lcl_AdjustRanges( ScRangeList& rRanges, SCTAB nSourceTab, SCTAB nDestTab, SCTAB nTabCount )
76 {
77  //TODO: if multiple sheets are copied, update references into the other copied sheets?
78 
79  bool bChanged = false;
80 
81  for ( size_t i=0, nCount = rRanges.size(); i < nCount; i++ )
82  {
83  ScRange & rRange = rRanges[ i ];
84  if ( rRange.aStart.Tab() == nSourceTab && rRange.aEnd.Tab() == nSourceTab )
85  {
86  rRange.aStart.SetTab( nDestTab );
87  rRange.aEnd.SetTab( nDestTab );
88  bChanged = true;
89  }
90  if ( rRange.aStart.Tab() >= nTabCount )
91  {
92  rRange.aStart.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
93  bChanged = true;
94  }
95  if ( rRange.aEnd.Tab() >= nTabCount )
96  {
97  rRange.aEnd.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
98  bChanged = true;
99  }
100  }
101 
102  return bChanged;
103 }
104 
105 }//end anonymous namespace
106 
107 // ScChartHelper
108 //static
110 {
111  return lcl_DoUpdateCharts( rDoc );
112 }
113 
114 void ScChartHelper::AdjustRangesOfChartsOnDestinationPage( const ScDocument& rSrcDoc, ScDocument& rDestDoc, const SCTAB nSrcTab, const SCTAB nDestTab )
115 {
116  ScDrawLayer* pDrawLayer = rDestDoc.GetDrawLayer();
117  if( !pDrawLayer )
118  return;
119 
120  SdrPage* pDestPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nDestTab));
121  if( !pDestPage )
122  return;
123 
124  SdrObjListIter aIter( pDestPage, SdrIterMode::Flat );
125  SdrObject* pObject = aIter.Next();
126  while( pObject )
127  {
128  if( pObject->GetObjIdentifier() == OBJ_OLE2 && static_cast<SdrOle2Obj*>(pObject)->IsChart() )
129  {
130  OUString aChartName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName();
131 
132  Reference< chart2::XChartDocument > xChartDoc( rDestDoc.GetChartByName( aChartName ) );
133  Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
134  if( xChartDoc.is() && xReceiver.is() && !xChartDoc->hasInternalDataProvider() )
135  {
136  ::std::vector< ScRangeList > aRangesVector;
137  rDestDoc.GetChartRanges( aChartName, aRangesVector, rSrcDoc );
138 
139  for( ScRangeList& rScRangeList : aRangesVector )
140  {
141  lcl_AdjustRanges( rScRangeList, nSrcTab, nDestTab, rDestDoc.GetTableCount() );
142  }
143  rDestDoc.SetChartRanges( aChartName, aRangesVector );
144  }
145  }
146  pObject = aIter.Next();
147  }
148 }
149 
151 {
152  ScDrawLayer* pDrawLayer = rDestDoc.GetDrawLayer();
153  if( !pDrawLayer )
154  return;
155 
156  SdrPage* pDestPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nDestTab));
157  if( !pDestPage )
158  return;
159 
160  SdrObjListIter aIter( pDestPage, SdrIterMode::Flat );
161  SdrObject* pObject = aIter.Next();
162  while( pObject )
163  {
164  if( pObject->GetObjIdentifier() == OBJ_OLE2 && static_cast<SdrOle2Obj*>(pObject)->IsChart() )
165  {
166  OUString aChartName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName();
167  Reference< chart2::XChartDocument > xChartDoc( rDestDoc.GetChartByName( aChartName ) );
168  Reference< util::XModifiable > xModif(xChartDoc, uno::UNO_QUERY_THROW);
169  xModif->setModified( true);
170  }
171  pObject = aIter.Next();
172  }
173 }
174 
175 uno::Reference< chart2::XChartDocument > ScChartHelper::GetChartFromSdrObject( const SdrObject* pObject )
176 {
177  uno::Reference< chart2::XChartDocument > xReturn;
178  if( pObject )
179  {
180  if( pObject->GetObjIdentifier() == OBJ_OLE2 && static_cast<const SdrOle2Obj*>(pObject)->IsChart() )
181  {
182  uno::Reference< embed::XEmbeddedObject > xIPObj = static_cast<const SdrOle2Obj*>(pObject)->GetObjRef();
183  if( xIPObj.is() )
184  {
186  uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
187  xReturn.set( uno::Reference< chart2::XChartDocument >( xComponent, uno::UNO_QUERY ) );
188  }
189  }
190  }
191  return xReturn;
192 }
193 
194 void ScChartHelper::GetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
195  std::vector< OUString >& rRanges )
196 {
197  rRanges.clear();
198  uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
199  if( !xDataSource.is() )
200  return;
201 
202  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
203  rRanges.reserve(2*aLabeledDataSequences.getLength());
204  for(const uno::Reference<chart2::data::XLabeledDataSequence>& xLabeledSequence : aLabeledDataSequences)
205  {
206  if(!xLabeledSequence.is())
207  continue;
208  uno::Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel());
209  uno::Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues());
210 
211  if (xLabel.is())
212  rRanges.push_back( xLabel->getSourceRangeRepresentation() );
213  if (xValues.is())
214  rRanges.push_back( xValues->getSourceRangeRepresentation() );
215  }
216 }
217 
218 void ScChartHelper::SetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
219  const uno::Sequence< OUString >& rRanges )
220 {
221  uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
222  if( !xDataSource.is() )
223  return;
224  uno::Reference< chart2::data::XDataProvider > xDataProvider = xChartDoc->getDataProvider();
225  if( !xDataProvider.is() )
226  return;
227 
228  xChartDoc->lockControllers();
229 
230  try
231  {
232  OUString aPropertyNameRole( "Role" );
233 
234  uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
235  sal_Int32 nRange=0;
236  for( uno::Reference<chart2::data::XLabeledDataSequence>& xLabeledSequence : asNonConstRange(aLabeledDataSequences) )
237  {
238  if( nRange >= rRanges.getLength() )
239  break;
240 
241  if(!xLabeledSequence.is())
242  continue;
243  uno::Reference< beans::XPropertySet > xLabel( xLabeledSequence->getLabel(), uno::UNO_QUERY );
244  uno::Reference< beans::XPropertySet > xValues( xLabeledSequence->getValues(), uno::UNO_QUERY );
245 
246  if( xLabel.is())
247  {
248  uno::Reference< chart2::data::XDataSequence > xNewSeq(
249  xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
250 
251  uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
252  if( xNewProps.is() )
253  xNewProps->setPropertyValue( aPropertyNameRole, xLabel->getPropertyValue( aPropertyNameRole ) );
254 
255  xLabeledSequence->setLabel( xNewSeq );
256  }
257 
258  if( nRange >= rRanges.getLength() )
259  break;
260 
261  if( xValues.is())
262  {
263  uno::Reference< chart2::data::XDataSequence > xNewSeq(
264  xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
265 
266  uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
267  if( xNewProps.is() )
268  xNewProps->setPropertyValue( aPropertyNameRole, xValues->getPropertyValue( aPropertyNameRole ) );
269 
270  xLabeledSequence->setValues( xNewSeq );
271  }
272  }
273  }
274  catch (const uno::Exception&)
275  {
276  TOOLS_WARN_EXCEPTION( "sc", "Exception in ScChartHelper::SetChartRanges - invalid range string?");
277  }
278 
279  xChartDoc->unlockControllers();
280 }
281 
282 void ScChartHelper::AddRangesIfProtectedChart( ScRangeListVector& rRangesVector, const ScDocument& rDocument, SdrObject* pObject )
283 {
284  if ( !(pObject && ( pObject->GetObjIdentifier() == OBJ_OLE2 )) )
285  return;
286 
287  SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
288  if ( !(pSdrOle2Obj && pSdrOle2Obj->IsChart()) )
289  return;
290 
291  const uno::Reference< embed::XEmbeddedObject >& xEmbeddedObj = pSdrOle2Obj->GetObjRef();
292  if ( !xEmbeddedObj.is() )
293  return;
294 
295  bool bDisableDataTableDialog = false;
296  sal_Int32 nOldState = xEmbeddedObj->getCurrentState();
298  uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
299  if ( xProps.is() &&
300  ( xProps->getPropertyValue("DisableDataTableDialog") >>= bDisableDataTableDialog ) &&
301  bDisableDataTableDialog )
302  {
303  ScChartListenerCollection* pCollection = rDocument.GetChartListenerCollection();
304  if (pCollection)
305  {
306  const OUString& aChartName = pSdrOle2Obj->GetPersistName();
307  const ScChartListener* pListener = pCollection->findByName(aChartName);
308  if (pListener)
309  {
310  const ScRangeListRef& rRangeList = pListener->GetRangeList();
311  if ( rRangeList.is() )
312  {
313  rRangesVector.push_back( *rRangeList );
314  }
315  }
316  }
317  }
318  if ( xEmbeddedObj->getCurrentState() != nOldState )
319  {
320  xEmbeddedObj->changeState( nOldState );
321  }
322 }
323 
324 void ScChartHelper::FillProtectedChartRangesVector( ScRangeListVector& rRangesVector, const ScDocument& rDocument, const SdrPage* pPage )
325 {
326  if ( pPage )
327  {
328  SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
329  SdrObject* pObject = aIter.Next();
330  while ( pObject )
331  {
332  AddRangesIfProtectedChart( rRangesVector, rDocument, pObject );
333  pObject = aIter.Next();
334  }
335  }
336 }
337 
338 void ScChartHelper::GetChartNames( ::std::vector< OUString >& rChartNames, const SdrPage* pPage )
339 {
340  if ( !pPage )
341  return;
342 
343  SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
344  SdrObject* pObject = aIter.Next();
345  while ( pObject )
346  {
347  if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
348  {
349  SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
350  if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
351  {
352  rChartNames.push_back( pSdrOle2Obj->GetPersistName() );
353  }
354  }
355  pObject = aIter.Next();
356  }
357 }
358 
360  const ScRangeListVector& rRangesVector, const ::std::vector< OUString >& rExcludedChartNames, bool bSameDoc )
361 {
362  if ( !(pPage && pModelObj) )
363  return;
364 
365  size_t nRangeListCount = rRangesVector.size();
366  size_t nRangeList = 0;
367  SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
368  SdrObject* pObject = aIter.Next();
369  while ( pObject )
370  {
371  if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
372  {
373  SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
374  if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
375  {
376  const OUString& aChartName = pSdrOle2Obj->GetPersistName();
377  ::std::vector< OUString >::const_iterator aEnd = rExcludedChartNames.end();
378  ::std::vector< OUString >::const_iterator aFound = ::std::find( rExcludedChartNames.begin(), aEnd, aChartName );
379  if ( aFound == aEnd )
380  {
381  const uno::Reference< embed::XEmbeddedObject >& xEmbeddedObj = pSdrOle2Obj->GetObjRef();
382  if ( xEmbeddedObj.is() && ( nRangeList < nRangeListCount ) )
383  {
384  bool bDisableDataTableDialog = false;
386  uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
387  if ( xProps.is() &&
388  ( xProps->getPropertyValue("DisableDataTableDialog") >>= bDisableDataTableDialog ) &&
389  bDisableDataTableDialog )
390  {
391  if ( bSameDoc )
392  {
394  if (pCollection && !pCollection->findByName(aChartName))
395  {
396  ScRangeList aRangeList( rRangesVector[ nRangeList++ ] );
397  ScRangeListRef rRangeList( new ScRangeList( aRangeList ) );
398  ScChartListener* pChartListener = new ScChartListener( aChartName, rDoc, rRangeList );
399  pCollection->insert( pChartListener );
400  pChartListener->StartListeningTo();
401  }
402  }
403  else
404  {
405  xProps->setPropertyValue("DisableDataTableDialog",
406  uno::makeAny( false ) );
407  xProps->setPropertyValue("DisableComplexChartTypes",
408  uno::makeAny( false ) );
409  }
410  }
411  }
412 
413  if (pModelObj->HasChangesListeners())
414  {
415  tools::Rectangle aRectangle = pSdrOle2Obj->GetSnapRect();
416  ScRange aRange( rDoc.GetRange( nTab, aRectangle ) );
417  ScRangeList aChangeRanges( aRange );
418 
419  uno::Sequence< beans::PropertyValue > aProperties{
420  comphelper::makePropertyValue("Name", aChartName)
421  };
422 
423  pModelObj->NotifyChanges( "insert-chart", aChangeRanges, aProperties );
424  }
425  }
426  }
427  }
428  pObject = aIter.Next();
429  }
430 }
431 
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool is() const
bool IsChart() const
static void FillProtectedChartRangesVector(ScRangeListVector &rRangesVector, const ScDocument &rDocument, const SdrPage *pPage)
ScAddress aStart
Definition: address.hxx:499
css::uno::Reference< css::embed::XEmbeddedObject > const & GetObjRef() const
static css::uno::Reference< css::chart2::XChartDocument > GetChartFromSdrObject(const SdrObject *pObject)
bool insert(ScChartListener *pListener)
Definition: chartlis.cxx:386
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
ScRangeListRef GetRangeList() const
Definition: chartlis.cxx:184
ScAddress aEnd
Definition: address.hxx:500
SC_DLLPUBLIC ScRange GetRange(SCTAB nTab, const tools::Rectangle &rMMRect, bool bHiddenAsZero=true) const
Definition: documen3.cxx:1802
virtual SdrObjKind GetObjIdentifier() const
virtual const tools::Rectangle & GetSnapRect() const override
EmbeddedObjectRef * pObject
css::uno::Reference< css::chart2::XChartDocument > GetChartByName(std::u16string_view rChartName)
Definition: documen5.cxx:138
void UpdateChart(const OUString &rName)
Definition: documen5.cxx:335
static void CreateProtectedChartListenersAndNotify(ScDocument &rDoc, const SdrPage *pPage, ScModelObj *pModelObj, SCTAB nTab, const ScRangeListVector &rRangesVector, const ::std::vector< OUString > &rExcludedChartNames, bool bSameDoc=true)
PropertiesInfo aProperties
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:314
int nCount
SCTAB Tab() const
Definition: address.hxx:270
void StartListeningTo()
Definition: chartlis.cxx:262
static void AddRangesIfProtectedChart(ScRangeListVector &rRangesVector, const ScDocument &rDocument, SdrObject *pObject)
static void AdjustRangesOfChartsOnDestinationPage(const ScDocument &rSrcDoc, ScDocument &rDestDoc, const SCTAB nSrcTab, const SCTAB nDestTab)
static void GetChartNames(::std::vector< OUString > &rChartNames, const SdrPage *pPage)
void SetTab(SCTAB nTabP)
Definition: address.hxx:282
ScChartListener * findByName(const OUString &rName)
Definition: chartlis.cxx:401
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1058
#define TOOLS_WARN_EXCEPTION(area, stream)
int i
static void GetChartRanges(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc, std::vector< OUString > &rRanges)
const SdrPage * GetPage(sal_uInt16 nPgNum) const
size_t size() const
Definition: rangelst.hxx:89
static void UpdateChartsOnDestinationPage(ScDocument &rDestDoc, const SCTAB nDestTab)
::std::vector< ScRangeList > ScRangeListVector
Definition: charthelper.hxx:29
void NotifyChanges(const OUString &rOperation, const ScRangeList &rRanges, const css::uno::Sequence< css::beans::PropertyValue > &rProperties)
Definition: docuno.cxx:3153
SdrObject * Next()
Any makeAny(Color const &value)
OUString aName
const OUString & GetPersistName() const
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2156
SC_DLLPUBLIC void GetChartRanges(std::u16string_view rChartName, std::vector< ScRangeList > &rRanges, const ScDocument &rSheetNameDoc)
Definition: documen5.cxx:168
static bool IsChart(const SdrObject *pObject)
Definition: documen9.cxx:203
static bool TryRunningState(const css::uno::Reference< css::embed::XEmbeddedObject > &)
bool HasChangesListeners() const
Definition: docuno.cxx:3144
void SetChartRanges(std::u16string_view rChartName, const std::vector< ScRangeList > &rRanges)
Definition: documen5.cxx:185
OBJ_OLE2
static void SetChartRanges(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc, const css::uno::Sequence< OUString > &rRanges)
static sal_uInt16 DoUpdateAllCharts(ScDocument &rDoc)
sal_uInt16 GetPageCount() const
sal_Int16 SCTAB
Definition: types.hxx:22