bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / window / accel.cxx
blob653dac9c942907f443eaf08a6521f3a3a6dafbdf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <tools/debug.hxx>
22 #include <tools/rc.h>
24 #include <vcl/svapp.hxx>
25 #include <accel.h>
26 #include <vcl/accel.hxx>
27 #include <map>
28 #include <vector>
30 // =======================================================================
32 typedef ::std::map< sal_uLong, ImplAccelEntry* > ImplAccelMap;
33 typedef ::std::vector< ImplAccelEntry* > ImplAccelList;
35 #define ACCELENTRY_NOTFOUND ((sal_uInt16)0xFFFF)
37 // =======================================================================
39 class ImplAccelData
41 public:
42 ImplAccelMap maKeyMap; // for keycodes, generated with a code
43 ImplAccelList maIdList; // Id-List
46 // =======================================================================
48 DBG_NAME( Accelerator )
50 // =======================================================================
52 sal_uInt16 ImplAccelEntryGetIndex( ImplAccelList* pList, sal_uInt16 nId,
53 sal_uInt16* pIndex = NULL )
55 size_t nLow;
56 size_t nHigh;
57 size_t nMid;
58 size_t nCount = pList->size();
59 sal_uInt16 nCompareId;
61 // check if first key is larger then the key to compare
62 if ( !nCount || (nId < (*pList)[ 0 ]->mnId) )
64 if ( pIndex )
65 *pIndex = 0;
66 return ACCELENTRY_NOTFOUND;
69 // Binairy search
70 nLow = 0;
71 nHigh = nCount-1;
74 nMid = (nLow + nHigh) / 2;
75 nCompareId = (*pList)[ nMid ]->mnId;
76 if ( nId < nCompareId )
77 nHigh = nMid-1;
78 else
80 if ( nId > nCompareId )
81 nLow = nMid + 1;
82 else
83 return (sal_uInt16)nMid;
86 while ( nLow <= nHigh );
88 if ( pIndex )
90 if ( nId > nCompareId )
91 *pIndex = (sal_uInt16)(nMid+1);
92 else
93 *pIndex = (sal_uInt16)nMid;
96 return ACCELENTRY_NOTFOUND;
99 // -----------------------------------------------------------------------
101 static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry )
103 sal_uInt16 nInsIndex;
104 sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
106 if ( nIndex != ACCELENTRY_NOTFOUND )
110 nIndex++;
111 ImplAccelEntry* pTempEntry = NULL;
112 if ( nIndex < pList->size() )
113 pTempEntry = (*pList)[ nIndex ];
114 if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
115 break;
117 while ( nIndex < pList->size() );
119 if ( nIndex < pList->size() ) {
120 ImplAccelList::iterator it = pList->begin();
121 ::std::advance( it, nIndex );
122 pList->insert( it, pEntry );
123 } else {
124 pList->push_back( pEntry );
127 else {
128 if ( nInsIndex < pList->size() ) {
129 ImplAccelList::iterator it = pList->begin();
130 ::std::advance( it, nInsIndex );
131 pList->insert( it, pEntry );
132 } else {
133 pList->push_back( pEntry );
138 // -----------------------------------------------------------------------
140 static sal_uInt16 ImplAccelEntryGetFirstPos( ImplAccelList* pList, sal_uInt16 nId )
142 sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, nId );
143 if ( nIndex != ACCELENTRY_NOTFOUND )
145 while ( nIndex )
147 nIndex--;
148 if ( (*pList)[ nIndex ]->mnId != nId )
149 break;
152 if ( (*pList)[ nIndex ]->mnId != nId )
153 nIndex++;
156 return nIndex;
159 // =======================================================================
161 void Accelerator::ImplInit()
163 mnCurId = 0;
164 mnCurRepeat = 0;
165 mbIsCancel = sal_False;
166 mpDel = NULL;
169 // -----------------------------------------------------------------------
171 ImplAccelEntry* Accelerator::ImplGetAccelData( const KeyCode& rKeyCode ) const
173 ImplAccelMap::iterator it = mpData->maKeyMap.find( rKeyCode.GetFullCode() );
174 if( it != mpData->maKeyMap.end() )
175 return it->second;
176 else
177 return NULL;
180 // -----------------------------------------------------------------------
182 void Accelerator::ImplCopyData( ImplAccelData& rAccelData )
184 // copy table
185 for ( size_t i = 0, n = rAccelData.maIdList.size(); i < n; ++i )
187 ImplAccelEntry* pEntry = new ImplAccelEntry( *rAccelData.maIdList[ i ] );
189 // sequence accelerator, then copy also
190 if ( pEntry->mpAccel )
192 pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
193 pEntry->mpAutoAccel = pEntry->mpAccel;
195 else
196 pEntry->mpAutoAccel = NULL;
198 mpData->maKeyMap.insert( std::make_pair( pEntry->maKeyCode.GetFullCode(), pEntry ) );
199 mpData->maIdList.push_back( pEntry );
203 // -----------------------------------------------------------------------
205 void Accelerator::ImplDeleteData()
207 // delete accelerator-entries using the id-table
208 for ( size_t i = 0, n = mpData->maIdList.size(); i < n; ++i ) {
209 ImplAccelEntry* pEntry = mpData->maIdList[ i ];
210 if ( pEntry->mpAutoAccel ) {
211 delete pEntry->mpAutoAccel;
213 delete pEntry;
215 mpData->maIdList.clear();
218 // -----------------------------------------------------------------------
220 void Accelerator::ImplInsertAccel( sal_uInt16 nItemId, const KeyCode& rKeyCode,
221 sal_Bool bEnable, Accelerator* pAutoAccel )
223 DBG_CHKTHIS( Accelerator, NULL );
224 DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" );
226 if ( rKeyCode.IsFunction() )
228 sal_uInt16 nCode1;
229 sal_uInt16 nCode2;
230 sal_uInt16 nCode3;
231 sal_uInt16 nCode4;
232 ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
233 if ( nCode1 )
234 ImplInsertAccel( nItemId, KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
235 if ( nCode2 )
237 if ( pAutoAccel )
238 pAutoAccel = new Accelerator( *pAutoAccel );
239 ImplInsertAccel( nItemId, KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
240 if ( nCode3 )
242 if ( pAutoAccel )
243 pAutoAccel = new Accelerator( *pAutoAccel );
244 ImplInsertAccel( nItemId, KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
247 return;
250 // fetch and fill new entries
251 ImplAccelEntry* pEntry = new ImplAccelEntry;
252 pEntry->mnId = nItemId;
253 pEntry->maKeyCode = rKeyCode;
254 pEntry->mpAccel = pAutoAccel;
255 pEntry->mpAutoAccel = pAutoAccel;
256 pEntry->mbEnabled = bEnable;
258 // now into the tables
259 sal_uLong nCode = rKeyCode.GetFullCode();
260 if ( !nCode )
262 OSL_FAIL( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
263 delete pEntry;
265 else if ( !mpData->maKeyMap.insert( std::make_pair( nCode, pEntry ) ).second )
267 SAL_WARN( "vcl.layout", "Accelerator::InsertItem(): KeyCode (Key: " << nCode << ") already exists" );
268 delete pEntry;
270 else
271 ImplAccelEntryInsert( &(mpData->maIdList), pEntry );
274 // -----------------------------------------------------------------------
276 Accelerator::Accelerator()
278 DBG_CTOR( Accelerator, NULL );
280 ImplInit();
281 mpData = new ImplAccelData;
284 // -----------------------------------------------------------------------
286 Accelerator::Accelerator( const Accelerator& rAccel ) :
287 Resource(),
288 maHelpStr( rAccel.maHelpStr ),
289 maCurKeyCode( rAccel.maCurKeyCode )
291 DBG_CTOR( Accelerator, NULL );
292 DBG_CHKOBJ( &rAccel, Accelerator, NULL );
294 ImplInit();
295 mpData = new ImplAccelData;
296 ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
299 // -----------------------------------------------------------------------
301 Accelerator::Accelerator( const ResId& rResId )
303 DBG_CTOR( Accelerator, NULL );
305 ImplInit();
306 mpData = new ImplAccelData;
307 rResId.SetRT( RSC_ACCEL );
308 ImplLoadRes( rResId );
311 // -----------------------------------------------------------------------
313 void Accelerator::ImplLoadRes( const ResId& rResId )
315 GetRes( rResId );
317 maHelpStr = ReadStringRes();
318 sal_uLong nObjFollows = ReadLongRes();
320 for( sal_uLong i = 0; i < nObjFollows; i++ )
322 InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
323 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
327 // -----------------------------------------------------------------------
329 Accelerator::~Accelerator()
331 DBG_DTOR( Accelerator, NULL );
333 // inform AccelManager about deleting the Accelerator
334 if ( mpDel )
335 *mpDel = sal_True;
337 ImplDeleteData();
338 delete mpData;
341 // -----------------------------------------------------------------------
343 void Accelerator::Activate()
345 maActivateHdl.Call( this );
348 // -----------------------------------------------------------------------
350 void Accelerator::Deactivate()
352 maDeactivateHdl.Call( this );
355 // -----------------------------------------------------------------------
357 void Accelerator::Select()
359 maSelectHdl.Call( this );
362 // -----------------------------------------------------------------------
364 void Accelerator::InsertItem( sal_uInt16 nItemId, const KeyCode& rKeyCode )
366 ImplInsertAccel( nItemId, rKeyCode, sal_True, NULL );
369 // -----------------------------------------------------------------------
371 void Accelerator::InsertItem( const ResId& rResId )
373 DBG_CHKTHIS( Accelerator, NULL );
375 sal_uLong nObjMask;
376 sal_uInt16 nAccelKeyId;
377 sal_uInt16 bDisable;
378 KeyCode aKeyCode;
379 Accelerator* pAutoAccel = NULL;
381 GetRes( rResId.SetRT( RSC_ACCELITEM ) );
382 nObjMask = ReadLongRes();
383 nAccelKeyId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
384 bDisable = ReadShortRes();
386 if ( nObjMask & ACCELITEM_KEY )
388 // new context was created
389 RSHEADER_TYPE * pKeyCodeRes = (RSHEADER_TYPE *)GetClassRes();
390 ResId aResId( pKeyCodeRes, *rResId.GetResMgr());
391 aKeyCode = KeyCode( aResId );
392 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
395 if ( nObjMask & ACCELITEM_ACCEL )
397 pAutoAccel = new Accelerator( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
398 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
401 ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel );
404 // -----------------------------------------------------------------------
406 sal_uInt16 Accelerator::GetItemCount() const
408 DBG_CHKTHIS( Accelerator, NULL );
410 return (sal_uInt16)mpData->maIdList.size();
413 // -----------------------------------------------------------------------
415 KeyCode Accelerator::GetKeyCode( sal_uInt16 nItemId ) const
417 DBG_CHKTHIS( Accelerator, NULL );
419 sal_uInt16 nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
420 if ( nIndex != ACCELENTRY_NOTFOUND )
421 return mpData->maIdList[ nIndex ]->maKeyCode;
422 else
423 return KeyCode();
426 // -----------------------------------------------------------------------
428 sal_uInt16 Accelerator::GetItemId( sal_uInt16 nPos ) const
430 DBG_CHKTHIS( Accelerator, NULL );
432 ImplAccelEntry* pEntry = ( nPos < mpData->maIdList.size() ) ? mpData->maIdList[ nPos ] : NULL;
433 if ( pEntry )
434 return pEntry->mnId;
435 else
436 return 0;
439 // -----------------------------------------------------------------------
441 Accelerator* Accelerator::GetAccel( sal_uInt16 nItemId ) const
443 DBG_CHKTHIS( Accelerator, NULL );
445 sal_uInt16 nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
446 if ( nIndex != ACCELENTRY_NOTFOUND )
447 return mpData->maIdList[ nIndex ]->mpAccel;
448 else
449 return NULL;
452 // -----------------------------------------------------------------------
454 Accelerator& Accelerator::operator=( const Accelerator& rAccel )
456 DBG_CHKTHIS( Accelerator, NULL );
457 DBG_CHKOBJ( &rAccel, Accelerator, NULL );
459 // assign new data
460 maHelpStr = rAccel.maHelpStr;
461 maCurKeyCode = KeyCode();
462 mnCurId = 0;
463 mnCurRepeat = 0;
464 mbIsCancel = sal_False;
466 // delete and copy tables
467 ImplDeleteData();
468 mpData->maKeyMap.clear();
469 ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
471 return *this;
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */