/src/libreoffice/svl/source/notify/lstner.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/lstner.hxx> |
21 | | |
22 | | #include <svl/SfxBroadcaster.hxx> |
23 | | #include <sal/backtrace.hxx> |
24 | | #include <sal/log.hxx> |
25 | | |
26 | | #include <algorithm> |
27 | | #include <cassert> |
28 | | #include <vector> |
29 | | #include <memory> |
30 | | |
31 | | // copy ctor of class SfxListener |
32 | | |
33 | | SfxListener::SfxListener( const SfxListener &rOther ) |
34 | 314k | : maBCs( rOther.maBCs ) |
35 | 314k | { |
36 | 629k | for ( size_t n = 0; n < maBCs.size(); ++n ) |
37 | 314k | { |
38 | 314k | maBCs[n]->AddListener(*this); |
39 | | #ifdef DBG_UTIL |
40 | | maCallStacks.emplace( maBCs[n], sal::backtrace_get(10) ); |
41 | | #endif |
42 | 314k | } |
43 | 314k | } |
44 | | |
45 | | // unregisters the SfxListener from its SfxBroadcasters |
46 | | |
47 | | SfxListener::~SfxListener() COVERITY_NOEXCEPT_FALSE |
48 | 12.5M | { |
49 | | // unregister at all remaining broadcasters |
50 | 12.5M | EndListeningAll(); |
51 | 12.5M | } |
52 | | |
53 | | |
54 | | // unregisters a specific SfxBroadcaster |
55 | | |
56 | | void SfxListener::RemoveBroadcaster_Impl( SfxBroadcaster& rBroadcaster ) |
57 | 1.21M | { |
58 | 1.21M | std::erase(maBCs, &rBroadcaster); |
59 | | #ifdef DBG_UTIL |
60 | | maCallStacks.erase( &rBroadcaster ); |
61 | | #endif |
62 | 1.21M | } |
63 | | |
64 | | |
65 | | |
66 | | /** |
67 | | Registers a specific SfxBroadcaster. |
68 | | |
69 | | Some code uses duplicates as a kind of ref-counting thing i.e. they add and remove listeners |
70 | | on different code paths, and they only really stop listening when the last EndListening() is called. |
71 | | */ |
72 | | void SfxListener::StartListening(SfxBroadcaster& rBroadcaster, DuplicateHandling eDuplicateHanding) |
73 | 12.9M | { |
74 | 12.9M | bool bListeningAlready = eDuplicateHanding != DuplicateHandling::Allow && IsListening( rBroadcaster ); |
75 | | |
76 | | #ifdef DBG_UTIL |
77 | | if (bListeningAlready && eDuplicateHanding == DuplicateHandling::Unexpected) |
78 | | { |
79 | | auto f = maCallStacks.find( &rBroadcaster ); |
80 | | SAL_WARN("svl", "previous StartListening call came from: " << sal::backtrace_to_string(f->second.get())); |
81 | | } |
82 | | #endif |
83 | 12.9M | assert(!(bListeningAlready && eDuplicateHanding == DuplicateHandling::Unexpected) && "duplicate listener, try building with DBG_UTIL to find the other insert site."); |
84 | | |
85 | 12.9M | if (!bListeningAlready || eDuplicateHanding != DuplicateHandling::Prevent) |
86 | 12.9M | { |
87 | 12.9M | rBroadcaster.AddListener(*this); |
88 | 12.9M | maBCs.push_back( &rBroadcaster ); |
89 | | #ifdef DBG_UTIL |
90 | | maCallStacks.emplace( &rBroadcaster, sal::backtrace_get(10) ); |
91 | | #endif |
92 | 12.9M | assert(IsListening(rBroadcaster) && "StartListening failed"); |
93 | 12.9M | } |
94 | 12.9M | } |
95 | | |
96 | | // unregisters a specific SfxBroadcaster |
97 | | |
98 | | void SfxListener::EndListening( SfxBroadcaster& rBroadcaster, bool bRemoveAllDuplicates ) |
99 | 10.8M | { |
100 | 10.8M | for (auto it = std::find(maBCs.begin(), maBCs.end(), &rBroadcaster); it != maBCs.end(); |
101 | 10.8M | it = std::find(it, maBCs.end(), &rBroadcaster)) |
102 | 10.4M | { |
103 | 10.4M | rBroadcaster.RemoveListener(*this); |
104 | 10.4M | it = maBCs.erase(it); |
105 | 10.4M | if (!bRemoveAllDuplicates) |
106 | 10.4M | break; |
107 | 10.4M | } |
108 | | #ifdef DBG_UTIL |
109 | | maCallStacks.erase(&rBroadcaster); |
110 | | #endif |
111 | 10.8M | } |
112 | | |
113 | | |
114 | | // unregisters all Broadcasters |
115 | | |
116 | | void SfxListener::EndListeningAll() |
117 | 12.9M | { |
118 | 12.9M | for (SfxBroadcaster *pBC : std::vector(std::move(maBCs))) |
119 | 1.62M | pBC->RemoveListener(*this); |
120 | | #ifdef DBG_UTIL |
121 | | maCallStacks.clear(); |
122 | | #endif |
123 | 12.9M | } |
124 | | |
125 | | |
126 | | bool SfxListener::IsListening( SfxBroadcaster& rBroadcaster ) const |
127 | 9.51M | { |
128 | 9.51M | return maBCs.end() != std::find( maBCs.begin(), maBCs.end(), &rBroadcaster ); |
129 | 9.51M | } |
130 | | |
131 | | sal_uInt16 SfxListener::GetBroadcasterCount() const |
132 | 2.48M | { |
133 | 2.48M | return maBCs.size(); |
134 | 2.48M | } |
135 | | |
136 | | SfxBroadcaster* SfxListener::GetBroadcasterJOE( sal_uInt16 nNo ) const |
137 | 193k | { |
138 | 193k | return maBCs[nNo]; |
139 | 193k | } |
140 | | |
141 | | |
142 | | // base implementation of notification handler |
143 | | |
144 | | void SfxListener::Notify( SfxBroadcaster& rBroadcaster, const SfxHint& ) |
145 | 0 | { |
146 | 0 | (void) rBroadcaster; |
147 | | assert(IsListening(rBroadcaster)); |
148 | 0 | } |
149 | | |
150 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |