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