Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/window/accel.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 <sal/log.hxx>
21
#include <osl/diagnose.h>
22
#include <accel.hxx>
23
24
0
#define ACCELENTRY_NOTFOUND     (sal_uInt16(0xFFFF))
25
26
static sal_uInt16 ImplAccelEntryGetIndex( const ImplAccelList* pList, sal_uInt16 nId,
27
                               sal_uInt16* pIndex = nullptr )
28
0
{
29
0
    size_t  nLow;
30
0
    size_t  nHigh;
31
0
    size_t  nMid;
32
0
    size_t  nCount = pList->size();
33
0
    sal_uInt16  nCompareId;
34
35
    // check if first key is larger then the key to compare
36
0
    if ( !nCount || (nId < (*pList)[ 0 ]->mnId) )
37
0
    {
38
0
        if ( pIndex )
39
0
            *pIndex = 0;
40
0
        return ACCELENTRY_NOTFOUND;
41
0
    }
42
43
    // Binary search
44
0
    nLow  = 0;
45
0
    nHigh = nCount-1;
46
0
    do
47
0
    {
48
0
        nMid = (nLow + nHigh) / 2;
49
0
        nCompareId = (*pList)[ nMid ]->mnId;
50
0
        if ( nId < nCompareId )
51
0
            nHigh = nMid-1;
52
0
        else
53
0
        {
54
0
            if ( nId > nCompareId )
55
0
                nLow = nMid + 1;
56
0
            else
57
0
                return static_cast<sal_uInt16>(nMid);
58
0
        }
59
0
    }
60
0
    while ( nLow <= nHigh );
61
62
0
    if ( pIndex )
63
0
    {
64
0
        if ( nId > nCompareId )
65
0
            *pIndex = static_cast<sal_uInt16>(nMid+1);
66
0
        else
67
0
            *pIndex = static_cast<sal_uInt16>(nMid);
68
0
    }
69
70
0
    return ACCELENTRY_NOTFOUND;
71
0
}
72
73
static void ImplAccelEntryInsert( ImplAccelList* pList, std::unique_ptr<ImplAccelEntry> pEntry )
74
0
{
75
0
    sal_uInt16  nInsIndex(0);
76
0
    std::vector<ImplAccelEntry *>::size_type nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
77
78
0
    if ( nIndex != ACCELENTRY_NOTFOUND )
79
0
    {
80
0
        do
81
0
        {
82
0
            nIndex++;
83
0
            ImplAccelEntry* pTempEntry = nullptr;
84
0
            if ( nIndex < pList->size() )
85
0
                pTempEntry = (*pList)[ nIndex ].get();
86
0
            if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
87
0
                break;
88
0
        }
89
0
        while ( nIndex < pList->size() );
90
91
0
        if ( nIndex < pList->size() ) {
92
0
            pList->insert( pList->begin() + nIndex, std::move(pEntry) );
93
0
        } else {
94
0
            pList->push_back( std::move(pEntry) );
95
0
        }
96
0
    }
97
0
    else {
98
0
        if ( nInsIndex < pList->size() ) {
99
0
            pList->insert( pList->begin() + nInsIndex, std::move(pEntry) );
100
0
        } else {
101
0
            pList->push_back( std::move(pEntry) );
102
0
        }
103
0
    }
104
0
}
105
106
void Accelerator::ImplInit()
107
0
{
108
0
    mnCurId             = 0;
109
0
    mpDel               = nullptr;
110
0
}
111
112
ImplAccelEntry* Accelerator::ImplGetAccelData( const vcl::KeyCode& rKeyCode ) const
113
0
{
114
0
    auto it = maKeyMap.find( rKeyCode.GetFullCode() );
115
0
    if( it != maKeyMap.end() )
116
0
        return it->second;
117
0
    else
118
0
        return nullptr;
119
0
}
120
121
void Accelerator::ImplCopyData( const Accelerator& rAccelData )
122
0
{
123
    // copy table
124
0
    for (const std::unique_ptr<ImplAccelEntry>& i : rAccelData.maIdList)
125
0
    {
126
0
        std::unique_ptr<ImplAccelEntry> pEntry(new ImplAccelEntry( *i ));
127
128
        // sequence accelerator, then copy also
129
0
        if ( pEntry->mpAccel )
130
0
        {
131
0
            pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
132
0
            pEntry->mpAutoAccel = pEntry->mpAccel;
133
0
        }
134
0
        else
135
0
            pEntry->mpAutoAccel = nullptr;
136
137
0
        maKeyMap.insert( std::make_pair( pEntry->maKeyCode.GetFullCode(), pEntry.get() ) );
138
0
        maIdList.push_back( std::move(pEntry) );
139
0
    }
140
0
}
141
142
void Accelerator::ImplDeleteData()
143
0
{
144
    // delete accelerator-entries using the id-table
145
0
    for (const std::unique_ptr<ImplAccelEntry>& pEntry : maIdList) {
146
0
        delete pEntry->mpAutoAccel;
147
0
    }
148
0
    maIdList.clear();
149
0
}
150
151
void Accelerator::ImplInsertAccel( sal_uInt16 nItemId, const vcl::KeyCode& rKeyCode,
152
                                   bool bEnable, Accelerator* pAutoAccel )
