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