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