xref: /trunk/main/sc/source/core/tool/charthelper.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 #include "charthelper.hxx"
32 #include "document.hxx"
33 #include "drwlayer.hxx"
34 #include "rangelst.hxx"
35 #include "chartlis.hxx"
36 #include "docuno.hxx"
37 
38 //#include <vcl/svapp.hxx>
39 #include <svx/svditer.hxx>
40 #include <svx/svdoole2.hxx>
41 #include <svx/svdpage.hxx>
42 
43 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
44 
45 using namespace com::sun::star;
46 using ::com::sun::star::uno::Reference;
47 
48 
49 // ====================================================================
50 
51 namespace
52 {
53 
54 
55 sal_uInt16 lcl_DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc, sal_Bool bAllCharts )
56 {
57 	ScDrawLayer* pModel = pDoc->GetDrawLayer();
58 	if (!pModel)
59 		return 0;
60 
61 	sal_uInt16 nFound = 0;
62 
63 	sal_uInt16 nPageCount = pModel->GetPageCount();
64 	for (sal_uInt16 nPageNo=0; nPageNo<nPageCount; nPageNo++)
65 	{
66 		SdrPage* pPage = pModel->GetPage(nPageNo);
67 		DBG_ASSERT(pPage,"Page ?");
68 
69 		SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
70 		SdrObject* pObject = aIter.Next();
71 		while (pObject)
72 		{
73             if ( pObject->GetObjIdentifier() == OBJ_OLE2 && pDoc->IsChart( pObject ) )
74 			{
75                 String aName = ((SdrOle2Obj*)pObject)->GetPersistName();
76                 sal_Bool bHit = sal_True;
77                 if ( !bAllCharts )
78                 {
79                     ScRangeList aRanges;
80                     sal_Bool bColHeaders = sal_False;
81                     sal_Bool bRowHeaders = sal_False;
82                     pDoc->GetOldChartParameters( aName, aRanges, bColHeaders, bRowHeaders );
83                     bHit = aRanges.In( rPos );
84                 }
85                 if ( bHit )
86                 {
87                     pDoc->UpdateChart( aName );
88                     ++nFound;
89                 }
90 			}
91 			pObject = aIter.Next();
92 		}
93 	}
94 	return nFound;
95 }
96 
97 sal_Bool lcl_AdjustRanges( ScRangeList& rRanges, SCTAB nSourceTab, SCTAB nDestTab, SCTAB nTabCount )
98 {
99 	//!	if multiple sheets are copied, update references into the other copied sheets?
100 
101 	sal_Bool bChanged = sal_False;
102 
103 	sal_uLong nCount = rRanges.Count();
104 	for (sal_uLong i=0; i<nCount; i++)
105 	{
106 		ScRange* pRange = rRanges.GetObject(i);
107 		if ( pRange->aStart.Tab() == nSourceTab && pRange->aEnd.Tab() == nSourceTab )
108 		{
109 			pRange->aStart.SetTab( nDestTab );
110 			pRange->aEnd.SetTab( nDestTab );
111 			bChanged = sal_True;
112 		}
113 		if ( pRange->aStart.Tab() >= nTabCount )
114 		{
115 			pRange->aStart.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
116 			bChanged = sal_True;
117 		}
118 		if ( pRange->aEnd.Tab() >= nTabCount )
119 		{
120 			pRange->aEnd.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
121 			bChanged = sal_True;
122 		}
123 	}
124 
125 	return bChanged;
126 }
127 
128 }//end anonymous namespace
129 
130 // === ScChartHelper ======================================
131 
132 //static
133 sal_uInt16 ScChartHelper::DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc )
134 {
135     return lcl_DoUpdateCharts( rPos, pDoc, sal_False );
136 }
137 
138 //static
139 sal_uInt16 ScChartHelper::DoUpdateAllCharts( ScDocument* pDoc )
140 {
141     return lcl_DoUpdateCharts( ScAddress(), pDoc, sal_True );
142 }
143 
144 //static
145 void ScChartHelper::AdjustRangesOfChartsOnDestinationPage( ScDocument* pSrcDoc, ScDocument* pDestDoc, const SCTAB nSrcTab, const SCTAB nDestTab )
146 {
147     if( !pSrcDoc || !pDestDoc )
148         return;
149     ScDrawLayer* pDrawLayer = pDestDoc->GetDrawLayer();
150     if( !pDrawLayer )
151         return;
152 
153     SdrPage* pDestPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nDestTab));
154     if( pDestPage )
155     {
156         SdrObjListIter aIter( *pDestPage, IM_FLAT );
157         SdrObject* pObject = aIter.Next();
158         while( pObject )
159         {
160             if( pObject->GetObjIdentifier() == OBJ_OLE2 && ((SdrOle2Obj*)pObject)->IsChart() )
161             {
162                 String aChartName = ((SdrOle2Obj*)pObject)->GetPersistName();
163 
164                 Reference< chart2::XChartDocument > xChartDoc( pDestDoc->GetChartByName( aChartName ) );
165                 Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
166                 if( xChartDoc.is() && xReceiver.is() && !xChartDoc->hasInternalDataProvider() )
167                 {
168                     ::std::vector< ScRangeList > aRangesVector;
169                     pDestDoc->GetChartRanges( aChartName, aRangesVector, pSrcDoc );
170 
171                     ::std::vector< ScRangeList >::iterator aIt( aRangesVector.begin() );
172                     for( ; aIt!=aRangesVector.end(); aIt++ )
173                     {
174                         ScRangeList& rScRangeList( *aIt );
175                         lcl_AdjustRanges( rScRangeList, nSrcTab, nDestTab, pDestDoc->GetTableCount() );
176                     }
177                     pDestDoc->SetChartRanges( aChartName, aRangesVector );
178                 }
179             }
180             pObject = aIter.Next();
181         }
182     }
183 }
184 
185 //static
186 uno::Reference< chart2::XChartDocument > ScChartHelper::GetChartFromSdrObject( SdrObject* pObject )
187 {
188     uno::Reference< chart2::XChartDocument > xReturn;
189     if( pObject )
190     {
191         if( pObject->GetObjIdentifier() == OBJ_OLE2 && ((SdrOle2Obj*)pObject)->IsChart() )
192         {
193             uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
194             if( xIPObj.is() )
195             {
196                 svt::EmbeddedObjectRef::TryRunningState( xIPObj );
197                 uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
198                 xReturn.set( uno::Reference< chart2::XChartDocument >( xComponent, uno::UNO_QUERY ) );
199             }
200         }
201     }
202     return xReturn;
203 }
204 
205 void ScChartHelper::GetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
206             uno::Sequence< rtl::OUString >& rRanges )
207 {
208     rRanges.realloc(0);
209     uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
210     if( !xDataSource.is() )
211         return;
212     //uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider();
213 
214     uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
215     rRanges.realloc(2*aLabeledDataSequences.getLength());
216     sal_Int32 nRealCount=0;
217     for( sal_Int32 nN=0;nN<aLabeledDataSequences.getLength();nN++)
218     {
219         uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aLabeledDataSequences[nN] );
220         if(!xLabeledSequence.is())
221             continue;
222         uno::Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel());
223         uno::Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues());
224 
225         if( xLabel.is())
226             rRanges[nRealCount++] = xLabel->getSourceRangeRepresentation();
227         if( xValues.is())
228             rRanges[nRealCount++] = xValues->getSourceRangeRepresentation();
229     }
230     rRanges.realloc(nRealCount);
231 }
232 
233 void ScChartHelper::SetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
234             const uno::Sequence< rtl::OUString >& rRanges )
235 {
236     uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
237     if( !xDataSource.is() )
238         return;
239     uno::Reference< chart2::data::XDataProvider > xDataProvider = xChartDoc->getDataProvider();
240     if( !xDataProvider.is() )
241         return;
242 
243     uno::Reference< frame::XModel > xModel( xChartDoc, uno::UNO_QUERY );
244     if( xModel.is() )
245         xModel->lockControllers();
246 
247     try
248     {
249         rtl::OUString aPropertyNameRole( ::rtl::OUString::createFromAscii("Role") );
250 
251         uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
252         sal_Int32 nRange=0;
253         for( sal_Int32 nN=0; (nN<aLabeledDataSequences.getLength()) && (nRange<rRanges.getLength()); nN++ )
254         {
255             uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aLabeledDataSequences[nN] );
256             if(!xLabeledSequence.is())
257                 continue;
258             uno::Reference< beans::XPropertySet > xLabel( xLabeledSequence->getLabel(), uno::UNO_QUERY );
259             uno::Reference< beans::XPropertySet > xValues( xLabeledSequence->getValues(), uno::UNO_QUERY );
260 
261             if( xLabel.is())
262             {
263                 // the range string must be in Calc A1 format.
264                 uno::Reference< chart2::data::XDataSequence > xNewSeq(
265                     xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
266 
267                 uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
268                 if( xNewProps.is() )
269                     xNewProps->setPropertyValue( aPropertyNameRole, xLabel->getPropertyValue( aPropertyNameRole ) );
270 
271                 xLabeledSequence->setLabel( xNewSeq );
272             }
273 
274             if( !(nRange<rRanges.getLength()) )
275                 break;
276 
277             if( xValues.is())
278             {
279                 // the range string must be in Calc A1 format.
280                 uno::Reference< chart2::data::XDataSequence > xNewSeq(
281                     xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
282 
283                 uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
284                 if( xNewProps.is() )
285                     xNewProps->setPropertyValue( aPropertyNameRole, xValues->getPropertyValue( aPropertyNameRole ) );
286 
287                 xLabeledSequence->setValues( xNewSeq );
288             }
289         }
290     }
291     catch ( uno::Exception& ex )
292     {
293         (void)ex;
294         DBG_ERROR("Exception in ScChartHelper::SetChartRanges - invalid range string?");
295     }
296 
297     if( xModel.is() )
298         xModel->unlockControllers();
299 }
300 
301 void ScChartHelper::AddRangesIfProtectedChart( ScRangeListVector& rRangesVector, ScDocument* pDocument, SdrObject* pObject )
302 {
303     if ( pDocument && pObject && ( pObject->GetObjIdentifier() == OBJ_OLE2 ) )
304     {
305         SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
306         if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
307         {
308             uno::Reference< embed::XEmbeddedObject > xEmbeddedObj = pSdrOle2Obj->GetObjRef();
309             if ( xEmbeddedObj.is() )
310             {
311                 bool bDisableDataTableDialog = false;
312                 sal_Int32 nOldState = xEmbeddedObj->getCurrentState();
313                 svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
314                 uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
315                 if ( xProps.is() &&
316                      ( xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ) ) >>= bDisableDataTableDialog ) &&
317                      bDisableDataTableDialog )
318                 {
319                     ::rtl::OUString aChartName = pSdrOle2Obj->GetPersistName();
320                     ScRange aEmptyRange;
321                     ScChartListener aSearcher( aChartName, pDocument, aEmptyRange );
322                     sal_uInt16 nIndex = 0;
323                     ScChartListenerCollection* pCollection = pDocument->GetChartListenerCollection();
324                     if ( pCollection && pCollection->Search( &aSearcher, nIndex ) )
325                     {
326                         ScChartListener* pListener = static_cast< ScChartListener* >( pCollection->At( nIndex ) );
327                         if ( pListener )
328                         {
329                             const ScRangeListRef& rRangeList = pListener->GetRangeList();
330                             if ( rRangeList.Is() )
331                             {
332                                 rRangesVector.push_back( *rRangeList );
333                             }
334                         }
335                     }
336                 }
337                 if ( xEmbeddedObj->getCurrentState() != nOldState )
338                 {
339                     xEmbeddedObj->changeState( nOldState );
340                 }
341             }
342         }
343     }
344 }
345 
346 void ScChartHelper::FillProtectedChartRangesVector( ScRangeListVector& rRangesVector, ScDocument* pDocument, SdrPage* pPage )
347 {
348     if ( pDocument && pPage )
349     {
350         SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
351         SdrObject* pObject = aIter.Next();
352         while ( pObject )
353         {
354             AddRangesIfProtectedChart( rRangesVector, pDocument, pObject );
355             pObject = aIter.Next();
356         }
357     }
358 }
359 
360 void ScChartHelper::GetChartNames( ::std::vector< ::rtl::OUString >& rChartNames, SdrPage* pPage )
361 {
362     if ( pPage )
363     {
364         SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
365         SdrObject* pObject = aIter.Next();
366         while ( pObject )
367         {
368             if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
369             {
370                 SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
371                 if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
372                 {
373                     rChartNames.push_back( pSdrOle2Obj->GetPersistName() );
374                 }
375             }
376             pObject = aIter.Next();
377         }
378     }
379 }
380 
381 void ScChartHelper::CreateProtectedChartListenersAndNotify( ScDocument* pDoc, SdrPage* pPage, ScModelObj* pModelObj, SCTAB nTab,
382     const ScRangeListVector& rRangesVector, const ::std::vector< ::rtl::OUString >& rExcludedChartNames, bool bSameDoc )
383 {
384     if ( pDoc && pPage && pModelObj )
385     {
386         size_t nRangeListCount = rRangesVector.size();
387         size_t nRangeList = 0;
388         SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
389         SdrObject* pObject = aIter.Next();
390         while ( pObject )
391         {
392             if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
393             {
394                 SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
395                 if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
396                 {
397                     ::rtl::OUString aChartName = pSdrOle2Obj->GetPersistName();
398                     ::std::vector< ::rtl::OUString >::const_iterator aEnd = rExcludedChartNames.end();
399                     ::std::vector< ::rtl::OUString >::const_iterator aFound = ::std::find( rExcludedChartNames.begin(), aEnd, aChartName );
400                     if ( aFound == aEnd )
401                     {
402                         uno::Reference< embed::XEmbeddedObject > xEmbeddedObj = pSdrOle2Obj->GetObjRef();
403                         if ( xEmbeddedObj.is() && ( nRangeList < nRangeListCount ) )
404                         {
405                             bool bDisableDataTableDialog = false;
406                             svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
407                             uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
408                             if ( xProps.is() &&
409                                  ( xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ) ) >>= bDisableDataTableDialog ) &&
410                                  bDisableDataTableDialog )
411                             {
412                                 if ( bSameDoc )
413                                 {
414                                     ScRange aEmptyRange;
415                                     ScChartListener aSearcher( aChartName, pDoc, aEmptyRange );
416                                     sal_uInt16 nIndex = 0;
417                                     ScChartListenerCollection* pCollection = pDoc->GetChartListenerCollection();
418                                     if ( pCollection && !pCollection->Search( &aSearcher, nIndex ) )
419                                     {
420                                         ScRangeList aRangeList( rRangesVector[ nRangeList++ ] );
421                                         ScRangeListRef rRangeList( new ScRangeList( aRangeList ) );
422                                         ScChartListener* pChartListener = new ScChartListener( aChartName, pDoc, rRangeList );
423                                         pCollection->Insert( pChartListener );
424                                         pChartListener->StartListeningTo();
425                                     }
426                                 }
427                                 else
428                                 {
429                                     xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ),
430                                         uno::makeAny( sal_False ) );
431                                     xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableComplexChartTypes" ) ),
432                                         uno::makeAny( sal_False ) );
433                                 }
434                             }
435                         }
436 
437                         if ( pModelObj && pModelObj->HasChangesListeners() )
438                         {
439                             Rectangle aRectangle = pSdrOle2Obj->GetSnapRect();
440                             ScRange aRange( pDoc->GetRange( nTab, aRectangle ) );
441                             ScRangeList aChangeRanges;
442                             aChangeRanges.Append( aRange );
443 
444                             uno::Sequence< beans::PropertyValue > aProperties( 1 );
445                             aProperties[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) );
446                             aProperties[ 0 ].Value <<= aChartName;
447 
448                             pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-chart" ) ), aChangeRanges, aProperties );
449                         }
450                     }
451                 }
452             }
453             pObject = aIter.Next();
454         }
455     }
456 }
457