153
0
{
154
0
    SAL_WARN_IF( !nItemId, "vcl", "Accelerator::InsertItem(): ItemId == 0" );
155
156
0
    if ( rKeyCode.IsFunction() )
157
0
    {
158
0
        sal_uInt16 nCode1;
159
0
        sal_uInt16 nCode2;
160
0
        sal_uInt16 nCode3;
161
0
        sal_uInt16 nCode4;
162
0
        ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
163
0
        if ( nCode1 )
164
0
            ImplInsertAccel( nItemId, vcl::KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
165
0
        if ( nCode2 )
166
0
        {
167
0
            if ( pAutoAccel )
168
0
                pAutoAccel = new Accelerator( *pAutoAccel );
169
0
            ImplInsertAccel( nItemId, vcl::KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
170
0
            if ( nCode3 )
171
0
            {
172
0
                if ( pAutoAccel )
173
0
                    pAutoAccel = new Accelerator( *pAutoAccel );
174
0
                ImplInsertAccel( nItemId, vcl::KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
175
0
            }
176
0
        }
177
0
        return;
178
0
    }
179
180
    // fetch and fill new entries
181
0
    std::unique_ptr<ImplAccelEntry> pEntry(new ImplAccelEntry);
182
0
    pEntry->mnId            = nItemId;
183
0
    pEntry->maKeyCode       = rKeyCode;
184
0
    pEntry->mpAccel         = pAutoAccel;
185
0
    pEntry->mpAutoAccel     = pAutoAccel;
186
0
    pEntry->mbEnabled       = bEnable;
187
188
    // now into the tables
189
0
    sal_uLong nCode = rKeyCode.GetFullCode();
190
0
    if ( !nCode )
191
0
    {
192
0
        OSL_FAIL( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
193
0
    }
194
0
    else if ( !maKeyMap.insert( std::make_pair( nCode, pEntry.get() ) ).second )
195
0
    {
196
0
        SAL_WARN( "vcl", "Accelerator::InsertItem(): KeyCode (Key: " << nCode << ") already exists" );
197
0
    }
198
0
    else
199
0
        ImplAccelEntryInsert( &maIdList, std::move(pEntry) );
200
0
}
201
202
Accelerator::Accelerator()
203
0
{
204
0
    ImplInit();
205
0
}
206
207
Accelerator::Accelerator(const Accelerator& rAccel)
208
0
{
209
0
    ImplInit();
210
0
    ImplCopyData(rAccel);
211
0
}
212
213
Accelerator::~Accelerator()
214
0
{
215
216
    // inform AccelManager about deleting the Accelerator
217
0
    if ( mpDel )
218
0
        *mpDel = true;
219
220
0
    ImplDeleteData();
221
0
}
222
223
void Accelerator::Activate()
224
0
{
225
0
    maActivateHdl.Call( *this );
226
0
}
227
228
void Accelerator::Select()
229
0
{
230
0
    maSelectHdl.Call( *this );
231
0
}
232
233
void Accelerator::InsertItem( sal_uInt16 nItemId, const vcl::KeyCode& rKeyCode )
234
0
{
235
0
    ImplInsertAccel( nItemId, rKeyCode, true, nullptr );
236
0
}
237
238
sal_uInt16 Accelerator::GetItemCount() const
239
0
{
240
0
    return static_cast<sal_uInt16>(maIdList.size());
241
0
}
242
243
sal_uInt16 Accelerator::GetItemId( sal_uInt16 nPos ) const
244
0
{
245
246
0
    ImplAccelEntry* pEntry = ( nPos < maIdList.size() ) ? maIdList[ nPos ].get() : nullptr;
247
0
    if ( pEntry )
248
0
        return pEntry->mnId;
249
0
    else
250
0
        return 0;
251
0
}
252
253
Accelerator* Accelerator::GetAccel( sal_uInt16 nItemId ) const
254
0
{
255
256
0
    sal_uInt16 nIndex = ImplAccelEntryGetIndex( &maIdList, nItemId );
257
0
    if ( nIndex != ACCELENTRY_NOTFOUND )
258
0
        return maIdList[ nIndex ]->mpAccel;
259
0
    else
260
0
        return nullptr;
261
0
}
262
263
Accelerator& Accelerator::operator=( const Accelerator& rAccel )
264
0
{
265
0
    if(this == &rAccel)
266
0
        return *this;
267
268
    // assign new data
269
0
    mnCurId         = 0;
270
271
    // delete and copy tables
272
0
    ImplDeleteData();
273
0
    maKeyMap.clear();
274
0
    ImplCopyData(rAccel);
275
276
0
    return *this;
277
0
}
278
279
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */