Line data Source code
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 <vcl/svapp.hxx>
21 :
22 : #include "chartlis.hxx"
23 : #include "brdcst.hxx"
24 : #include "document.hxx"
25 : #include "reftokenhelper.hxx"
26 : #include "stlalgorithm.hxx"
27 :
28 : using namespace com::sun::star;
29 : using ::std::vector;
30 : using ::std::list;
31 : using ::std::unary_function;
32 : using ::std::for_each;
33 :
34 : // Update chart listeners quickly, to get a similar behavior to loaded charts
35 : // which register UNO listeners.
36 : #define SC_CHARTTIMEOUT 10
37 :
38 0 : class ScChartUnoData
39 : {
40 : uno::Reference< chart::XChartDataChangeEventListener > xListener;
41 : uno::Reference< chart::XChartData > xSource;
42 :
43 : public:
44 0 : ScChartUnoData( const uno::Reference< chart::XChartDataChangeEventListener >& rL,
45 : const uno::Reference< chart::XChartData >& rS ) :
46 0 : xListener( rL ), xSource( rS ) {}
47 0 : ~ScChartUnoData() {}
48 :
49 0 : const uno::Reference< chart::XChartDataChangeEventListener >& GetListener() const { return xListener; }
50 0 : const uno::Reference< chart::XChartData >& GetSource() const { return xSource; }
51 : };
52 :
53 : // ScChartListener
54 0 : ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
55 0 : mrParent(rParent), mpDoc(pDoc)
56 : {
57 0 : }
58 :
59 0 : ScChartListener::ExternalRefListener::~ExternalRefListener()
60 : {
61 0 : if (!mpDoc || mpDoc->IsInDtorClear())
62 : // The document is being destroyed. Do nothing.
63 0 : return;
64 :
65 : // Make sure to remove all pointers to this object.
66 0 : mpDoc->GetExternalRefManager()->removeLinkListener(this);
67 0 : }
68 :
69 0 : void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
70 : {
71 0 : switch (eType)
72 : {
73 : case ScExternalRefManager::LINK_MODIFIED:
74 : {
75 0 : if (maFileIds.count(nFileId))
76 : // We are listening to this external document. Send an update
77 : // requst to the chart.
78 0 : mrParent.SetUpdateQueue();
79 : }
80 0 : break;
81 : case ScExternalRefManager::LINK_BROKEN:
82 0 : removeFileId(nFileId);
83 0 : break;
84 : }
85 0 : }
86 :
87 0 : void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
88 : {
89 0 : maFileIds.insert(nFileId);
90 0 : }
91 :
92 0 : void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
93 : {
94 0 : maFileIds.erase(nFileId);
95 0 : }
96 :
97 0 : boost::unordered_set<sal_uInt16>& ScChartListener::ExternalRefListener::getAllFileIds()
98 : {
99 0 : return maFileIds;
100 : }
101 :
102 0 : ScChartListener::ScChartListener( const OUString& rName, ScDocument* pDocP,
103 : const ScRangeListRef& rRangeList ) :
104 : SvtListener(),
105 : mpExtRefListener(NULL),
106 0 : mpTokens(new vector<ScTokenRef>),
107 : maName(rName),
108 : pUnoData( NULL ),
109 : mpDoc( pDocP ),
110 : bUsed( false ),
111 : bDirty( false ),
112 0 : bSeriesRangesScheduled( false )
113 : {
114 0 : ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
115 0 : }
116 :
117 0 : ScChartListener::ScChartListener( const OUString& rName, ScDocument* pDocP, vector<ScTokenRef>* pTokens ) :
118 : SvtListener(),
119 : mpExtRefListener(NULL),
120 : mpTokens(pTokens),
121 : maName(rName),
122 : pUnoData( NULL ),
123 : mpDoc( pDocP ),
124 : bUsed( false ),
125 : bDirty( false ),
126 0 : bSeriesRangesScheduled( false )
127 : {
128 0 : }
129 :
130 0 : ScChartListener::ScChartListener( const ScChartListener& r ) :
131 : SvtListener(),
132 : mpExtRefListener(NULL),
133 0 : mpTokens(new vector<ScTokenRef>(*r.mpTokens)),
134 : maName(r.maName),
135 : pUnoData( NULL ),
136 : mpDoc( r.mpDoc ),
137 : bUsed( false ),
138 : bDirty( r.bDirty ),
139 0 : bSeriesRangesScheduled( r.bSeriesRangesScheduled )
140 : {
141 0 : if ( r.pUnoData )
142 0 : pUnoData = new ScChartUnoData( *r.pUnoData );
143 :
144 0 : if (r.mpExtRefListener.get())
145 : {
146 : // Re-register this new listener for the files that the old listener
147 : // was listening to.
148 :
149 0 : ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
150 0 : const boost::unordered_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
151 0 : mpExtRefListener.reset(new ExternalRefListener(*this, mpDoc));
152 0 : boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
153 0 : for (; itr != itrEnd; ++itr)
154 : {
155 0 : pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
156 0 : mpExtRefListener->addFileId(*itr);
157 : }
158 : }
159 0 : }
160 :
161 0 : ScChartListener::~ScChartListener()
162 : {
163 0 : if ( HasBroadcaster() )
164 0 : EndListeningTo();
165 0 : delete pUnoData;
166 :
167 0 : if (mpExtRefListener.get())
168 : {
169 : // Stop listening to all external files.
170 0 : ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
171 0 : const boost::unordered_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
172 0 : boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
173 0 : for (; itr != itrEnd; ++itr)
174 0 : pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
175 : }
176 0 : }
177 :
178 0 : const OUString& ScChartListener::GetName() const
179 : {
180 0 : return maName;
181 : }
182 :
183 0 : void ScChartListener::SetUno(
184 : const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
185 : const uno::Reference< chart::XChartData >& rSource )
186 : {
187 0 : delete pUnoData;
188 0 : pUnoData = new ScChartUnoData( rListener, rSource );
189 0 : }
190 :
191 0 : uno::Reference< chart::XChartDataChangeEventListener > ScChartListener::GetUnoListener() const
192 : {
193 0 : if ( pUnoData )
194 0 : return pUnoData->GetListener();
195 0 : return uno::Reference< chart::XChartDataChangeEventListener >();
196 : }
197 :
198 0 : uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
199 : {
200 0 : if ( pUnoData )
201 0 : return pUnoData->GetSource();
202 0 : return uno::Reference< chart::XChartData >();
203 : }
204 :
205 0 : void ScChartListener::Notify( const SfxHint& rHint )
206 : {
207 0 : const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
208 0 : if (p && (p->GetId() & SC_HINT_DATACHANGED))
209 0 : SetUpdateQueue();
210 0 : }
211 :
212 0 : void ScChartListener::Update()
213 : {
214 0 : if ( mpDoc->IsInInterpreter() )
215 : { // If interpreting do nothing and restart timer so we don't
216 : // interfere with interpreter and don't produce an Err522 or similar.
217 : // This may happen if we are rescheduled via Basic function.
218 0 : mpDoc->GetChartListenerCollection()->StartTimer();
219 0 : return ;
220 : }
221 0 : if ( pUnoData )
222 : {
223 0 : bDirty = false;
224 : // recognize some day what has changed inside the Chart
225 0 : chart::ChartDataChangeEvent aEvent( pUnoData->GetSource(),
226 : chart::ChartDataChangeType_ALL,
227 0 : 0, 0, 0, 0 );
228 0 : pUnoData->GetListener()->chartDataChanged( aEvent );
229 : }
230 0 : else if ( mpDoc->GetAutoCalc() )
231 : {
232 0 : bDirty = false;
233 0 : mpDoc->UpdateChart(GetName());
234 : }
235 : }
236 :
237 0 : ScRangeListRef ScChartListener::GetRangeList() const
238 : {
239 0 : ScRangeListRef aRLRef(new ScRangeList);
240 0 : ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens, ScAddress());
241 0 : return aRLRef;
242 : }
243 :
244 0 : void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
245 : {
246 0 : vector<ScTokenRef> aTokens;
247 0 : ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
248 0 : mpTokens->swap(aTokens);
249 0 : }
250 :
251 : namespace {
252 :
253 : class StartEndListening : public unary_function<ScTokenRef, void>
254 : {
255 : public:
256 0 : StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
257 0 : mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
258 :
259 0 : void operator() (const ScTokenRef& pToken)
260 : {
261 0 : if (!ScRefTokenHelper::isRef(pToken))
262 0 : return;
263 :
264 0 : bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
265 0 : if (bExternal)
266 : {
267 0 : sal_uInt16 nFileId = pToken->GetIndex();
268 0 : ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
269 0 : ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
270 0 : if (mbStart)
271 : {
272 0 : pRefMgr->addLinkListener(nFileId, pExtRefListener);
273 0 : pExtRefListener->addFileId(nFileId);
274 : }
275 : else
276 : {
277 0 : pRefMgr->removeLinkListener(nFileId, pExtRefListener);
278 0 : pExtRefListener->removeFileId(nFileId);
279 : }
280 : }
281 : else
282 : {
283 0 : ScRange aRange;
284 0 : ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
285 0 : if (mbStart)
286 0 : startListening(aRange);
287 : else
288 0 : endListening(aRange);
289 : }
290 : }
291 : private:
292 0 : void startListening(const ScRange& rRange)
293 : {
294 0 : if (rRange.aStart == rRange.aEnd)
295 0 : mpDoc->StartListeningCell(rRange.aStart, &mrParent);
296 : else
297 0 : mpDoc->StartListeningArea(rRange, &mrParent);
298 0 : }
299 :
300 0 : void endListening(const ScRange& rRange)
301 : {
302 0 : if (rRange.aStart == rRange.aEnd)
303 0 : mpDoc->EndListeningCell(rRange.aStart, &mrParent);
304 : else
305 0 : mpDoc->EndListeningArea(rRange, &mrParent);
306 0 : }
307 : private:
308 : ScDocument* mpDoc;
309 : ScChartListener& mrParent;
310 : bool mbStart;
311 : };
312 :
313 : }
314 :
315 0 : void ScChartListener::StartListeningTo()
316 : {
317 0 : if (!mpTokens.get() || mpTokens->empty())
318 : // no references to listen to.
319 0 : return;
320 :
321 0 : for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(mpDoc, *this, true));
322 : }
323 :
324 0 : void ScChartListener::EndListeningTo()
325 : {
326 0 : if (!mpTokens.get() || mpTokens->empty())
327 : // no references to listen to.
328 0 : return;
329 :
330 0 : for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(mpDoc, *this, false));
331 : }
332 :
333 0 : void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
334 : bool bDirtyP )
335 : {
336 0 : EndListeningTo();
337 0 : SetRangeList( rRangeListRef );
338 0 : StartListeningTo();
339 0 : if ( bDirtyP )
340 0 : SetDirty( true );
341 0 : }
342 :
343 0 : void ScChartListener::UpdateScheduledSeriesRanges()
344 : {
345 0 : if ( bSeriesRangesScheduled )
346 : {
347 0 : bSeriesRangesScheduled = false;
348 0 : UpdateSeriesRanges();
349 : }
350 0 : }
351 :
352 0 : void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
353 : {
354 0 : ScTokenRef pToken;
355 0 : ScRefTokenHelper::getTokenFromRange(pToken, rRange);
356 :
357 0 : if (ScRefTokenHelper::intersects(*mpTokens, pToken, ScAddress()))
358 : {
359 : // force update (chart has to be loaded), don't use ScChartListener::Update
360 0 : mpDoc->UpdateChart(GetName());
361 0 : }
362 0 : }
363 :
364 0 : void ScChartListener::UpdateSeriesRanges()
365 : {
366 0 : ScRangeListRef pRangeList(new ScRangeList);
367 0 : ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens, ScAddress());
368 0 : mpDoc->SetChartRangeList(GetName(), pRangeList);
369 0 : }
370 :
371 0 : ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
372 : {
373 0 : if (!mpExtRefListener.get())
374 0 : mpExtRefListener.reset(new ExternalRefListener(*this, mpDoc));
375 :
376 0 : return mpExtRefListener.get();
377 : }
378 :
379 0 : void ScChartListener::SetUpdateQueue()
380 : {
381 0 : bDirty = true;
382 0 : mpDoc->GetChartListenerCollection()->StartTimer();
383 0 : }
384 :
385 0 : bool ScChartListener::operator==( const ScChartListener& r ) const
386 : {
387 0 : bool b1 = (mpTokens.get() && !mpTokens->empty());
388 0 : bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
389 :
390 0 : if (mpDoc != r.mpDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
391 0 : bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
392 0 : GetName() != r.GetName() || b1 != b2)
393 0 : return false;
394 :
395 0 : if (!b1 && !b2)
396 : // both token list instances are empty.
397 0 : return true;
398 :
399 0 : return *mpTokens == *r.mpTokens;
400 : }
401 :
402 0 : bool ScChartListener::operator!=( const ScChartListener& r ) const
403 : {
404 0 : return !operator==(r);
405 : }
406 :
407 0 : ScChartHiddenRangeListener::ScChartHiddenRangeListener()
408 : {
409 0 : }
410 :
411 0 : ScChartHiddenRangeListener::~ScChartHiddenRangeListener()
412 : {
413 : // empty d'tor
414 0 : }
415 :
416 : // ScChartListenerCollection
417 0 : ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& rRange, ScChartHiddenRangeListener* p) :
418 0 : maRange(rRange), mpListener(p)
419 : {
420 0 : }
421 :
422 0 : ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
423 0 : pDoc( pDocP )
424 : {
425 0 : aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
426 0 : }
427 :
428 0 : ScChartListenerCollection::ScChartListenerCollection(
429 : const ScChartListenerCollection& rColl ) :
430 0 : pDoc( rColl.pDoc )
431 : {
432 0 : aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
433 0 : }
434 :
435 0 : ScChartListenerCollection::~ScChartListenerCollection()
436 : {
437 : // remove ChartListener objects before aTimer dtor is called, because
438 : // ScChartListener::EndListeningTo may cause ScChartListenerCollection::StartTimer
439 : // to be called if an empty ScNoteCell is deleted
440 :
441 0 : maListeners.clear();
442 0 : }
443 :
444 0 : void ScChartListenerCollection::StartAllListeners()
445 : {
446 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
447 0 : for (; it != itEnd; ++it)
448 0 : it->second->StartListeningTo();
449 0 : }
450 :
451 0 : void ScChartListenerCollection::insert(ScChartListener* pListener)
452 : {
453 0 : OUString aName = pListener->GetName();
454 0 : maListeners.insert(aName, pListener);
455 0 : }
456 :
457 0 : void ScChartListenerCollection::removeByName(const OUString& rName)
458 : {
459 0 : maListeners.erase(rName);
460 0 : }
461 :
462 0 : ScChartListener* ScChartListenerCollection::findByName(const OUString& rName)
463 : {
464 0 : ListenersType::iterator it = maListeners.find(rName);
465 0 : return it == maListeners.end() ? NULL : it->second;
466 : }
467 :
468 0 : const ScChartListener* ScChartListenerCollection::findByName(const OUString& rName) const
469 : {
470 0 : ListenersType::const_iterator it = maListeners.find(rName);
471 0 : return it == maListeners.end() ? NULL : it->second;
472 : }
473 :
474 0 : bool ScChartListenerCollection::hasListeners() const
475 : {
476 0 : return !maListeners.empty();
477 : }
478 :
479 0 : const ScChartListenerCollection::ListenersType& ScChartListenerCollection::getListeners() const
480 : {
481 0 : return maListeners;
482 : }
483 :
484 0 : ScChartListenerCollection::ListenersType& ScChartListenerCollection::getListeners()
485 : {
486 0 : return maListeners;
487 : }
488 :
489 0 : ScChartListenerCollection::StringSetType& ScChartListenerCollection::getNonOleObjectNames()
490 : {
491 0 : return maNonOleObjectNames;
492 : }
493 :
494 0 : OUString ScChartListenerCollection::getUniqueName(const OUString& rPrefix) const
495 : {
496 0 : for (sal_Int32 nNum = 1; nNum < 10000; ++nNum) // arbitrary limit to prevent infinite loop.
497 : {
498 0 : OUStringBuffer aBuf(rPrefix);
499 0 : aBuf.append(nNum);
500 0 : OUString aTestName = aBuf.makeStringAndClear();
501 0 : if (maListeners.find(aTestName) == maListeners.end())
502 0 : return aTestName;
503 0 : }
504 0 : return OUString();
505 : }
506 :
507 0 : void ScChartListenerCollection::ChangeListening( const OUString& rName,
508 : const ScRangeListRef& rRangeListRef, bool bDirty )
509 : {
510 0 : ScChartListener* pCL = findByName(rName);
511 0 : if (pCL)
512 : {
513 0 : pCL->EndListeningTo();
514 0 : pCL->SetRangeList( rRangeListRef );
515 : }
516 : else
517 : {
518 0 : pCL = new ScChartListener(rName, pDoc, rRangeListRef);
519 0 : insert(pCL);
520 : }
521 0 : pCL->StartListeningTo();
522 0 : if ( bDirty )
523 0 : pCL->SetDirty( true );
524 0 : }
525 :
526 : namespace {
527 :
528 : class InsertChartListener : public std::unary_function<ScChartListener*, void>
529 : {
530 : ScChartListenerCollection::ListenersType& mrListeners;
531 : public:
532 0 : InsertChartListener(ScChartListenerCollection::ListenersType& rListeners) :
533 0 : mrListeners(rListeners) {}
534 :
535 0 : void operator() (ScChartListener* p)
536 : {
537 0 : OUString aName = p->GetName();
538 0 : mrListeners.insert(aName, p);
539 0 : }
540 : };
541 :
542 : }
543 :
544 0 : void ScChartListenerCollection::FreeUnused()
545 : {
546 0 : std::vector<ScChartListener*> aUsed, aUnused;
547 :
548 : // First, filter each listener into 'used' and 'unused' categories.
549 : {
550 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
551 0 : for (; it != itEnd; ++it)
552 : {
553 0 : ScChartListener* p = it->second;
554 0 : if (p->IsUno())
555 : {
556 : // We don't delete UNO charts; they are to be deleted separately via FreeUno().
557 0 : aUsed.push_back(p);
558 0 : continue;
559 : }
560 :
561 0 : if (p->IsUsed())
562 : {
563 0 : p->SetUsed(false);
564 0 : aUsed.push_back(p);
565 : }
566 : else
567 0 : aUnused.push_back(p);
568 : }
569 : }
570 :
571 : // Release all pointers currently managed by the ptr_map container.
572 0 : maListeners.release().release();
573 :
574 : // Re-insert the listeners we need to keep.
575 0 : std::for_each(aUsed.begin(), aUsed.end(), InsertChartListener(maListeners));
576 :
577 : // Now, delete the ones no longer needed.
578 0 : std::for_each(aUnused.begin(), aUnused.end(), ScDeleteObjectByPtr<ScChartListener>());
579 0 : }
580 :
581 0 : void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
582 : const uno::Reference< chart::XChartData >& rSource )
583 : {
584 0 : std::vector<ScChartListener*> aUsed, aUnused;
585 :
586 : // First, filter each listener into 'used' and 'unused' categories.
587 : {
588 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
589 0 : for (; it != itEnd; ++it)
590 : {
591 0 : ScChartListener* p = it->second;
592 0 : if (p->IsUno() && p->GetUnoListener() == rListener && p->GetUnoSource() == rSource)
593 0 : aUnused.push_back(p);
594 : else
595 0 : aUsed.push_back(p);
596 : }
597 : }
598 :
599 : // Release all pointers currently managed by the ptr_map container.
600 0 : maListeners.release().release();
601 :
602 : // Re-insert the listeners we need to keep.
603 0 : std::for_each(aUsed.begin(), aUsed.end(), InsertChartListener(maListeners));
604 :
605 : // Now, delete the ones no longer needed.
606 0 : std::for_each(aUnused.begin(), aUnused.end(), ScDeleteObjectByPtr<ScChartListener>());
607 0 : }
608 :
609 0 : void ScChartListenerCollection::StartTimer()
610 : {
611 0 : aTimer.SetTimeout( SC_CHARTTIMEOUT );
612 0 : aTimer.Start();
613 0 : }
614 :
615 0 : IMPL_LINK_NOARG(ScChartListenerCollection, TimerHdl)
616 : {
617 0 : if ( Application::AnyInput( VCL_INPUT_KEYBOARD ) )
618 : {
619 0 : aTimer.Start();
620 0 : return 0;
621 : }
622 0 : UpdateDirtyCharts();
623 0 : return 0;
624 : }
625 :
626 0 : void ScChartListenerCollection::UpdateDirtyCharts()
627 : {
628 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
629 0 : for (; it != itEnd; ++it)
630 : {
631 0 : ScChartListener* p = it->second;
632 0 : if (p->IsDirty())
633 0 : p->Update();
634 :
635 0 : if (aTimer.IsActive() && !pDoc->IsImportingXML())
636 0 : break; // one interfered
637 : }
638 0 : }
639 :
640 0 : void ScChartListenerCollection::SetDirty()
641 : {
642 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
643 0 : for (; it != itEnd; ++it)
644 0 : it->second->SetDirty(true);
645 :
646 0 : StartTimer();
647 0 : }
648 :
649 0 : void ScChartListenerCollection::SetDiffDirty(
650 : const ScChartListenerCollection& rCmp, bool bSetChartRangeLists )
651 : {
652 0 : bool bDirty = false;
653 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
654 0 : for (; it != itEnd; ++it)
655 : {
656 0 : ScChartListener* pCL = it->second;
657 : OSL_ASSERT(pCL);
658 0 : const ScChartListener* pCLCmp = rCmp.findByName(pCL->GetName());
659 0 : if (!pCLCmp || *pCL != *pCLCmp)
660 : {
661 0 : if ( bSetChartRangeLists )
662 : {
663 0 : if (pCLCmp)
664 : {
665 0 : const ScRangeListRef& rList1 = pCL->GetRangeList();
666 0 : const ScRangeListRef& rList2 = pCLCmp->GetRangeList();
667 0 : bool b1 = rList1.Is();
668 0 : bool b2 = rList2.Is();
669 0 : if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
670 0 : pDoc->SetChartRangeList( pCL->GetName(), rList1 );
671 : }
672 : else
673 0 : pDoc->SetChartRangeList( pCL->GetName(), pCL->GetRangeList() );
674 : }
675 0 : bDirty = true;
676 0 : pCL->SetDirty( true );
677 : }
678 : }
679 0 : if ( bDirty )
680 0 : StartTimer();
681 0 : }
682 :
683 0 : void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
684 : {
685 0 : bool bDirty = false;
686 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
687 0 : for (; it != itEnd; ++it)
688 : {
689 0 : ScChartListener* pCL = it->second;
690 0 : const ScRangeListRef& rList = pCL->GetRangeList();
691 0 : if ( rList.Is() && rList->Intersects( rRange ) )
692 : {
693 0 : bDirty = true;
694 0 : pCL->SetDirty( true );
695 : }
696 0 : }
697 0 : if ( bDirty )
698 0 : StartTimer();
699 :
700 : // New hidden range listener implementation
701 0 : for (list<RangeListenerItem>::iterator itr = maHiddenListeners.begin(), itrEnd = maHiddenListeners.end();
702 : itr != itrEnd; ++itr)
703 : {
704 0 : if (itr->maRange.Intersects(rRange))
705 0 : itr->mpListener->notify();
706 : }
707 0 : }
708 :
709 0 : void ScChartListenerCollection::UpdateScheduledSeriesRanges()
710 : {
711 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
712 0 : for (; it != itEnd; ++it)
713 0 : it->second->UpdateScheduledSeriesRanges();
714 0 : }
715 :
716 0 : void ScChartListenerCollection::UpdateChartsContainingTab( SCTAB nTab )
717 : {
718 0 : ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
719 0 : ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
720 0 : for (; it != itEnd; ++it)
721 0 : it->second->UpdateChartIntersecting(aRange);
722 0 : }
723 :
724 0 : bool ScChartListenerCollection::operator==( const ScChartListenerCollection& r ) const
725 : {
726 : // Do not use ScStrCollection::operator==() here that uses IsEqual und Compare.
727 : // Use ScChartListener::operator==() instead.
728 0 : if (pDoc != r.pDoc || maListeners.size() != r.maListeners.size())
729 0 : return false;
730 :
731 0 : ListenersType::const_iterator it = maListeners.begin(), itEnd = maListeners.end();
732 0 : ListenersType::const_iterator it2 = r.maListeners.begin();
733 0 : for (; it != itEnd; ++it, ++it2)
734 : {
735 0 : if (*it != *it2)
736 0 : return false;
737 : }
738 0 : return true;
739 : }
740 :
741 0 : bool ScChartListenerCollection::operator!=( const ScChartListenerCollection& r ) const
742 : {
743 0 : return !operator==(r);
744 : }
745 :
746 0 : void ScChartListenerCollection::StartListeningHiddenRange( const ScRange& rRange, ScChartHiddenRangeListener* pListener )
747 : {
748 0 : RangeListenerItem aItem(rRange, pListener);
749 0 : maHiddenListeners.push_back(aItem);
750 0 : }
751 :
752 : namespace {
753 :
754 : struct MatchListener : public ::std::unary_function<
755 : ScChartListenerCollection::RangeListenerItem, bool>
756 : {
757 0 : MatchListener(const ScChartHiddenRangeListener* pMatch) :
758 0 : mpMatch(pMatch)
759 : {
760 0 : }
761 :
762 0 : bool operator() (const ScChartListenerCollection::RangeListenerItem& rItem) const
763 : {
764 0 : return mpMatch == rItem.mpListener;
765 : }
766 :
767 : private:
768 : const ScChartHiddenRangeListener* mpMatch;
769 : };
770 :
771 : }
772 0 : void ScChartListenerCollection::EndListeningHiddenRange( ScChartHiddenRangeListener* pListener )
773 : {
774 0 : maHiddenListeners.remove_if(MatchListener(pListener));
775 0 : }
776 :
777 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|