1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accel.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <tools/list.hxx>
35 #include <tools/table.hxx>
37 #include <tools/debug.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/accel.h>
40 #include <vcl/accel.hxx>
47 // =======================================================================
49 DECLARE_TABLE( ImplAccelTable
, ImplAccelEntry
* )
50 DECLARE_LIST( ImplAccelList
, ImplAccelEntry
* )
52 #define ACCELENTRY_NOTFOUND ((USHORT)0xFFFF)
54 // =======================================================================
59 ImplAccelTable maKeyTable
; // Fuer KeyCodes, die mit einem Code erzeugt wurden
60 ImplAccelList maIdList
; // Id-List
63 // =======================================================================
65 DBG_NAME( Accelerator
)
67 // =======================================================================
69 USHORT
ImplAccelEntryGetIndex( ImplAccelList
* pList
, USHORT nId
,
70 USHORT
* pIndex
= NULL
)
75 ULONG nCount
= pList
->Count();
78 // Abpruefen, ob der erste Key groesser als der Vergleichskey ist
79 if ( !nCount
|| (nId
< pList
->GetObject( 0 )->mnId
) )
83 return ACCELENTRY_NOTFOUND
;
91 nMid
= (nLow
+ nHigh
) / 2;
92 nCompareId
= pList
->GetObject( nMid
)->mnId
;
93 if ( nId
< nCompareId
)
97 if ( nId
> nCompareId
)
103 while ( nLow
<= nHigh
);
107 if ( nId
> nCompareId
)
108 *pIndex
= (USHORT
)(nMid
+1);
110 *pIndex
= (USHORT
)nMid
;
113 return ACCELENTRY_NOTFOUND
;
116 // -----------------------------------------------------------------------
118 static void ImplAccelEntryInsert( ImplAccelList
* pList
, ImplAccelEntry
* pEntry
)
121 USHORT nIndex
= ImplAccelEntryGetIndex( pList
, pEntry
->mnId
, &nInsIndex
);
123 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
128 ImplAccelEntry
* pTempEntry
= pList
->GetObject( nIndex
);
129 if ( !pTempEntry
|| (pTempEntry
->mnId
!= pEntry
->mnId
) )
132 while ( nIndex
< pList
->Count() );
134 pList
->Insert( pEntry
, (ULONG
)nIndex
);
137 pList
->Insert( pEntry
, (ULONG
)nInsIndex
);
140 // -----------------------------------------------------------------------
142 static USHORT
ImplAccelEntryGetFirstPos( ImplAccelList
* pList
, USHORT nId
)
144 USHORT nIndex
= ImplAccelEntryGetIndex( pList
, nId
);
145 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
150 if ( pList
->GetObject( nIndex
)->mnId
!= nId
)
154 if ( pList
->GetObject( nIndex
)->mnId
!= nId
)
161 // =======================================================================
163 void Accelerator::ImplInit()
171 // -----------------------------------------------------------------------
173 ImplAccelEntry
* Accelerator::ImplGetAccelData( const KeyCode
& rKeyCode
) const
175 return mpData
->maKeyTable
.Get( rKeyCode
.GetFullKeyCode() );
178 // -----------------------------------------------------------------------
180 void Accelerator::ImplCopyData( ImplAccelData
& rAccelData
)
183 ImplAccelEntry
* pEntry
= rAccelData
.maIdList
.First();
186 pEntry
= new ImplAccelEntry( *pEntry
);
188 // Folge-Accelerator, dann auch kopieren
189 if ( pEntry
->mpAccel
)
191 pEntry
->mpAccel
= new Accelerator( *(pEntry
->mpAccel
) );
192 pEntry
->mpAutoAccel
= pEntry
->mpAccel
;
195 pEntry
->mpAutoAccel
= NULL
;
197 mpData
->maKeyTable
.Insert( (ULONG
)pEntry
->maKeyCode
.GetFullKeyCode(), pEntry
);
198 mpData
->maIdList
.Insert( pEntry
, LIST_APPEND
);
200 pEntry
= rAccelData
.maIdList
.Next();
204 // -----------------------------------------------------------------------
206 void Accelerator::ImplDeleteData()
208 // Accelerator-Eintraege ueber die Id-Tabelle loeschen
209 ImplAccelEntry
* pEntry
= mpData
->maIdList
.First();
212 // AutoResAccel zerstoeren
213 if ( pEntry
->mpAutoAccel
)
214 delete pEntry
->mpAutoAccel
;
217 pEntry
= mpData
->maIdList
.Next();
221 // -----------------------------------------------------------------------
223 void Accelerator::ImplInsertAccel( USHORT nItemId
, const KeyCode
& rKeyCode
,
224 BOOL bEnable
, Accelerator
* pAutoAccel
)
226 DBG_CHKTHIS( Accelerator
, NULL
);
227 DBG_ASSERT( nItemId
, "Accelerator::InsertItem(): ItemId == 0" );
229 if ( rKeyCode
.IsFunction() )
235 ImplGetKeyCode( rKeyCode
.GetFunction(), nCode1
, nCode2
, nCode3
, nCode4
);
237 ImplInsertAccel( nItemId
, KeyCode( nCode1
, nCode1
), bEnable
, pAutoAccel
);
241 pAutoAccel
= new Accelerator( *pAutoAccel
);
242 ImplInsertAccel( nItemId
, KeyCode( nCode2
, nCode2
), bEnable
, pAutoAccel
);
246 pAutoAccel
= new Accelerator( *pAutoAccel
);
247 ImplInsertAccel( nItemId
, KeyCode( nCode3
, nCode3
), bEnable
, pAutoAccel
);
253 // Neuen Eintrag holen und fuellen
254 ImplAccelEntry
* pEntry
= new ImplAccelEntry
;
255 pEntry
->mnId
= nItemId
;
256 pEntry
->maKeyCode
= rKeyCode
;
257 pEntry
->mpAccel
= pAutoAccel
;
258 pEntry
->mpAutoAccel
= pAutoAccel
;
259 pEntry
->mbEnabled
= bEnable
;
261 // Ab in die Tabellen
262 ULONG nCode
= rKeyCode
.GetFullKeyCode();
265 DBG_ERROR( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
268 else if ( !mpData
->maKeyTable
.Insert( nCode
, pEntry
) )
270 DBG_ERROR1( "Accelerator::InsertItem(): KeyCode (Key: %lx) already exists", nCode
);
274 ImplAccelEntryInsert( &(mpData
->maIdList
), pEntry
);
277 // -----------------------------------------------------------------------
279 Accelerator::Accelerator()
281 DBG_CTOR( Accelerator
, NULL
);
284 mpData
= new ImplAccelData
;
287 // -----------------------------------------------------------------------
289 Accelerator::Accelerator( const Accelerator
& rAccel
) :
291 maHelpStr( rAccel
.maHelpStr
),
292 maCurKeyCode( rAccel
.maCurKeyCode
)
294 DBG_CTOR( Accelerator
, NULL
);
295 DBG_CHKOBJ( &rAccel
, Accelerator
, NULL
);
298 mpData
= new ImplAccelData
;
299 ImplCopyData( *((ImplAccelData
*)(rAccel
.mpData
)) );
302 // -----------------------------------------------------------------------
304 Accelerator::Accelerator( const ResId
& rResId
)
306 DBG_CTOR( Accelerator
, NULL
);
309 mpData
= new ImplAccelData
;
310 rResId
.SetRT( RSC_ACCEL
);
311 ImplLoadRes( rResId
);
314 // -----------------------------------------------------------------------
316 void Accelerator::ImplLoadRes( const ResId
& rResId
)
320 maHelpStr
= ReadStringRes();
321 ULONG nObjFollows
= ReadLongRes();
323 for( ULONG i
= 0; i
< nObjFollows
; i
++ )
325 InsertItem( ResId( (RSHEADER_TYPE
*)GetClassRes(), *rResId
.GetResMgr() ) );
326 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE
*)GetClassRes() ) );
330 // -----------------------------------------------------------------------
332 Accelerator::~Accelerator()
334 DBG_DTOR( Accelerator
, NULL
);
336 // AccelManager benachrichtigen, das Accelrator geloescht wurde
344 // -----------------------------------------------------------------------
346 void Accelerator::Activate()
348 maActivateHdl
.Call( this );
351 // -----------------------------------------------------------------------
353 void Accelerator::Deactivate()
355 maDeactivateHdl
.Call( this );
358 // -----------------------------------------------------------------------
360 void Accelerator::Select()
362 maSelectHdl
.Call( this );
365 // -----------------------------------------------------------------------
367 void Accelerator::InsertItem( USHORT nItemId
, const KeyCode
& rKeyCode
)
369 ImplInsertAccel( nItemId
, rKeyCode
, TRUE
, NULL
);
372 // -----------------------------------------------------------------------
374 void Accelerator::InsertItem( const ResId
& rResId
)
376 DBG_CHKTHIS( Accelerator
, NULL
);
382 Accelerator
* pAutoAccel
= NULL
;
384 GetRes( rResId
.SetRT( RSC_ACCELITEM
) );
385 nObjMask
= ReadLongRes();
386 nAccelKeyId
= sal::static_int_cast
<USHORT
>(ReadLongRes());
387 bDisable
= ReadShortRes();
389 if ( nObjMask
& ACCELITEM_KEY
)
391 // es wird ein neuer Kontext aufgespannt
392 RSHEADER_TYPE
* pKeyCodeRes
= (RSHEADER_TYPE
*)GetClassRes();
393 ResId
aResId( pKeyCodeRes
, *rResId
.GetResMgr());
394 aKeyCode
= KeyCode( aResId
);
395 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE
*)GetClassRes() ) );
398 if ( nObjMask
& ACCELITEM_ACCEL
)
400 pAutoAccel
= new Accelerator( ResId( (RSHEADER_TYPE
*)GetClassRes(), *rResId
.GetResMgr() ) );
401 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE
*)GetClassRes() ) );
404 ImplInsertAccel( nAccelKeyId
, aKeyCode
, !bDisable
, pAutoAccel
);
407 // -----------------------------------------------------------------------
409 void Accelerator::RemoveItem( USHORT nItemId
)
411 DBG_CHKTHIS( Accelerator
, NULL
);
413 // Aus der Id-Liste entfernen
414 USHORT nIndex
= ImplAccelEntryGetFirstPos( &(mpData
->maIdList
), nItemId
);
415 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
417 USHORT nItemCount
= GetItemCount();
420 ImplAccelEntry
* pEntry
= mpData
->maIdList
.GetObject( (ULONG
)nIndex
);
421 if ( pEntry
&& pEntry
->mnId
== nItemId
)
423 mpData
->maKeyTable
.Remove( pEntry
->maKeyCode
.GetFullKeyCode() );
424 mpData
->maIdList
.Remove( (ULONG
)nIndex
);
426 // AutoResAccel zerstoeren
427 if ( pEntry
->mpAutoAccel
)
428 delete pEntry
->mpAutoAccel
;
435 while ( nIndex
< nItemCount
);
439 // -----------------------------------------------------------------------
441 void Accelerator::RemoveItem( const KeyCode rKeyCode
)
443 DBG_CHKTHIS( Accelerator
, NULL
);
445 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
448 // Aus der Id-Liste entfernen
449 USHORT nIndex
= ImplAccelEntryGetFirstPos( &(mpData
->maIdList
), pEntry
->mnId
);
450 USHORT nItemCount
= GetItemCount();
453 if ( mpData
->maIdList
.GetObject( (ULONG
)nIndex
) == pEntry
)
457 while ( nIndex
< nItemCount
);
459 mpData
->maKeyTable
.Remove( rKeyCode
.GetFullKeyCode() );
460 mpData
->maIdList
.Remove( (ULONG
)nIndex
);
462 // AutoResAccel zerstoeren
463 if ( pEntry
->mpAutoAccel
)
464 delete pEntry
->mpAutoAccel
;
470 // -----------------------------------------------------------------------
472 void Accelerator::Clear()
474 DBG_CHKTHIS( Accelerator
, NULL
);
477 mpData
->maKeyTable
.Clear();
478 mpData
->maIdList
.Clear();
481 // -----------------------------------------------------------------------
483 USHORT
Accelerator::GetItemCount() const
485 DBG_CHKTHIS( Accelerator
, NULL
);
487 return (USHORT
)mpData
->maIdList
.Count();
490 // -----------------------------------------------------------------------
492 USHORT
Accelerator::GetItemId( USHORT nPos
) const
494 DBG_CHKTHIS( Accelerator
, NULL
);
496 ImplAccelEntry
* pEntry
= mpData
->maIdList
.GetObject( (ULONG
)nPos
);
503 // -----------------------------------------------------------------------
505 KeyCode
Accelerator::GetItemKeyCode( USHORT nPos
) const
507 DBG_CHKTHIS( Accelerator
, NULL
);
509 ImplAccelEntry
* pEntry
= mpData
->maIdList
.GetObject( (ULONG
)nPos
);
511 return pEntry
->maKeyCode
;
516 // -----------------------------------------------------------------------
518 USHORT
Accelerator::GetItemId( const KeyCode
& rKeyCode
) const
520 DBG_CHKTHIS( Accelerator
, NULL
);
522 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
529 // -----------------------------------------------------------------------
531 KeyCode
Accelerator::GetKeyCode( USHORT nItemId
) const
533 DBG_CHKTHIS( Accelerator
, NULL
);
535 USHORT nIndex
= ImplAccelEntryGetFirstPos( &(mpData
->maIdList
), nItemId
);
536 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
537 return mpData
->maIdList
.GetObject( (ULONG
)nIndex
)->maKeyCode
;
542 // -----------------------------------------------------------------------
544 BOOL
Accelerator::IsIdValid( USHORT nItemId
) const
546 DBG_CHKTHIS( Accelerator
, NULL
);
548 USHORT nIndex
= ImplAccelEntryGetIndex( &(mpData
->maIdList
), nItemId
);
549 return (nIndex
!= ACCELENTRY_NOTFOUND
);
552 // -----------------------------------------------------------------------
554 BOOL
Accelerator::IsKeyCodeValid( const KeyCode rKeyCode
) const
556 DBG_CHKTHIS( Accelerator
, NULL
);
558 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
559 return (pEntry
!= NULL
);
562 // -----------------------------------------------------------------------
564 BOOL
Accelerator::Call( const KeyCode
& rKeyCode
, USHORT nRepeat
)
566 DBG_CHKTHIS( Accelerator
, NULL
);
568 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
571 if ( pEntry
->mbEnabled
)
574 mnCurId
= pEntry
->mnId
;
575 maCurKeyCode
= rKeyCode
;
576 mnCurRepeat
= nRepeat
;
582 maCurKeyCode
= KeyCode();
593 // -----------------------------------------------------------------------
595 void Accelerator::SetAccel( USHORT nItemId
, Accelerator
* pAccel
)
597 DBG_CHKTHIS( Accelerator
, NULL
);
599 USHORT nIndex
= ImplAccelEntryGetFirstPos( &(mpData
->maIdList
), nItemId
);
600 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
602 USHORT nItemCount
= GetItemCount();
605 ImplAccelEntry
* pEntry
= mpData
->maIdList
.GetObject( (ULONG
)nIndex
);
606 if ( pEntry
->mnId
!= nItemId
)
609 pEntry
->mpAccel
= pAccel
;
612 while ( nIndex
< nItemCount
);
616 // -----------------------------------------------------------------------
618 Accelerator
* Accelerator::GetAccel( USHORT nItemId
) const
620 DBG_CHKTHIS( Accelerator
, NULL
);
622 USHORT nIndex
= ImplAccelEntryGetIndex( &(mpData
->maIdList
), nItemId
);
623 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
624 return mpData
->maIdList
.GetObject( (ULONG
)nIndex
)->mpAccel
;
629 // -----------------------------------------------------------------------
631 void Accelerator::SetAccel( const KeyCode rKeyCode
, Accelerator
* pAccel
)
633 DBG_CHKTHIS( Accelerator
, NULL
);
635 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
637 pEntry
->mpAccel
= pAccel
;
640 // -----------------------------------------------------------------------
642 Accelerator
* Accelerator::GetAccel( const KeyCode rKeyCode
) const
644 DBG_CHKTHIS( Accelerator
, NULL
);
646 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
648 return pEntry
->mpAccel
;
653 // -----------------------------------------------------------------------
655 void Accelerator::EnableItem( USHORT nItemId
, BOOL bEnable
)
657 DBG_CHKTHIS( Accelerator
, NULL
);
659 USHORT nIndex
= ImplAccelEntryGetFirstPos( &(mpData
->maIdList
), nItemId
);
660 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
662 USHORT nItemCount
= GetItemCount();
665 ImplAccelEntry
* pEntry
= mpData
->maIdList
.GetObject( (ULONG
)nIndex
);
666 if ( pEntry
->mnId
!= nItemId
)
669 pEntry
->mbEnabled
= bEnable
;
672 while ( nIndex
< nItemCount
);
676 // -----------------------------------------------------------------------
678 BOOL
Accelerator::IsItemEnabled( USHORT nItemId
) const
680 DBG_CHKTHIS( Accelerator
, NULL
);
682 USHORT nIndex
= ImplAccelEntryGetIndex( &(mpData
->maIdList
), nItemId
);
683 if ( nIndex
!= ACCELENTRY_NOTFOUND
)
684 return mpData
->maIdList
.GetObject( (ULONG
)nIndex
)->mbEnabled
;
689 // -----------------------------------------------------------------------
691 void Accelerator::EnableItem( const KeyCode rKeyCode
, BOOL bEnable
)
693 DBG_CHKTHIS( Accelerator
, NULL
);
695 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
697 pEntry
->mbEnabled
= bEnable
;
700 // -----------------------------------------------------------------------
702 BOOL
Accelerator::IsItemEnabled( const KeyCode rKeyCode
) const
704 DBG_CHKTHIS( Accelerator
, NULL
);
706 ImplAccelEntry
* pEntry
= ImplGetAccelData( rKeyCode
);
708 return pEntry
->mbEnabled
;
713 // -----------------------------------------------------------------------
715 Accelerator
& Accelerator::operator=( const Accelerator
& rAccel
)
717 DBG_CHKTHIS( Accelerator
, NULL
);
718 DBG_CHKOBJ( &rAccel
, Accelerator
, NULL
);
720 // Neue Daten zuweisen
721 maHelpStr
= rAccel
.maHelpStr
;
722 maCurKeyCode
= KeyCode();
727 // Tabellen loeschen und kopieren
729 mpData
->maKeyTable
.Clear();
730 mpData
->maIdList
.Clear();
731 ImplCopyData( *((ImplAccelData
*)(rAccel
.mpData
)) );