Line data Source code
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 <tools/debug.hxx>
21 : #include <tools/rc.h>
22 :
23 : #include <vcl/window.hxx>
24 : #include <vcl/svapp.hxx>
25 : #include <accel.h>
26 : #include <vcl/accel.hxx>
27 : #include <map>
28 : #include <vector>
29 :
30 : typedef ::std::map< sal_uLong, ImplAccelEntry* > ImplAccelMap;
31 : typedef ::std::vector< ImplAccelEntry* > ImplAccelList;
32 :
33 : #define ACCELENTRY_NOTFOUND ((sal_uInt16)0xFFFF)
34 :
35 6191 : class ImplAccelData
36 : {
37 : public:
38 : ImplAccelMap maKeyMap; // for keycodes, generated with a code
39 : ImplAccelList maIdList; // Id-List
40 : };
41 :
42 6144 : sal_uInt16 ImplAccelEntryGetIndex( ImplAccelList* pList, sal_uInt16 nId,
43 : sal_uInt16* pIndex = NULL )
44 : {
45 : size_t nLow;
46 : size_t nHigh;
47 : size_t nMid;
48 6144 : size_t nCount = pList->size();
49 : sal_uInt16 nCompareId;
50 :
51 : // check if first key is larger then the key to compare
52 6144 : if ( !nCount || (nId < (*pList)[ 0 ]->mnId) )
53 : {
54 3072 : if ( pIndex )
55 3072 : *pIndex = 0;
56 3072 : return ACCELENTRY_NOTFOUND;
57 : }
58 :
59 : // Binairy search
60 3072 : nLow = 0;
61 3072 : nHigh = nCount-1;
62 3072 : do
63 : {
64 3072 : nMid = (nLow + nHigh) / 2;
65 3072 : nCompareId = (*pList)[ nMid ]->mnId;
66 3072 : if ( nId < nCompareId )
67 0 : nHigh = nMid-1;
68 : else
69 : {
70 3072 : if ( nId > nCompareId )
71 3072 : nLow = nMid + 1;
72 : else
73 0 : return (sal_uInt16)nMid;
74 : }
75 : }
76 : while ( nLow <= nHigh );
77 :
78 3072 : if ( pIndex )
79 : {
80 3072 : if ( nId > nCompareId )
81 3072 : *pIndex = (sal_uInt16)(nMid+1);
82 : else
83 0 : *pIndex = (sal_uInt16)nMid;
84 : }
85 :
86 3072 : return ACCELENTRY_NOTFOUND;
87 : }
88 :
89 6144 : static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry )
90 : {
91 : sal_uInt16 nInsIndex;
92 6144 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
93 :
94 6144 : if ( nIndex != ACCELENTRY_NOTFOUND )
95 : {
96 0 : do
97 : {
98 0 : nIndex++;
99 0 : ImplAccelEntry* pTempEntry = NULL;
100 0 : if ( nIndex < pList->size() )
101 0 : pTempEntry = (*pList)[ nIndex ];
102 0 : if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
103 : break;
104 : }
105 0 : while ( nIndex < pList->size() );
106 :
107 0 : if ( nIndex < pList->size() ) {
108 0 : ImplAccelList::iterator it = pList->begin();
109 0 : ::std::advance( it, nIndex );
110 0 : pList->insert( it, pEntry );
111 : } else {
112 0 : pList->push_back( pEntry );
113 : }
114 : }
115 : else {
116 6144 : if ( nInsIndex < pList->size() ) {
117 0 : ImplAccelList::iterator it = pList->begin();
118 0 : ::std::advance( it, nInsIndex );
119 0 : pList->insert( it, pEntry );
120 : } else {
121 6144 : pList->push_back( pEntry );
122 : }
123 : }
124 6144 : }
125 :
126 0 : static sal_uInt16 ImplAccelEntryGetFirstPos( ImplAccelList* pList, sal_uInt16 nId )
127 : {
128 0 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, nId );
129 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
130 : {
131 0 : while ( nIndex )
132 : {
133 0 : nIndex--;
134 0 : if ( (*pList)[ nIndex ]->mnId != nId )
135 0 : break;
136 : }
137 :
138 0 : if ( (*pList)[ nIndex ]->mnId != nId )
139 0 : nIndex++;
140 : }
141 :
142 0 : return nIndex;
143 : }
144 :
145 3100 : void Accelerator::ImplInit()
146 : {
147 3100 : mnCurId = 0;
148 3100 : mnCurRepeat = 0;
149 3100 : mbIsCancel = false;
150 3100 : mpDel = NULL;
151 3100 : }
152 :
153 0 : ImplAccelEntry* Accelerator::ImplGetAccelData( const vcl::KeyCode& rKeyCode ) const
154 : {
155 0 : ImplAccelMap::iterator it = mpData->maKeyMap.find( rKeyCode.GetFullCode() );
156 0 : if( it != mpData->maKeyMap.end() )
157 0 : return it->second;
158 : else
159 0 : return NULL;
160 : }
161 :
162 0 : void Accelerator::ImplCopyData( ImplAccelData& rAccelData )
163 : {
164 : // copy table
165 0 : for ( size_t i = 0, n = rAccelData.maIdList.size(); i < n; ++i )
166 : {
167 0 : ImplAccelEntry* pEntry = new ImplAccelEntry( *rAccelData.maIdList[ i ] );
168 :
169 : // sequence accelerator, then copy also
170 0 : if ( pEntry->mpAccel )
171 : {
172 0 : pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
173 0 : pEntry->mpAutoAccel = pEntry->mpAccel;
174 : }
175 : else
176 0 : pEntry->mpAutoAccel = NULL;
177 :
178 0 : mpData->maKeyMap.insert( std::make_pair( pEntry->maKeyCode.GetFullCode(), pEntry ) );
179 0 : mpData->maIdList.push_back( pEntry );
180 : }
181 0 : }
182 :
183 3091 : void Accelerator::ImplDeleteData()
184 : {
185 : // delete accelerator-entries using the id-table
186 9221 : for ( size_t i = 0, n = mpData->maIdList.size(); i < n; ++i ) {
187 6130 : ImplAccelEntry* pEntry = mpData->maIdList[ i ];
188 6130 : if ( pEntry->mpAutoAccel ) {
189 0 : delete pEntry->mpAutoAccel;
190 : }
191 6130 : delete pEntry;
192 : }
193 3091 : mpData->maIdList.clear();
194 3091 : }
195 :
196 6144 : void Accelerator::ImplInsertAccel( sal_uInt16 nItemId, const vcl::KeyCode& rKeyCode,
197 : bool bEnable, Accelerator* pAutoAccel )
198 : {
199 : DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" );
200 :
201 6144 : if ( rKeyCode.IsFunction() )
202 : {
203 : sal_uInt16 nCode1;
204 : sal_uInt16 nCode2;
205 : sal_uInt16 nCode3;
206 : sal_uInt16 nCode4;
207 0 : ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
208 0 : if ( nCode1 )
209 0 : ImplInsertAccel( nItemId, vcl::KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
210 0 : if ( nCode2 )
211 : {
212 0 : if ( pAutoAccel )
213 0 : pAutoAccel = new Accelerator( *pAutoAccel );
214 0 : ImplInsertAccel( nItemId, vcl::KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
215 0 : if ( nCode3 )
216 : {
217 0 : if ( pAutoAccel )
218 0 : pAutoAccel = new Accelerator( *pAutoAccel );
219 0 : ImplInsertAccel( nItemId, vcl::KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
220 : }
221 : }
222 6144 : return;
223 : }
224 :
225 : // fetch and fill new entries
226 6144 : ImplAccelEntry* pEntry = new ImplAccelEntry;
227 6144 : pEntry->mnId = nItemId;
228 6144 : pEntry->maKeyCode = rKeyCode;
229 6144 : pEntry->mpAccel = pAutoAccel;
230 6144 : pEntry->mpAutoAccel = pAutoAccel;
231 6144 : pEntry->mbEnabled = bEnable;
232 :
233 : // now into the tables
234 6144 : sal_uLong nCode = rKeyCode.GetFullCode();
235 6144 : if ( !nCode )
236 : {
237 : OSL_FAIL( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
238 0 : delete pEntry;
239 : }
240 6144 : else if ( !mpData->maKeyMap.insert( std::make_pair( nCode, pEntry ) ).second )
241 : {
242 : SAL_WARN( "vcl.layout", "Accelerator::InsertItem(): KeyCode (Key: " << nCode << ") already exists" );
243 0 : delete pEntry;
244 : }
245 : else
246 6144 : ImplAccelEntryInsert( &(mpData->maIdList), pEntry );
247 : }
248 :
249 3100 : Accelerator::Accelerator()
250 : {
251 :
252 3100 : ImplInit();
253 3100 : mpData = new ImplAccelData;
254 3100 : }
255 :
256 0 : Accelerator::Accelerator( const Accelerator& rAccel ) :
257 : Resource(),
258 : maHelpStr( rAccel.maHelpStr ),
259 0 : maCurKeyCode( rAccel.maCurKeyCode )
260 : {
261 :
262 0 : ImplInit();
263 0 : mpData = new ImplAccelData;
264 0 : ImplCopyData(*rAccel.mpData);
265 0 : }
266 :
267 0 : Accelerator::Accelerator( const ResId& rResId )
268 : {
269 :
270 0 : ImplInit();
271 0 : mpData = new ImplAccelData;
272 0 : rResId.SetRT( RSC_ACCEL );
273 0 : ImplLoadRes( rResId );
274 0 : }
275 :
276 0 : void Accelerator::ImplLoadRes( const ResId& rResId )
277 : {
278 0 : GetRes( rResId );
279 :
280 0 : maHelpStr = ReadStringRes();
281 0 : sal_uLong nObjFollows = ReadLongRes();
282 :
283 0 : for( sal_uLong i = 0; i < nObjFollows; i++ )
284 : {
285 0 : InsertItem( ResId( static_cast<RSHEADER_TYPE *>(GetClassRes()), *rResId.GetResMgr() ) );
286 0 : IncrementRes( GetObjSizeRes( static_cast<RSHEADER_TYPE *>(GetClassRes()) ) );
287 : }
288 0 : }
289 :
290 6182 : Accelerator::~Accelerator()
291 : {
292 :
293 : // inform AccelManager about deleting the Accelerator
294 3091 : if ( mpDel )
295 0 : *mpDel = true;
296 :
297 3091 : ImplDeleteData();
298 3091 : delete mpData;
299 3091 : }
300 :
301 0 : void Accelerator::Activate()
302 : {
303 0 : maActivateHdl.Call( this );
304 0 : }
305 :
306 0 : void Accelerator::Deactivate()
307 : {
308 0 : maDeactivateHdl.Call( this );
309 0 : }
310 :
311 0 : void Accelerator::Select()
312 : {
313 0 : maSelectHdl.Call( this );
314 0 : }
315 :
316 6144 : void Accelerator::InsertItem( sal_uInt16 nItemId, const vcl::KeyCode& rKeyCode )
317 : {
318 6144 : ImplInsertAccel( nItemId, rKeyCode, true, NULL );
319 6144 : }
320 :
321 0 : void Accelerator::InsertItem( const ResId& rResId )
322 : {
323 :
324 : sal_uLong nObjMask;
325 : sal_uInt16 nAccelKeyId;
326 : sal_uInt16 bDisable;
327 0 : vcl::KeyCode aKeyCode;
328 0 : Accelerator* pAutoAccel = NULL;
329 :
330 0 : GetRes( rResId.SetRT( RSC_ACCELITEM ) );
331 0 : nObjMask = ReadLongRes();
332 0 : nAccelKeyId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
333 0 : bDisable = ReadShortRes();
334 :
335 0 : if ( nObjMask & ACCELITEM_KEY )
336 : {
337 : // new context was created
338 0 : RSHEADER_TYPE * pKeyCodeRes = static_cast<RSHEADER_TYPE *>(GetClassRes());
339 0 : ResId aResId( pKeyCodeRes, *rResId.GetResMgr());
340 0 : aKeyCode = vcl::KeyCode( aResId );
341 0 : IncrementRes( GetObjSizeRes( static_cast<RSHEADER_TYPE *>(GetClassRes()) ) );
342 : }
343 :
344 0 : if ( nObjMask & ACCELITEM_ACCEL )
345 : {
346 0 : pAutoAccel = new Accelerator( ResId( static_cast<RSHEADER_TYPE *>(GetClassRes()), *rResId.GetResMgr() ) );
347 0 : IncrementRes( GetObjSizeRes( static_cast<RSHEADER_TYPE *>(GetClassRes()) ) );
348 : }
349 :
350 0 : ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel );
351 0 : }
352 :
353 0 : sal_uInt16 Accelerator::GetItemCount() const
354 : {
355 :
356 0 : return (sal_uInt16)mpData->maIdList.size();
357 : }
358 :
359 0 : vcl::KeyCode Accelerator::GetKeyCode( sal_uInt16 nItemId ) const
360 : {
361 :
362 0 : sal_uInt16 nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
363 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
364 0 : return mpData->maIdList[ nIndex ]->maKeyCode;
365 : else
366 0 : return vcl::KeyCode();
367 : }
368 :
369 0 : sal_uInt16 Accelerator::GetItemId( sal_uInt16 nPos ) const
370 : {
371 :
372 0 : ImplAccelEntry* pEntry = ( nPos < mpData->maIdList.size() ) ? mpData->maIdList[ nPos ] : NULL;
373 0 : if ( pEntry )
374 0 : return pEntry->mnId;
375 : else
376 0 : return 0;
377 : }
378 :
379 0 : Accelerator* Accelerator::GetAccel( sal_uInt16 nItemId ) const
380 : {
381 :
382 0 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
383 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
384 0 : return mpData->maIdList[ nIndex ]->mpAccel;
385 : else
386 0 : return NULL;
387 : }
388 :
389 0 : Accelerator& Accelerator::operator=( const Accelerator& rAccel )
390 : {
391 :
392 : // assign new data
393 0 : maHelpStr = rAccel.maHelpStr;
394 0 : maCurKeyCode = vcl::KeyCode();
395 0 : mnCurId = 0;
396 0 : mnCurRepeat = 0;
397 0 : mbIsCancel = false;
398 :
399 : // delete and copy tables
400 0 : ImplDeleteData();
401 0 : mpData->maKeyMap.clear();
402 0 : ImplCopyData(*rAccel.mpData);
403 :
404 0 : return *this;
405 : }
406 :
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|