/src/libreoffice/svl/source/notify/SfxBroadcaster.cxx
Line | Count | Source |
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 <svl/SfxBroadcaster.hxx> |
21 | | |
22 | | #include <svl/hint.hxx> |
23 | | #include <svl/lstner.hxx> |
24 | | #include <tools/debug.hxx> |
25 | | |
26 | | #include <algorithm> |
27 | | #include <cassert> |
28 | | #include <vector> |
29 | | |
30 | | // Note: The loops in this file cannot be range-based |
31 | | // because vectors can change size during the loops. |
32 | | |
33 | | // broadcast immediately |
34 | | |
35 | | void SfxBroadcaster::Broadcast(const SfxHint& rHint) |
36 | 41.8M | { |
37 | | // notify all registered listeners exactly once |
38 | 41.8M | size_t nSize = m_Listeners.size(); |
39 | 143M | for (size_t i = 0; i < nSize; ++i) |
40 | 101M | { |
41 | 101M | SfxListener* const pListener = m_Listeners[i]; |
42 | 101M | if (pListener) |
43 | 53.3M | pListener->Notify(*this, rHint); |
44 | 101M | } |
45 | 41.8M | } |
46 | | |
47 | | // unregister all listeners |
48 | | |
49 | | SfxBroadcaster::~SfxBroadcaster() COVERITY_NOEXCEPT_FALSE |
50 | 26.3M | { |
51 | 26.3M | Broadcast(SfxHint(SfxHintId::Dying)); |
52 | | |
53 | | // remove all still registered listeners |
54 | 31.1M | for (size_t i = 0; i < m_Listeners.size(); ++i) |
55 | 4.78M | { |
56 | 4.78M | SfxListener* const pListener = m_Listeners[i]; |
57 | 4.78M | if (pListener) |
58 | 467k | pListener->RemoveBroadcaster_Impl(*this); |
59 | 4.78M | } |
60 | 26.3M | } |
61 | | |
62 | | // copy ctor of class SfxBroadcaster |
63 | | |
64 | | SfxBroadcaster::SfxBroadcaster(const SfxBroadcaster& rOther) |
65 | 0 | { |
66 | 0 | for (size_t i = 0; i < rOther.m_Listeners.size(); ++i) |
67 | 0 | { |
68 | 0 | SfxListener* const pListener = rOther.m_Listeners[i]; |
69 | 0 | if (pListener) |
70 | 0 | pListener->StartListening(*this); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | // add a new SfxListener to the list |
75 | | |
76 | | void SfxBroadcaster::AddListener(SfxListener& rListener) |
77 | 7.89M | { |
78 | 7.89M | DBG_TESTSOLARMUTEX(); |
79 | 7.89M | if (m_RemovedPositions.empty()) |
80 | 4.79M | { |
81 | 4.79M | m_Listeners.push_back(&rListener); |
82 | 4.79M | } |
83 | 3.10M | else |
84 | 3.10M | { |
85 | 3.10M | size_t targetPosition = m_RemovedPositions.back(); |
86 | 3.10M | m_RemovedPositions.pop_back(); |
87 | 3.10M | assert(m_Listeners[targetPosition] == nullptr); |
88 | 3.10M | m_Listeners[targetPosition] = &rListener; |
89 | 3.10M | } |
90 | 7.89M | } |
91 | | |
92 | | // forward a notification to all registered listeners |
93 | | |
94 | | void SfxBroadcaster::Forward(SfxBroadcaster& rBC, const SfxHint& rHint) |
95 | 36.1M | { |
96 | 66.5M | for (size_t i = 0; i < m_Listeners.size(); ++i) |
97 | 30.4M | { |
98 | 30.4M | SfxListener* const pListener = m_Listeners[i]; |
99 | 30.4M | if (pListener) |
100 | 27.1M | pListener->Notify(rBC, rHint); |
101 | 30.4M | } |
102 | 36.1M | } |
103 | | |
104 | | // remove one SfxListener from the list |
105 | | |
106 | | void SfxBroadcaster::RemoveListener(SfxListener& rListener) |
107 | 7.42M | { |
108 | 7.42M | DBG_TESTSOLARMUTEX(); |
109 | | |
110 | | // First, check the slots either side of the last removed slot, makes a significant |
111 | | // difference when the list is large. |
112 | 7.42M | int positionOfRemovedElement = -1; |
113 | 7.42M | if (!m_RemovedPositions.empty()) |
114 | 4.05M | { |
115 | 4.05M | auto i = m_RemovedPositions.back(); |
116 | 4.05M | if (i < m_Listeners.size() - 2 && m_Listeners[i + 1] == &rListener) |
117 | 726k | { |
118 | 726k | positionOfRemovedElement = i + 1; |
119 | 726k | } |
120 | 3.32M | else if (i > 0 && m_Listeners[i - 1] == &rListener) |
121 | 1.68M | { |
122 | 1.68M | positionOfRemovedElement = i - 1; |
123 | 1.68M | } |
124 | 4.05M | } |
125 | | // then scan the whole list if we didn't find it |
126 | 7.42M | if (positionOfRemovedElement == -1) |
127 | 5.01M | { |
128 | 5.01M | auto aIter = std::find(m_Listeners.begin(), m_Listeners.end(), &rListener); |
129 | 5.01M | positionOfRemovedElement = std::distance(m_Listeners.begin(), aIter); |
130 | 5.01M | } |
131 | | // DO NOT erase the listener, set the pointer to 0 |
132 | | // because the current continuation may contain this->Broadcast |
133 | 7.42M | m_Listeners[positionOfRemovedElement] = nullptr; |
134 | 7.42M | m_RemovedPositions.push_back(positionOfRemovedElement); |
135 | 7.42M | } |
136 | | |
137 | | void SfxBroadcaster::ForAllListeners(const std::function<bool(SfxListener*)>& f) const |
138 | 672k | { |
139 | 3.99M | for (size_t i = 0; i < m_Listeners.size(); ++i) |
140 | 3.34M | { |
141 | 3.34M | SfxListener* const pListener = m_Listeners[i]; |
142 | 3.34M | if (pListener) |
143 | 3.02M | if (f(pListener)) |
144 | 14.5k | break; |
145 | 3.34M | } |
146 | 672k | } |
147 | | |
148 | 883k | bool SfxBroadcaster::HasListeners() const { return GetListenerCount() != 0; } |
149 | | |
150 | | size_t SfxBroadcaster::GetListenerCount() const |
151 | 883k | { |
152 | 883k | return m_Listeners.size() - m_RemovedPositions.size(); |
153 | 883k | } |
154 | | |
155 | 0 | bool SfxBroadcaster::IsSfxStyleSheet() const { return false; } |
156 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |