xref: /trunk/main/sc/source/core/tool/chartlis.cxx (revision b3f79822)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 #include <vcl/svapp.hxx>
30 
31 #include "chartlis.hxx"
32 #include "brdcst.hxx"
33 #include "document.hxx"
34 #include "reftokenhelper.hxx"
35 
36 using namespace com::sun::star;
37 using ::std::vector;
38 using ::std::list;
39 using ::std::hash_set;
40 using ::std::auto_ptr;
41 using ::std::unary_function;
42 using ::std::for_each;
43 
44 //2do: DocOption TimeOut?
45 //#define SC_CHARTTIMEOUT 1000		// eine Sekunde keine Aenderung/KeyEvent
46 
47 // Update chart listeners quickly, to get a similar behavior to loaded charts
48 // which register UNO listeners.
49 #define SC_CHARTTIMEOUT 10
50 
51 
52 // ====================================================================
53 
54 class ScChartUnoData
55 {
56 	uno::Reference< chart::XChartDataChangeEventListener >	xListener;
57 	uno::Reference< chart::XChartData >						xSource;
58 
59 public:
ScChartUnoData(const uno::Reference<chart::XChartDataChangeEventListener> & rL,const uno::Reference<chart::XChartData> & rS)60 			ScChartUnoData( const uno::Reference< chart::XChartDataChangeEventListener >& rL,
61 							const uno::Reference< chart::XChartData >& rS ) :
62 					xListener( rL ), xSource( rS ) {}
~ScChartUnoData()63 			~ScChartUnoData() {}
64 
GetListener() const65 	const uno::Reference< chart::XChartDataChangeEventListener >& GetListener() const	{ return xListener; }
GetSource() const66 	const uno::Reference< chart::XChartData >& GetSource() const						{ return xSource; }
67 };
68 
69 
70 // === ScChartListener ================================================
71 
ExternalRefListener(ScChartListener & rParent,ScDocument * pDoc)72 ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
73     mrParent(rParent), mpDoc(pDoc)
74 {
75 }
76 
~ExternalRefListener()77 ScChartListener::ExternalRefListener::~ExternalRefListener()
78 {
79     if (!mpDoc || mpDoc->IsInDtorClear())
80         // The document is being destroyed.  Do nothing.
81         return;
82 
83     // Make sure to remove all pointers to this object.
84     mpDoc->GetExternalRefManager()->removeLinkListener(this);
85 }
86 
notify(sal_uInt16 nFileId,ScExternalRefManager::LinkUpdateType eType)87 void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
88 {
89     switch (eType)
90     {
91         case ScExternalRefManager::LINK_MODIFIED:
92         {
93             if (maFileIds.count(nFileId))
94                 // We are listening to this external document.  Send an update
95                 // requst to the chart.
96                 mrParent.SetUpdateQueue();
97         }
98         break;
99         case ScExternalRefManager::LINK_BROKEN:
100             removeFileId(nFileId);
101         break;
102     }
103 }
104 
addFileId(sal_uInt16 nFileId)105 void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
106 {
107     maFileIds.insert(nFileId);
108 }
109 
removeFileId(sal_uInt16 nFileId)110 void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
111 {
112     maFileIds.erase(nFileId);
113 }
114 
getAllFileIds()115 hash_set<sal_uInt16>& ScChartListener::ExternalRefListener::getAllFileIds()
116 {
117     return maFileIds;
118 }
119 
120 // ----------------------------------------------------------------------------
121 
ScChartListener(const String & rName,ScDocument * pDocP,const ScRange & rRange)122 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
123         const ScRange& rRange ) :
124     StrData( rName ),
125     SvtListener(),
126     mpExtRefListener(NULL),
127     mpTokens(new vector<ScSharedTokenRef>),
128     pUnoData( NULL ),
129     pDoc( pDocP ),
130     bUsed( sal_False ),
131     bDirty( sal_False ),
132     bSeriesRangesScheduled( sal_False )
133 {
134     SetRangeList( rRange );
135 }
136 
ScChartListener(const String & rName,ScDocument * pDocP,const ScRangeListRef & rRangeList)137 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
138         const ScRangeListRef& rRangeList ) :
139     StrData( rName ),
140     SvtListener(),
141     mpExtRefListener(NULL),
142     mpTokens(new vector<ScSharedTokenRef>),
143     pUnoData( NULL ),
144     pDoc( pDocP ),
145     bUsed( sal_False ),
146     bDirty( sal_False ),
147     bSeriesRangesScheduled( sal_False )
148 {
149     ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
150 }
151 
ScChartListener(const String & rName,ScDocument * pDocP,vector<ScSharedTokenRef> * pTokens)152 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP, vector<ScSharedTokenRef>* pTokens ) :
153     StrData( rName ),
154     SvtListener(),
155     mpExtRefListener(NULL),
156     mpTokens(pTokens),
157     pUnoData( NULL ),
158     pDoc( pDocP ),
159     bUsed( sal_False ),
160     bDirty( sal_False ),
161     bSeriesRangesScheduled( sal_False )
162 {
163 }
164 
ScChartListener(const ScChartListener & r)165 ScChartListener::ScChartListener( const ScChartListener& r ) :
166     StrData( r ),
167     SvtListener(),
168     mpExtRefListener(NULL),
169     mpTokens(new vector<ScSharedTokenRef>(*r.mpTokens)),
170     pUnoData( NULL ),
171     pDoc( r.pDoc ),
172     bUsed( sal_False ),
173     bDirty( r.bDirty ),
174     bSeriesRangesScheduled( r.bSeriesRangesScheduled )
175 {
176     if ( r.pUnoData )
177         pUnoData = new ScChartUnoData( *r.pUnoData );
178 
179     if (r.mpExtRefListener.get())
180     {
181         // Re-register this new listener for the files that the old listener
182         // was listening to.
183 
184         ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
185         const hash_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
186         mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
187         hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
188         for (; itr != itrEnd; ++itr)
189         {
190             pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
191             mpExtRefListener->addFileId(*itr);
192         }
193     }
194 }
195 
~ScChartListener()196 ScChartListener::~ScChartListener()
197 {
198 	if ( HasBroadcaster() )
199 		EndListeningTo();
200 	delete pUnoData;
201 
202     if (mpExtRefListener.get())
203     {
204         // Stop listening to all external files.
205         ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
206         const hash_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
207         hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
208         for (; itr != itrEnd; ++itr)
209             pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
210     }
211 }
212 
Clone() const213 ScDataObject* ScChartListener::Clone() const
214 {
215 	return new ScChartListener( *this );
216 }
217 
SetUno(const uno::Reference<chart::XChartDataChangeEventListener> & rListener,const uno::Reference<chart::XChartData> & rSource)218 void ScChartListener::SetUno(
219 		const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
220 		const uno::Reference< chart::XChartData >& rSource )
221 {
222 //	DBG_ASSERT( rListener.is() && rSource.is(), "Nullpointer bei SetUno" );
223 	delete pUnoData;
224 	pUnoData = new ScChartUnoData( rListener, rSource );
225 }
226 
GetUnoListener() const227 uno::Reference< chart::XChartDataChangeEventListener > ScChartListener::GetUnoListener() const
228 {
229 	if ( pUnoData )
230 		return pUnoData->GetListener();
231 	return uno::Reference< chart::XChartDataChangeEventListener >();
232 }
233 
GetUnoSource() const234 uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
235 {
236 	if ( pUnoData )
237 		return pUnoData->GetSource();
238 	return uno::Reference< chart::XChartData >();
239 }
240 
Notify(SvtBroadcaster &,const SfxHint & rHint)241 void ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
242 {
243     const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
244     if (p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)))
245         SetUpdateQueue();
246 }
247 
Update()248 void ScChartListener::Update()
249 {
250 	if ( pDoc->IsInInterpreter() )
251 	{	// #73482# If interpreting do nothing and restart timer so we don't
252 		// interfere with interpreter and don't produce an Err522 or similar.
253 		// This may happen if we are rescheduled via Basic function.
254 		pDoc->GetChartListenerCollection()->StartTimer();
255 		return ;
256 	}
257 	if ( pUnoData )
258 	{
259 		bDirty = sal_False;
260 		//!	irgendwann mal erkennen, was sich innerhalb des Charts geaendert hat
261 		chart::ChartDataChangeEvent aEvent( pUnoData->GetSource(),
262 										chart::ChartDataChangeType_ALL,
263 										0, 0, 0, 0 );
264 		pUnoData->GetListener()->chartDataChanged( aEvent );
265 	}
266 	else if ( pDoc->GetAutoCalc() )
267 	{
268 		bDirty = sal_False;
269 		pDoc->UpdateChart( GetString());
270 	}
271 }
272 
GetRangeList() const273 ScRangeListRef ScChartListener::GetRangeList() const
274 {
275     ScRangeListRef aRLRef(new ScRangeList);
276     ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens);
277     return aRLRef;
278 }
279 
SetRangeList(const ScRangeListRef & rNew)280 void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
281 {
282     vector<ScSharedTokenRef> aTokens;
283     ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
284     mpTokens->swap(aTokens);
285 }
286 
SetRangeList(const ScRange & rRange)287 void ScChartListener::SetRangeList( const ScRange& rRange )
288 {
289     ScSharedTokenRef pToken;
290     ScRefTokenHelper::getTokenFromRange(pToken, rRange);
291     mpTokens->push_back(pToken);
292 }
293 
294 namespace {
295 
296 class StartEndListening : public unary_function<ScSharedTokenRef, void>
297 {
298 public:
StartEndListening(ScDocument * pDoc,ScChartListener & rParent,bool bStart)299     StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
300         mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
301 
operator ()(const ScSharedTokenRef & pToken)302     void operator() (const ScSharedTokenRef& pToken)
303     {
304         if (!ScRefTokenHelper::isRef(pToken))
305             return;
306 
307         bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
308         if (bExternal)
309         {
310             sal_uInt16 nFileId = pToken->GetIndex();
311             ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
312             ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
313             if (mbStart)
314             {
315                 pRefMgr->addLinkListener(nFileId, pExtRefListener);
316                 pExtRefListener->addFileId(nFileId);
317             }
318             else
319             {
320                 pRefMgr->removeLinkListener(nFileId, pExtRefListener);
321                 pExtRefListener->removeFileId(nFileId);
322             }
323         }
324         else
325         {
326             ScRange aRange;
327             ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal);
328             if (mbStart)
329                 startListening(aRange);
330             else
331                 endListening(aRange);
332         }
333     }
334 
335 private:
startListening(const ScRange & rRange)336     void startListening(const ScRange& rRange)
337     {
338         if (rRange.aStart == rRange.aEnd)
339             mpDoc->StartListeningCell(rRange.aStart, &mrParent);
340         else
341             mpDoc->StartListeningArea(rRange, &mrParent);
342     }
343 
endListening(const ScRange & rRange)344     void endListening(const ScRange& rRange)
345     {
346         if (rRange.aStart == rRange.aEnd)
347             mpDoc->EndListeningCell(rRange.aStart, &mrParent);
348         else
349             mpDoc->EndListeningArea(rRange, &mrParent);
350     }
351 
352 private:
353     ScDocument* mpDoc;
354     ScChartListener& mrParent;
355     bool mbStart;
356 };
357 
358 }
359 
StartListeningTo()360 void ScChartListener::StartListeningTo()
361 {
362     if (!mpTokens.get() || mpTokens->empty())
363         // no references to listen to.
364         return;
365 
366     for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, true));
367 }
368 
EndListeningTo()369 void ScChartListener::EndListeningTo()
370 {
371     if (!mpTokens.get() || mpTokens->empty())
372         // no references to listen to.
373         return;
374 
375     for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, false));
376 }
377 
378 
ChangeListening(const ScRangeListRef & rRangeListRef,sal_Bool bDirtyP)379 void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
380 			sal_Bool bDirtyP  )
381 {
382 	EndListeningTo();
383 	SetRangeList( rRangeListRef );
384 	StartListeningTo();
385 	if ( bDirtyP )
386 		SetDirty( sal_True );
387 }
388 
389 
UpdateScheduledSeriesRanges()390 void ScChartListener::UpdateScheduledSeriesRanges()
391 {
392 	if ( bSeriesRangesScheduled )
393 	{
394 		bSeriesRangesScheduled = sal_False;
395 		UpdateSeriesRanges();
396 	}
397 }
398 
399 
UpdateChartIntersecting(const ScRange & rRange)400 void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
401 {
402     ScSharedTokenRef pToken;
403     ScRefTokenHelper::getTokenFromRange(pToken, rRange);
404 
405     if (ScRefTokenHelper::intersects(*mpTokens, pToken))
406     {
407         // force update (chart has to be loaded), don't use ScChartListener::Update
408         pDoc->UpdateChart( GetString());
409     }
410 }
411 
412 
UpdateSeriesRanges()413 void ScChartListener::UpdateSeriesRanges()
414 {
415     ScRangeListRef pRangeList(new ScRangeList);
416     ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens);
417     pDoc->SetChartRangeList(GetString(), pRangeList);
418 }
419 
GetExtRefListener()420 ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
421 {
422     if (!mpExtRefListener.get())
423         mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
424 
425     return mpExtRefListener.get();
426 }
427 
SetUpdateQueue()428 void ScChartListener::SetUpdateQueue()
429 {
430     bDirty = true;
431     pDoc->GetChartListenerCollection()->StartTimer();
432 }
433 
operator ==(const ScChartListener & r)434 sal_Bool ScChartListener::operator==( const ScChartListener& r )
435 {
436     bool b1 = (mpTokens.get() && !mpTokens->empty());
437     bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
438 
439     if (pDoc != r.pDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
440         bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
441         GetString() != r.GetString() || b1 != b2)
442         return false;
443 
444     if (!b1 && !b2)
445         // both token list instances are empty.
446         return true;
447 
448     return *mpTokens == *r.mpTokens;
449 }
450 
451 // ============================================================================
452 
ScChartHiddenRangeListener()453 ScChartHiddenRangeListener::ScChartHiddenRangeListener()
454 {
455 }
456 
~ScChartHiddenRangeListener()457 ScChartHiddenRangeListener::~ScChartHiddenRangeListener()
458 {
459     // empty d'tor
460 }
461 
462 // === ScChartListenerCollection ======================================
463 
RangeListenerItem(const ScRange & rRange,ScChartHiddenRangeListener * p)464 ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& rRange, ScChartHiddenRangeListener* p) :
465     maRange(rRange), mpListener(p)
466 {
467 }
468 
ScChartListenerCollection(ScDocument * pDocP)469 ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
470 	ScStrCollection( 4, 4, sal_False ),
471 	pDoc( pDocP )
472 {
473 	aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
474 }
475 
ScChartListenerCollection(const ScChartListenerCollection & rColl)476 ScChartListenerCollection::ScChartListenerCollection(
477 		const ScChartListenerCollection& rColl ) :
478 	ScStrCollection( rColl ),
479 	pDoc( rColl.pDoc )
480 {
481 	aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
482 }
483 
~ScChartListenerCollection()484 ScChartListenerCollection::~ScChartListenerCollection()
485 {
486 	//	#96783# remove ChartListener objects before aTimer dtor is called, because
487 	//	ScChartListener::EndListeningTo may cause ScChartListenerCollection::StartTimer
488 	//	to be called if an empty ScNoteCell is deleted
489 
490 	if (GetCount())
491 		FreeAll();
492 }
493 
Clone() const494 ScDataObject*	ScChartListenerCollection::Clone() const
495 {
496 	return new ScChartListenerCollection( *this );
497 }
498 
StartAllListeners()499 void ScChartListenerCollection::StartAllListeners()
500 {
501 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
502 	{
503 		((ScChartListener*) pItems[ nIndex ])->StartListeningTo();
504 	}
505 }
506 
ChangeListening(const String & rName,const ScRangeListRef & rRangeListRef,sal_Bool bDirty)507 void ScChartListenerCollection::ChangeListening( const String& rName,
508 		const ScRangeListRef& rRangeListRef, sal_Bool bDirty )
509 {
510 	ScChartListener aCLSearcher( rName, pDoc, rRangeListRef );
511 	ScChartListener* pCL;
512 	sal_uInt16 nIndex;
513 	if ( Search( &aCLSearcher, nIndex ) )
514 	{
515 		pCL = (ScChartListener*) pItems[ nIndex ];
516 		pCL->EndListeningTo();
517 		pCL->SetRangeList( rRangeListRef );
518 	}
519 	else
520 	{
521 		pCL = new ScChartListener( aCLSearcher );
522 		Insert( pCL );
523 	}
524 	pCL->StartListeningTo();
525 	if ( bDirty )
526 		pCL->SetDirty( sal_True );
527 }
528 
FreeUnused()529 void ScChartListenerCollection::FreeUnused()
530 {
531 	// rueckwaerts wg. Pointer-Aufrueckerei im Array
532 	for ( sal_uInt16 nIndex = nCount; nIndex-- >0; )
533 	{
534 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
535 		//	Uno-Charts nicht rauskicken
536 		//	(werden per FreeUno von aussen geloescht)
537 		if ( !pCL->IsUno() )
538 		{
539 			if ( pCL->IsUsed() )
540 				pCL->SetUsed( sal_False );
541 			else
542 				Free( pCL );
543 		}
544 	}
545 }
546 
FreeUno(const uno::Reference<chart::XChartDataChangeEventListener> & rListener,const uno::Reference<chart::XChartData> & rSource)547 void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
548 										 const uno::Reference< chart::XChartData >& rSource )
549 {
550 	// rueckwaerts wg. Pointer-Aufrueckerei im Array
551 	for ( sal_uInt16 nIndex = nCount; nIndex-- >0; )
552 	{
553 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
554 		if ( pCL->IsUno() &&
555 			 pCL->GetUnoListener() == rListener &&
556 			 pCL->GetUnoSource() == rSource )
557 		{
558 			Free( pCL );
559 		}
560 		//!	sollte nur einmal vorkommen?
561 	}
562 }
563 
StartTimer()564 void ScChartListenerCollection::StartTimer()
565 {
566 	aTimer.SetTimeout( SC_CHARTTIMEOUT );
567 	aTimer.Start();
568 }
569 
IMPL_LINK(ScChartListenerCollection,TimerHdl,Timer *,EMPTYARG)570 IMPL_LINK( ScChartListenerCollection, TimerHdl, Timer*, EMPTYARG )
571 {
572 	if ( Application::AnyInput( INPUT_KEYBOARD ) )
573 	{
574 		aTimer.Start();
575 		return 0;
576 	}
577 	UpdateDirtyCharts();
578 	return 0;
579 }
580 
UpdateDirtyCharts()581 void ScChartListenerCollection::UpdateDirtyCharts()
582 {
583 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
584 	{
585 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
586 		if ( pCL->IsDirty() )
587 			pCL->Update();
588 		if ( aTimer.IsActive() && !pDoc->IsImportingXML())
589 			break;						// da kam einer dazwischen
590 	}
591 }
592 
593 
SetDirty()594 void ScChartListenerCollection::SetDirty()
595 {
596 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
597 	{
598 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
599 		pCL->SetDirty( sal_True );
600 	}
601 	StartTimer();
602 }
603 
604 
SetDiffDirty(const ScChartListenerCollection & rCmp,sal_Bool bSetChartRangeLists)605 void ScChartListenerCollection::SetDiffDirty(
606 			const ScChartListenerCollection& rCmp, sal_Bool bSetChartRangeLists )
607 {
608 	sal_Bool bDirty = sal_False;
609 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
610 	{
611 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
612 		sal_uInt16 nFound;
613 		sal_Bool bFound = rCmp.Search( pCL, nFound );
614 		if ( !bFound ||	(*pCL != *((const ScChartListener*) rCmp.pItems[ nFound ])) )
615 		{
616 			if ( bSetChartRangeLists )
617 			{
618 				if ( bFound )
619 				{
620 					const ScRangeListRef& rList1 = pCL->GetRangeList();
621 					const ScRangeListRef& rList2 =
622 						((const ScChartListener*) rCmp.pItems[ nFound ])->GetRangeList();
623 					sal_Bool b1 = rList1.Is();
624 					sal_Bool b2 = rList2.Is();
625 					if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
626 						pDoc->SetChartRangeList( pCL->GetString(), rList1 );
627 				}
628 				else
629 					pDoc->SetChartRangeList( pCL->GetString(), pCL->GetRangeList() );
630 			}
631 			bDirty = sal_True;
632 			pCL->SetDirty( sal_True );
633 		}
634 	}
635 	if ( bDirty )
636 		StartTimer();
637 }
638 
639 
SetRangeDirty(const ScRange & rRange)640 void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
641 {
642 	sal_Bool bDirty = sal_False;
643 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
644 	{
645 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
646 		const ScRangeListRef& rList = pCL->GetRangeList();
647 		if ( rList.Is() && rList->Intersects( rRange ) )
648 		{
649 			bDirty = sal_True;
650 			pCL->SetDirty( sal_True );
651 		}
652 	}
653 	if ( bDirty )
654 		StartTimer();
655 
656     // New hidden range listener implementation
657     for (list<RangeListenerItem>::iterator itr = maHiddenListeners.begin(), itrEnd = maHiddenListeners.end();
658           itr != itrEnd; ++itr)
659     {
660         if (itr->maRange.Intersects(rRange))
661             itr->mpListener->notify();
662     }
663 }
664 
665 
UpdateScheduledSeriesRanges()666 void ScChartListenerCollection::UpdateScheduledSeriesRanges()
667 {
668 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
669 	{
670 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
671 		pCL->UpdateScheduledSeriesRanges();
672 	}
673 }
674 
675 
UpdateChartsContainingTab(SCTAB nTab)676 void ScChartListenerCollection::UpdateChartsContainingTab( SCTAB nTab )
677 {
678 	ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
679 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
680 	{
681 		ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
682 		pCL->UpdateChartIntersecting( aRange );
683 	}
684 }
685 
686 
operator ==(const ScChartListenerCollection & r)687 sal_Bool ScChartListenerCollection::operator==( const ScChartListenerCollection& r )
688 {
689 	// hier nicht ScStrCollection::operator==() verwenden, der umstaendlich via
690 	// IsEqual und Compare laeuft, stattdessen ScChartListener::operator==()
691 	if ( pDoc != r.pDoc || nCount != r.nCount )
692 		return sal_False;
693 	for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
694 	{
695 		if ( *((ScChartListener*) pItems[ nIndex ]) !=
696 				*((ScChartListener*) r.pItems[ nIndex ]) )
697 			return sal_False;
698 	}
699 	return sal_True;
700 }
701 
StartListeningHiddenRange(const ScRange & rRange,ScChartHiddenRangeListener * pListener)702 void ScChartListenerCollection::StartListeningHiddenRange( const ScRange& rRange, ScChartHiddenRangeListener* pListener )
703 {
704     RangeListenerItem aItem(rRange, pListener);
705     maHiddenListeners.push_back(aItem);
706 }
707 
708 namespace {
709 
710 struct MatchListener : public ::std::unary_function<
711         ScChartListenerCollection::RangeListenerItem, bool>
712 {
MatchListener__anon3197e7b30211::MatchListener713     MatchListener(const ScChartHiddenRangeListener* pMatch) :
714         mpMatch(pMatch)
715     {
716     }
717 
operator ()__anon3197e7b30211::MatchListener718     bool operator() (const ScChartListenerCollection::RangeListenerItem& rItem) const
719     {
720         return mpMatch == rItem.mpListener;
721     }
722 
723 private:
724     const ScChartHiddenRangeListener* mpMatch;
725 };
726 
727 }
EndListeningHiddenRange(ScChartHiddenRangeListener * pListener)728 void ScChartListenerCollection::EndListeningHiddenRange( ScChartHiddenRangeListener* pListener )
729 {
730     maHiddenListeners.remove_if(MatchListener(pListener));
731 }
732 
733