1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svl/SfxBroadcaster.hxx>
22 #include <svl/hint.hxx>
23 #include <svl/lstner.hxx>
24 #include <tools/debug.hxx>
31 typedef std::vector
<SfxListener
*> SfxListenerArr_Impl
;
33 struct SfxBroadcaster::Impl
35 /** Contains the positions of removed listeners. */
36 std::vector
<size_t> m_RemovedPositions
;
37 SfxListenerArr_Impl m_Listeners
;
40 // broadcast immediately
42 void SfxBroadcaster::Broadcast( const SfxHint
&rHint
)
44 // notify all registered listeners exactly once
45 for (size_t i
= 0; i
< mpImpl
->m_Listeners
.size(); ++i
)
47 SfxListener
*const pListener
= mpImpl
->m_Listeners
[i
];
49 pListener
->Notify( *this, rHint
);
53 // unregister all listeners
55 SfxBroadcaster::~SfxBroadcaster() COVERITY_NOEXCEPT_FALSE
57 Broadcast( SfxHint(SfxHintId::Dying
) );
59 // remove all still registered listeners
60 for (size_t i
= 0; i
< mpImpl
->m_Listeners
.size(); ++i
)
62 SfxListener
*const pListener
= mpImpl
->m_Listeners
[i
];
64 pListener
->RemoveBroadcaster_Impl(*this);
69 // simple ctor of class SfxBroadcaster
71 SfxBroadcaster::SfxBroadcaster() : mpImpl(new Impl
)
76 // copy ctor of class SfxBroadcaster
79 SfxBroadcaster::SfxBroadcaster( const SfxBroadcaster
&rBC
) : mpImpl(new Impl
)
81 for (size_t i
= 0; i
< rBC
.mpImpl
->m_Listeners
.size(); ++i
)
83 SfxListener
*const pListener
= rBC
.mpImpl
->m_Listeners
[i
];
85 pListener
->StartListening( *this );
90 // add a new SfxListener to the list
92 void SfxBroadcaster::AddListener( SfxListener
& rListener
)
95 if (mpImpl
->m_RemovedPositions
.empty())
97 mpImpl
->m_Listeners
.push_back(&rListener
);
101 size_t targetPosition
= mpImpl
->m_RemovedPositions
.back();
102 mpImpl
->m_RemovedPositions
.pop_back();
103 assert(mpImpl
->m_Listeners
[targetPosition
] == nullptr);
104 mpImpl
->m_Listeners
[targetPosition
] = &rListener
;
109 // forward a notification to all registered listeners
111 void SfxBroadcaster::Forward(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
113 for (size_t i
= 0; i
< mpImpl
->m_Listeners
.size(); ++i
)
115 SfxListener
*const pListener
= mpImpl
->m_Listeners
[i
];
117 pListener
->Notify( rBC
, rHint
);
122 // remove one SfxListener from the list
124 void SfxBroadcaster::RemoveListener( SfxListener
& rListener
)
126 DBG_TESTSOLARMUTEX();
128 // First, check the slots either side of the last removed slot, makes a significant
129 // difference when the list is large.
130 int positionOfRemovedElement
= -1;
131 if (!mpImpl
->m_RemovedPositions
.empty())
133 auto i
= mpImpl
->m_RemovedPositions
.back();
134 if (i
< mpImpl
->m_Listeners
.size() - 2 && mpImpl
->m_Listeners
[i
+1] == &rListener
)
136 positionOfRemovedElement
= i
+ 1;
138 else if (i
> 0 && mpImpl
->m_Listeners
[i
-1] == &rListener
)
140 positionOfRemovedElement
= i
-1;
143 // then scan the whole list if we didn't find it
144 if (positionOfRemovedElement
== -1)
146 SfxListenerArr_Impl::iterator aIter
= std::find(
147 mpImpl
->m_Listeners
.begin(), mpImpl
->m_Listeners
.end(), &rListener
);
148 positionOfRemovedElement
= std::distance(mpImpl
->m_Listeners
.begin(), aIter
);
150 // DO NOT erase the listener, set the pointer to 0
151 // because the current continuation may contain this->Broadcast
152 mpImpl
->m_Listeners
[positionOfRemovedElement
] = nullptr;
153 mpImpl
->m_RemovedPositions
.push_back(positionOfRemovedElement
);
156 bool SfxBroadcaster::HasListeners() const
158 return (GetListenerCount() != 0);
161 size_t SfxBroadcaster::GetListenerCount() const
163 assert(mpImpl
->m_Listeners
.size() >= mpImpl
->m_RemovedPositions
.size());
164 return mpImpl
->m_Listeners
.size() - mpImpl
->m_RemovedPositions
.size();
167 size_t SfxBroadcaster::GetSizeOfVector() const
169 return mpImpl
->m_Listeners
.size();
172 SfxListener
* SfxBroadcaster::GetListener( size_t nNo
) const
174 return mpImpl
->m_Listeners
[nNo
];
178 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */