Update ooo320-m1
[ooovba.git] / sc / source / core / tool / chartlis.cxx
blob00af942cd658224d6f8fa8666ad5240a44402aac
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: chartlis.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 #include <vcl/svapp.hxx>
38 #include "chartlis.hxx"
39 #include "brdcst.hxx"
40 #include "document.hxx"
41 #include "reftokenhelper.hxx"
43 using namespace com::sun::star;
44 using ::std::vector;
45 using ::std::list;
46 using ::std::hash_set;
47 using ::std::auto_ptr;
48 using ::std::unary_function;
49 using ::std::for_each;
51 //2do: DocOption TimeOut?
52 //#define SC_CHARTTIMEOUT 1000 // eine Sekunde keine Aenderung/KeyEvent
54 // Update chart listeners quickly, to get a similar behavior to loaded charts
55 // which register UNO listeners.
56 #define SC_CHARTTIMEOUT 10
59 // ====================================================================
61 class ScChartUnoData
63 uno::Reference< chart::XChartDataChangeEventListener > xListener;
64 uno::Reference< chart::XChartData > xSource;
66 public:
67 ScChartUnoData( const uno::Reference< chart::XChartDataChangeEventListener >& rL,
68 const uno::Reference< chart::XChartData >& rS ) :
69 xListener( rL ), xSource( rS ) {}
70 ~ScChartUnoData() {}
72 const uno::Reference< chart::XChartDataChangeEventListener >& GetListener() const { return xListener; }
73 const uno::Reference< chart::XChartData >& GetSource() const { return xSource; }
77 // === ScChartListener ================================================
79 ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
80 mrParent(rParent), mpDoc(pDoc)
84 ScChartListener::ExternalRefListener::~ExternalRefListener()
86 if (!mpDoc || mpDoc->IsInDtorClear())
87 // The document is being destroyed. Do nothing.
88 return;
90 // Make sure to remove all pointers to this object.
91 mpDoc->GetExternalRefManager()->removeLinkListener(this);
94 void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
96 switch (eType)
98 case ScExternalRefManager::LINK_MODIFIED:
100 if (maFileIds.count(nFileId))
101 // We are listening to this external document. Send an update
102 // requst to the chart.
103 mrParent.SetUpdateQueue();
105 break;
106 case ScExternalRefManager::LINK_BROKEN:
107 removeFileId(nFileId);
108 break;
112 void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
114 maFileIds.insert(nFileId);
117 void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
119 maFileIds.erase(nFileId);
122 hash_set<sal_uInt16>& ScChartListener::ExternalRefListener::getAllFileIds()
124 return maFileIds;
127 // ----------------------------------------------------------------------------
129 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
130 const ScRange& rRange ) :
131 StrData( rName ),
132 SvtListener(),
133 mpExtRefListener(NULL),
134 mpTokens(new vector<ScSharedTokenRef>),
135 pUnoData( NULL ),
136 pDoc( pDocP ),
137 bUsed( FALSE ),
138 bDirty( FALSE ),
139 bSeriesRangesScheduled( FALSE )
141 SetRangeList( rRange );
144 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
145 const ScRangeListRef& rRangeList ) :
146 StrData( rName ),
147 SvtListener(),
148 mpExtRefListener(NULL),
149 mpTokens(new vector<ScSharedTokenRef>),
150 pUnoData( NULL ),
151 pDoc( pDocP ),
152 bUsed( FALSE ),
153 bDirty( FALSE ),
154 bSeriesRangesScheduled( FALSE )
156 ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
159 ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP, vector<ScSharedTokenRef>* pTokens ) :
160 StrData( rName ),
161 SvtListener(),
162 mpExtRefListener(NULL),
163 mpTokens(pTokens),
164 pUnoData( NULL ),
165 pDoc( pDocP ),
166 bUsed( FALSE ),
167 bDirty( FALSE ),
168 bSeriesRangesScheduled( FALSE )
172 ScChartListener::ScChartListener( const ScChartListener& r ) :
173 StrData( r ),
174 SvtListener(),
175 mpExtRefListener(NULL),
176 mpTokens(new vector<ScSharedTokenRef>(*r.mpTokens)),
177 pUnoData( NULL ),
178 pDoc( r.pDoc ),
179 bUsed( FALSE ),
180 bDirty( r.bDirty ),
181 bSeriesRangesScheduled( r.bSeriesRangesScheduled )
183 if ( r.pUnoData )
184 pUnoData = new ScChartUnoData( *r.pUnoData );
186 if (r.mpExtRefListener.get())
188 // Re-register this new listener for the files that the old listener
189 // was listening to.
191 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
192 const hash_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
193 mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
194 hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
195 for (; itr != itrEnd; ++itr)
197 pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
198 mpExtRefListener->addFileId(*itr);
203 ScChartListener::~ScChartListener()
205 if ( HasBroadcaster() )
206 EndListeningTo();
207 delete pUnoData;
209 if (mpExtRefListener.get())
211 // Stop listening to all external files.
212 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
213 const hash_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
214 hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
215 for (; itr != itrEnd; ++itr)
216 pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
220 ScDataObject* ScChartListener::Clone() const
222 return new ScChartListener( *this );
225 void ScChartListener::SetUno(
226 const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
227 const uno::Reference< chart::XChartData >& rSource )
229 // DBG_ASSERT( rListener.is() && rSource.is(), "Nullpointer bei SetUno" );
230 delete pUnoData;
231 pUnoData = new ScChartUnoData( rListener, rSource );
234 uno::Reference< chart::XChartDataChangeEventListener > ScChartListener::GetUnoListener() const
236 if ( pUnoData )
237 return pUnoData->GetListener();
238 return uno::Reference< chart::XChartDataChangeEventListener >();
241 uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
243 if ( pUnoData )
244 return pUnoData->GetSource();
245 return uno::Reference< chart::XChartData >();
248 void ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
250 const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
251 if (p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)))
252 SetUpdateQueue();
255 void ScChartListener::Update()
257 if ( pDoc->IsInInterpreter() )
258 { // #73482# If interpreting do nothing and restart timer so we don't
259 // interfere with interpreter and don't produce an Err522 or similar.
260 // This may happen if we are rescheduled via Basic function.
261 pDoc->GetChartListenerCollection()->StartTimer();
262 return ;
264 if ( pUnoData )
266 bDirty = FALSE;
267 //! irgendwann mal erkennen, was sich innerhalb des Charts geaendert hat
268 chart::ChartDataChangeEvent aEvent( pUnoData->GetSource(),
269 chart::ChartDataChangeType_ALL,
270 0, 0, 0, 0 );
271 pUnoData->GetListener()->chartDataChanged( aEvent );
273 else if ( pDoc->GetAutoCalc() )
275 bDirty = FALSE;
276 pDoc->UpdateChart( GetString());
280 ScRangeListRef ScChartListener::GetRangeList() const
282 ScRangeListRef aRLRef(new ScRangeList);
283 ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens);
284 return aRLRef;
287 void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
289 vector<ScSharedTokenRef> aTokens;
290 ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
291 mpTokens->swap(aTokens);
294 void ScChartListener::SetRangeList( const ScRange& rRange )
296 ScSharedTokenRef pToken;
297 ScRefTokenHelper::getTokenFromRange(pToken, rRange);
298 mpTokens->push_back(pToken);
301 namespace {
303 class StartEndListening : public unary_function<ScSharedTokenRef, void>
305 public:
306 StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
307 mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
309 void operator() (const ScSharedTokenRef& pToken)
311 if (!ScRefTokenHelper::isRef(pToken))
312 return;
314 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
315 if (bExternal)
317 sal_uInt16 nFileId = pToken->GetIndex();
318 ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
319 ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
320 if (mbStart)
322 pRefMgr->addLinkListener(nFileId, pExtRefListener);
323 pExtRefListener->addFileId(nFileId);
325 else
327 pRefMgr->removeLinkListener(nFileId, pExtRefListener);
328 pExtRefListener->removeFileId(nFileId);
331 else
333 ScRange aRange;
334 ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal);
335 if (mbStart)
336 startListening(aRange);
337 else
338 endListening(aRange);
342 private:
343 void startListening(const ScRange& rRange)
345 if (rRange.aStart == rRange.aEnd)
346 mpDoc->StartListeningCell(rRange.aStart, &mrParent);
347 else
348 mpDoc->StartListeningArea(rRange, &mrParent);
351 void endListening(const ScRange& rRange)
353 if (rRange.aStart == rRange.aEnd)
354 mpDoc->EndListeningCell(rRange.aStart, &mrParent);
355 else
356 mpDoc->EndListeningArea(rRange, &mrParent);
359 private:
360 ScDocument* mpDoc;
361 ScChartListener& mrParent;
362 bool mbStart;
367 void ScChartListener::StartListeningTo()
369 if (!mpTokens.get() || mpTokens->empty())
370 // no references to listen to.
371 return;
373 for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, true));
376 void ScChartListener::EndListeningTo()
378 if (!mpTokens.get() || mpTokens->empty())
379 // no references to listen to.
380 return;
382 for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, false));
386 void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
387 BOOL bDirtyP )
389 EndListeningTo();
390 SetRangeList( rRangeListRef );
391 StartListeningTo();
392 if ( bDirtyP )
393 SetDirty( TRUE );
397 void ScChartListener::UpdateScheduledSeriesRanges()
399 if ( bSeriesRangesScheduled )
401 bSeriesRangesScheduled = FALSE;
402 UpdateSeriesRanges();
407 void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
409 ScSharedTokenRef pToken;
410 ScRefTokenHelper::getTokenFromRange(pToken, rRange);
412 if (ScRefTokenHelper::intersects(*mpTokens, pToken))
414 // force update (chart has to be loaded), don't use ScChartListener::Update
415 pDoc->UpdateChart( GetString());
420 void ScChartListener::UpdateSeriesRanges()
422 ScRangeListRef pRangeList(new ScRangeList);
423 ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens);
424 pDoc->SetChartRangeList(GetString(), pRangeList);
427 ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
429 if (!mpExtRefListener.get())
430 mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
432 return mpExtRefListener.get();
435 void ScChartListener::SetUpdateQueue()
437 bDirty = true;
438 pDoc->GetChartListenerCollection()->StartTimer();
441 BOOL ScChartListener::operator==( const ScChartListener& r )
443 bool b1 = (mpTokens.get() && !mpTokens->empty());
444 bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
446 if (pDoc != r.pDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
447 bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
448 GetString() != r.GetString() || b1 != b2)
449 return false;
451 if (!b1 && !b2)
452 // both token list instances are empty.
453 return true;
455 return *mpTokens == *r.mpTokens;
458 // ============================================================================
460 ScChartHiddenRangeListener::ScChartHiddenRangeListener()
464 ScChartHiddenRangeListener::~ScChartHiddenRangeListener()
466 // empty d'tor
469 // === ScChartListenerCollection ======================================
471 ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& rRange, ScChartHiddenRangeListener* p) :
472 maRange(rRange), mpListener(p)
476 ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
477 ScStrCollection( 4, 4, FALSE ),
478 pDoc( pDocP )
480 aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
483 ScChartListenerCollection::ScChartListenerCollection(
484 const ScChartListenerCollection& rColl ) :
485 ScStrCollection( rColl ),
486 pDoc( rColl.pDoc )
488 aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
491 ScChartListenerCollection::~ScChartListenerCollection()
493 // #96783# remove ChartListener objects before aTimer dtor is called, because
494 // ScChartListener::EndListeningTo may cause ScChartListenerCollection::StartTimer
495 // to be called if an empty ScNoteCell is deleted
497 if (GetCount())
498 FreeAll();
501 ScDataObject* ScChartListenerCollection::Clone() const
503 return new ScChartListenerCollection( *this );
506 void ScChartListenerCollection::StartAllListeners()
508 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
510 ((ScChartListener*) pItems[ nIndex ])->StartListeningTo();
514 void ScChartListenerCollection::ChangeListening( const String& rName,
515 const ScRangeListRef& rRangeListRef, BOOL bDirty )
517 ScChartListener aCLSearcher( rName, pDoc, rRangeListRef );
518 ScChartListener* pCL;
519 USHORT nIndex;
520 if ( Search( &aCLSearcher, nIndex ) )
522 pCL = (ScChartListener*) pItems[ nIndex ];
523 pCL->EndListeningTo();
524 pCL->SetRangeList( rRangeListRef );
526 else
528 pCL = new ScChartListener( aCLSearcher );
529 Insert( pCL );
531 pCL->StartListeningTo();
532 if ( bDirty )
533 pCL->SetDirty( TRUE );
536 void ScChartListenerCollection::FreeUnused()
538 // rueckwaerts wg. Pointer-Aufrueckerei im Array
539 for ( USHORT nIndex = nCount; nIndex-- >0; )
541 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
542 // Uno-Charts nicht rauskicken
543 // (werden per FreeUno von aussen geloescht)
544 if ( !pCL->IsUno() )
546 if ( pCL->IsUsed() )
547 pCL->SetUsed( FALSE );
548 else
549 Free( pCL );
554 void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
555 const uno::Reference< chart::XChartData >& rSource )
557 // rueckwaerts wg. Pointer-Aufrueckerei im Array
558 for ( USHORT nIndex = nCount; nIndex-- >0; )
560 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
561 if ( pCL->IsUno() &&
562 pCL->GetUnoListener() == rListener &&
563 pCL->GetUnoSource() == rSource )
565 Free( pCL );
567 //! sollte nur einmal vorkommen?
571 void ScChartListenerCollection::StartTimer()
573 aTimer.SetTimeout( SC_CHARTTIMEOUT );
574 aTimer.Start();
577 IMPL_LINK( ScChartListenerCollection, TimerHdl, Timer*, EMPTYARG )
579 if ( Application::AnyInput( INPUT_KEYBOARD ) )
581 aTimer.Start();
582 return 0;
584 UpdateDirtyCharts();
585 return 0;
588 void ScChartListenerCollection::UpdateDirtyCharts()
590 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
592 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
593 if ( pCL->IsDirty() )
594 pCL->Update();
595 if ( aTimer.IsActive() && !pDoc->IsImportingXML())
596 break; // da kam einer dazwischen
601 void ScChartListenerCollection::SetDirty()
603 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
605 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
606 pCL->SetDirty( TRUE );
608 StartTimer();
612 void ScChartListenerCollection::SetDiffDirty(
613 const ScChartListenerCollection& rCmp, BOOL bSetChartRangeLists )
615 BOOL bDirty = FALSE;
616 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
618 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
619 USHORT nFound;
620 BOOL bFound = rCmp.Search( pCL, nFound );
621 if ( !bFound || (*pCL != *((const ScChartListener*) rCmp.pItems[ nFound ])) )
623 if ( bSetChartRangeLists )
625 if ( bFound )
627 const ScRangeListRef& rList1 = pCL->GetRangeList();
628 const ScRangeListRef& rList2 =
629 ((const ScChartListener*) rCmp.pItems[ nFound ])->GetRangeList();
630 BOOL b1 = rList1.Is();
631 BOOL b2 = rList2.Is();
632 if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
633 pDoc->SetChartRangeList( pCL->GetString(), rList1 );
635 else
636 pDoc->SetChartRangeList( pCL->GetString(), pCL->GetRangeList() );
638 bDirty = TRUE;
639 pCL->SetDirty( TRUE );
642 if ( bDirty )
643 StartTimer();
647 void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
649 BOOL bDirty = FALSE;
650 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
652 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
653 const ScRangeListRef& rList = pCL->GetRangeList();
654 if ( rList.Is() && rList->Intersects( rRange ) )
656 bDirty = TRUE;
657 pCL->SetDirty( TRUE );
660 if ( bDirty )
661 StartTimer();
663 // New hidden range listener implementation
664 for (list<RangeListenerItem>::iterator itr = maHiddenListeners.begin(), itrEnd = maHiddenListeners.end();
665 itr != itrEnd; ++itr)
667 if (itr->maRange.Intersects(rRange))
668 itr->mpListener->notify();
673 void ScChartListenerCollection::UpdateScheduledSeriesRanges()
675 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
677 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
678 pCL->UpdateScheduledSeriesRanges();
683 void ScChartListenerCollection::UpdateChartsContainingTab( SCTAB nTab )
685 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
686 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
688 ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
689 pCL->UpdateChartIntersecting( aRange );
694 BOOL ScChartListenerCollection::operator==( const ScChartListenerCollection& r )
696 // hier nicht ScStrCollection::operator==() verwenden, der umstaendlich via
697 // IsEqual und Compare laeuft, stattdessen ScChartListener::operator==()
698 if ( pDoc != r.pDoc || nCount != r.nCount )
699 return FALSE;
700 for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
702 if ( *((ScChartListener*) pItems[ nIndex ]) !=
703 *((ScChartListener*) r.pItems[ nIndex ]) )
704 return FALSE;
706 return TRUE;
709 void ScChartListenerCollection::StartListeningHiddenRange( const ScRange& rRange, ScChartHiddenRangeListener* pListener )
711 RangeListenerItem aItem(rRange, pListener);
712 maHiddenListeners.push_back(aItem);
715 namespace {
717 struct MatchListener : public ::std::unary_function<
718 ScChartListenerCollection::RangeListenerItem, bool>
720 MatchListener(const ScChartHiddenRangeListener* pMatch) :
721 mpMatch(pMatch)
725 bool operator() (const ScChartListenerCollection::RangeListenerItem& rItem) const
727 return mpMatch == rItem.mpListener;
730 private:
731 const ScChartHiddenRangeListener* mpMatch;
735 void ScChartListenerCollection::EndListeningHiddenRange( ScChartHiddenRangeListener* pListener )
737 maHiddenListeners.remove_if(MatchListener(pListener));