1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
24 #include <vcl/svapp.hxx>
26 #include <vcl/accel.hxx>
30 // =======================================================================
32 typedef ::std::map
< sal_uLong
, ImplAccelEntry
* > ImplAccelMap
;
33 typedef ::std::vector
< ImplAccelEntry
* > ImplAccelList
;
35 #define ACCELENTRY_NOTFOUND ((sal_uInt16)0xFFFF)
37 // =======================================================================
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
)
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
) )
66 return ACCELENTRY_NOTFOUND
;
74 nMid
= (nLow
+ nHigh
) / 2;
75 nCompareId
= (*pList
)[ nMid
]->mnId
;
76 if ( nId
< nCompareId
)
80 if ( nId
> nCompareId
)
83 return (sal_uInt16
)nMid
;
86 while ( nLow
<= nHigh
);
90 if ( nId
> nCompareId
)
91 *pIndex
= (sal_uInt16
)(nMid
+1);
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
)
111 ImplAccelEntry
* pTempEntry
= NULL
;
112 if ( nIndex
< pList
->size() )
113 pTempEntry
= (*pList
)[ nIndex
];
114 if ( !pTempEntry
|| (pTempEntry
->mnId
!= pEntry
->mnId
) )
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
);
124 pList
->push_back( pEntry
);
128 if ( nInsIndex
< pList
->size() ) {
129 ImplAccelList::iterator it
= pList
->begin();
130 ::std::advance( it
, nInsIndex
);
131 pList
->insert( it
, pEntry
);
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
)
148 if ( (*pList
)[ nIndex
]->mnId
!= nId
)
152 if ( (*pList
)[ nIndex
]->mnId
!= nId
)
159 // =======================================================================
161 void Accelerator::ImplInit()
165 mbIsCancel
= sal_False
;
169 // -----------------------------------------------------------------------
171 ImplAccelEntry
* Accelerator::ImplGetAccelData( const KeyCode
& rKeyCode
) const
173 ImplAccelMap::iterator it
= mpData
->maKeyMap
.find( rKeyCode
.GetFullCode() );
174 if( it
!= mpData
->maKeyMap
.end() )
180 // -----------------------------------------------------------------------
182 void Accelerator::ImplCopyData( ImplAccelData
& rAccelData
)
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
;
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
;
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() )
232 ImplGetKeyCode( rKeyCode
.GetFunction(), nCode1
, nCode2
, nCode3
, nCode4
);
234 ImplInsertAccel( nItemId
, KeyCode( nCode1
, nCode1
), bEnable
, pAutoAccel
);
238 pAutoAccel
= new Accelerator( *pAutoAccel
);
239 ImplInsertAccel( nItemId
, KeyCode( nCode2
, nCode2
), bEnable
, pAutoAccel
);
243 pAutoAccel
= new Accelerator( *pAutoAccel
);
244 ImplInsertAccel( nItemId
, KeyCode( nCode3
, nCode3
), bEnable
, pAutoAccel
);
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();
262 OSL_FAIL( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
265 else if ( !mpData
->maKeyMap
.insert( std::make_pair( nCode
, pEntry
) ).second
)
267 SAL_WARN( "vcl.layout", "Accelerator::InsertItem(): KeyCode (Key: " << nCode
<< ") already exists" );
271 ImplAccelEntryInsert( &(mpData
->maIdList
), pEntry
);
274 // -----------------------------------------------------------------------
276 Accelerator::Accelerator()
278 DBG_CTOR( Accelerator
, NULL
);
281 mpData
= new ImplAccelData
;
284 // -----------------------------------------------------------------------
286 Accelerator::Accelerator( const Accelerator
& rAccel
) :
288 maHelpStr( rAccel
.maHelpStr
),
289 maCurKeyCode( rAccel
.maCurKeyCode
)
291 DBG_CTOR( Accelerator
, NULL
);
292 DBG_CHKOBJ( &rAccel
, Accelerator
, NULL
);
295 mpData
= new ImplAccelData
;
296 ImplCopyData( *((ImplAccelData
*)(rAccel
.mpData
)) );
299 // -----------------------------------------------------------------------
301 Accelerator::Accelerator( const ResId
& rResId
)
303 DBG_CTOR( Accelerator
, NULL
);
306 mpData
= new ImplAccelData
;
307 rResId
.SetRT( RSC_ACCEL
);
308 ImplLoadRes( rResId
);
311 // -----------------------------------------------------------------------
313 void Accelerator::ImplLoadRes( const ResId
& 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
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
);
376 sal_uInt16 nAccelKeyId
;
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
;
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
;
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
;
452 // -----------------------------------------------------------------------
454 Accelerator
& Accelerator::operator=( const Accelerator
& rAccel
)
456 DBG_CHKTHIS( Accelerator
, NULL
);
457 DBG_CHKOBJ( &rAccel
, Accelerator
, NULL
);
460 maHelpStr
= rAccel
.maHelpStr
;
461 maCurKeyCode
= KeyCode();
464 mbIsCancel
= sal_False
;
466 // delete and copy tables
468 mpData
->maKeyMap
.clear();
469 ImplCopyData( *((ImplAccelData
*)(rAccel
.mpData
)) );
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */