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