Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */