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 .
24 #include "dlgctrl.hxx"
25 #include <vcl/event.hxx>
26 #include <vcl/toolkit/fixed.hxx>
27 #include <vcl/layout.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/tabpage.hxx>
30 #include <vcl/tabctrl.hxx>
31 #include <vcl/toolkit/button.hxx>
32 #include <vcl/settings.hxx>
33 #include <sal/log.hxx>
34 #include <i18nlangtag/languagetag.hxx>
36 #include <com/sun/star/i18n/XCharacterClassification.hpp>
38 using namespace ::com::sun::star
;
40 static bool ImplHasIndirectTabParent( vcl::Window
* pWindow
)
42 // The window has indirect tab parent if it is included in tab hierarchy
43 // of the indirect parent window
45 vcl::Window
* pNonLayoutParent
= getNonLayoutParent(pWindow
);
46 return ( pNonLayoutParent
47 && ( pNonLayoutParent
->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL
) );
50 static vcl::Window
* ImplGetTopParentOfTabHierarchy( vcl::Window
* pParent
)
52 // The method allows to find the most close parent containing all the
53 // window from the current tab-hierarchy
54 // The direct parent should be provided as a parameter here
56 vcl::Window
* pResult
= pParent
;
60 vcl::Window
* pNonLayoutParent
= getNonLayoutParent(pResult
);
61 while ( pNonLayoutParent
&& ( pResult
->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL
) )
63 pResult
= pNonLayoutParent
;
64 pNonLayoutParent
= getNonLayoutParent(pResult
);
71 static vcl::Window
* ImplGetCurTabWindow(const vcl::Window
* pWindow
)
73 assert(pWindow
->GetType() == WindowType::TABCONTROL
);
74 const TabControl
* pTabControl
= static_cast<const TabControl
*>(pWindow
);
75 // Check if the TabPage is a Child of the TabControl and still exists (by
76 // walking all child windows); because it could be that the TabPage has been
77 // destroyed already by a Dialog-Dtor, event that the TabControl still exists.
78 const TabPage
* pTempTabPage
= pTabControl
->GetTabPage(pTabControl
->GetCurPageId());
81 vcl::Window
* pTempWindow
= pTabControl
->GetWindow(GetWindowType::FirstChild
);
84 if (pTempWindow
->ImplGetWindow() == pTempTabPage
)
86 return const_cast<TabPage
*>(pTempTabPage
);
88 pTempWindow
= nextLogicalChildOfParent(pTabControl
, pTempWindow
);
95 static vcl::Window
* ImplGetSubChildWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
)
97 // ignore all windows with mpClientWindow set
98 for (vcl::Window
*pNewParent
= pParent
->ImplGetWindow();
99 pParent
!= pNewParent
; pParent
= pNewParent
);
101 vcl::Window
* pFoundWindow
= nullptr;
102 vcl::Window
* pWindow
= firstLogicalChildOfParent(pParent
);
103 vcl::Window
* pNextWindow
= pWindow
;
105 // process just the current page of a tab control
106 if (pWindow
&& pParent
->GetType() == WindowType::TABCONTROL
)
108 pWindow
= ImplGetCurTabWindow(pParent
);
109 pNextWindow
= lastLogicalChildOfParent(pParent
);
114 pWindow
= pWindow
->ImplGetWindow();
116 // skip invisible and disabled windows
117 if (isVisibleInLayout(pWindow
))
119 // return the TabControl itself, before handling its page
120 if (pWindow
->GetType() == WindowType::TABCONTROL
)
126 if (pWindow
->GetStyle() & (WB_DIALOGCONTROL
| WB_CHILDDLGCTRL
))
127 pFoundWindow
= ImplGetSubChildWindow(pWindow
, n
, nIndex
);
129 pFoundWindow
= pWindow
;
136 pWindow
= nextLogicalChildOfParent(pParent
, pNextWindow
);
137 pNextWindow
= pWindow
;
141 assert(!pFoundWindow
|| (pFoundWindow
== pFoundWindow
->ImplGetWindow()));
145 vcl::Window
* ImplGetChildWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
, bool bTestEnable
)
147 pParent
= ImplGetTopParentOfTabHierarchy( pParent
);
150 vcl::Window
* pWindow
= ImplGetSubChildWindow( pParent
, n
, nIndex
);
153 sal_uInt16 n2
= nIndex
;
154 while ( pWindow
&& (!isEnabledInLayout(pWindow
) || !pWindow
->IsInputEnabled()) )
158 pWindow
= ImplGetSubChildWindow( pParent
, n2
, nIndex
);
163 if ( (nIndex
< n2
) && n
)
169 pWindow
= ImplGetSubChildWindow( pParent
, n
, nIndex
);
171 while ( pWindow
&& n
&& (!isEnabledInLayout(pWindow
) || !pWindow
->IsInputEnabled()) );
177 static vcl::Window
* ImplGetNextWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
, bool bTestEnable
)
179 vcl::Window
* pWindow
= ImplGetChildWindow( pParent
, n
+1, nIndex
, bTestEnable
);
183 pWindow
= ImplGetChildWindow( pParent
, n
, nIndex
, bTestEnable
);
190 static bool lcl_ToolBoxTabStop( Window
* pWindow
)
192 ToolBox
* pToolBoxWindow
= static_cast<ToolBox
*>( pWindow
);
195 for ( ToolBox::ImplToolItems::size_type nPos
= 0; nPos
< pToolBoxWindow
->GetItemCount(); nPos
++ )
197 nId
= pToolBoxWindow
->GetItemId( nPos
);
198 if ( pToolBoxWindow
->IsItemVisible( nId
) && pToolBoxWindow
->IsItemEnabled( nId
) )
205 vcl::Window
* Window::ImplGetDlgWindow( sal_uInt16 nIndex
, GetDlgWindowType nType
,
206 sal_uInt16 nFormStart
, sal_uInt16 nFormEnd
,
209 SAL_WARN_IF( (nIndex
< nFormStart
) || (nIndex
> nFormEnd
), "vcl",
210 "Window::ImplGetDlgWindow() - nIndex not in Form" );
212 vcl::Window
* pWindow
= nullptr;
215 sal_uInt16 nStartIndex
;
217 if ( nType
== GetDlgWindowType::Prev
)
222 if ( i
> nFormStart
)
226 pWindow
= ImplGetChildWindow( this, i
, nTemp
, true );
229 if ( (i
== nTemp
) && (pWindow
->GetStyle() & WB_TABSTOP
) )
231 if ( WindowType::TOOLBOX
== pWindow
->GetType() )
233 if ( lcl_ToolBoxTabStop( pWindow
) )
240 while ( i
!= nIndex
);
245 pWindow
= ImplGetChildWindow( this, i
, i
, (nType
== GetDlgWindowType::First
) );
250 if ( nType
== GetDlgWindowType::Next
)
254 pWindow
= ImplGetNextWindow( this, i
, i
, true );
255 if ( (i
> nFormEnd
) || (i
< nFormStart
) )
256 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
259 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
262 if (i
<= nFormEnd
&& pWindow
)
264 // carry the 2nd index, in case all controls are disabled
265 sal_uInt16 nStartIndex2
= i
;
266 sal_uInt16 nOldIndex
= i
+1;
270 if ( pWindow
->GetStyle() & WB_TABSTOP
)
272 if ( WindowType::TOOLBOX
== pWindow
->GetType() )
274 if ( lcl_ToolBoxTabStop( pWindow
) )
280 if( i
== nOldIndex
) // only disabled controls ?
286 if ( (i
> nFormEnd
) || (i
< nFormStart
) )
287 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
289 pWindow
= ImplGetNextWindow( this, i
, i
, true );
291 while (i
!= nStartIndex
&& i
!= nStartIndex2
&& pWindow
);
293 if ( (i
== nStartIndex2
) && pWindow
&&
294 (!(pWindow
->GetStyle() & WB_TABSTOP
) || !isEnabledInLayout(pWindow
)) )
299 if ( nType
== GetDlgWindowType::First
)
303 if ( pWindow
->GetType() == WindowType::TABCONTROL
)
305 vcl::Window
* pNextWindow
= ImplGetDlgWindow( i
, GetDlgWindowType::Next
);
308 if ( pWindow
->IsChild( pNextWindow
) )
309 pWindow
= pNextWindow
;
313 if ( !(pWindow
->GetStyle() & WB_TABSTOP
) )
325 } /* namespace vcl */
327 vcl::Window
* ImplFindDlgCtrlWindow( vcl::Window
* pParent
, vcl::Window
* pWindow
, sal_uInt16
& rIndex
,
328 sal_uInt16
& rFormStart
, sal_uInt16
& rFormEnd
)
330 vcl::Window
* pSWindow
;
331 vcl::Window
* pSecondWindow
= nullptr;
332 vcl::Window
* pTempWindow
= nullptr;
334 sal_uInt16 nSecond_i
= 0;
335 sal_uInt16 nFormStart
= 0;
336 sal_uInt16 nSecondFormStart
= 0;
339 // find focus window in the child list
340 vcl::Window
* pFirstChildWindow
= pSWindow
= ImplGetChildWindow( pParent
, 0, i
, false );
342 if( pWindow
== nullptr )
347 // the DialogControlStart mark is only accepted for the direct children
348 if ( !ImplHasIndirectTabParent( pSWindow
)
349 && pSWindow
->ImplGetWindow()->IsDialogControlStart() )
352 // SecondWindow for composite controls like ComboBoxes and arrays
353 if ( pSWindow
->ImplIsWindowOrChild( pWindow
) )
355 pSecondWindow
= pSWindow
;
357 nSecondFormStart
= nFormStart
;
358 if ( pSWindow
== pWindow
)
362 pSWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
369 // Window not found; we cannot handle it
370 if ( !pSecondWindow
)
374 pSWindow
= pSecondWindow
;
376 nFormStart
= nSecondFormStart
;
382 rFormStart
= nFormStart
;
384 // find end of template
385 sal_Int32 nIteration
= 0;
389 pTempWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
391 // the DialogControlStart mark is only accepted for the direct children
393 || ( pTempWindow
&& !ImplHasIndirectTabParent( pTempWindow
)
394 && pTempWindow
->ImplGetWindow()->IsDialogControlStart() ) )
397 if ( pTempWindow
&& pTempWindow
== pFirstChildWindow
)
399 // It is possible to go through the begin of hierarchy once
400 // while looking for DialogControlStart mark.
401 // If it happens second time, it looks like an endless loop,
402 // that should be impossible, but just for the case...
404 if ( nIteration
>= 2 )
406 // this is an unexpected scenario
407 SAL_WARN( "vcl", "It seems to be an endless loop!" );
413 while ( pTempWindow
);
419 vcl::Window
* ImplFindAccelWindow( vcl::Window
* pParent
, sal_uInt16
& rIndex
, sal_Unicode cCharCode
,
420 sal_uInt16 nFormStart
, sal_uInt16 nFormEnd
, bool bCheckEnable
)
422 SAL_WARN_IF( (rIndex
< nFormStart
) || (rIndex
> nFormEnd
), "vcl",
423 "Window::ImplFindAccelWindow() - rIndex not in Form" );
425 sal_Unicode cCompareChar
;
426 sal_uInt16 nStart
= rIndex
;
427 sal_uInt16 i
= rIndex
;
428 vcl::Window
* pWindow
;
430 uno::Reference
<i18n::XCharacterClassification
> const& xCharClass(ImplGetCharClass());
432 const css::lang::Locale
& rLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
433 cCharCode
= xCharClass
->toUpper( OUString(cCharCode
), 0, 1, rLocale
)[0];
436 pWindow
= ImplGetNextWindow( pParent
, i
, i
, true );
438 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, true );
441 const OUString aStr
= pWindow
->GetText();
442 sal_Int32 nPos
= aStr
.indexOf( '~' );
445 cCompareChar
= aStr
[nPos
+1];
446 cCompareChar
= xCharClass
->toUpper( OUString(cCompareChar
), 0, 1, rLocale
)[0];
447 if ( cCompareChar
== cCharCode
)
449 if (pWindow
->GetType() == WindowType::FIXEDTEXT
)
451 FixedText
*pFixedText
= static_cast<FixedText
*>(pWindow
);
452 vcl::Window
*pMnemonicWidget
= pFixedText
->get_mnemonic_widget();
453 SAL_WARN_IF(isContainerWindow(pFixedText
->GetParent()) && !pMnemonicWidget
,
454 "vcl.a11y", "label missing mnemonic_widget?");
456 return pMnemonicWidget
;
459 // skip Static-Controls
460 if ( (pWindow
->GetType() == WindowType::FIXEDTEXT
) ||
461 (pWindow
->GetType() == WindowType::FIXEDLINE
) ||
462 (pWindow
->GetType() == WindowType::GROUPBOX
) )
463 pWindow
= pParent
->ImplGetDlgWindow( i
, GetDlgWindowType::Next
);
467 nPos
= aStr
.indexOf( '~', nPos
+1 );
470 // #i93011# it would have made sense to have this really recursive
471 // right from the start. However this would cause unpredictable side effects now
472 // so instead we have a style bit for some child windows, that want their
473 // children checked for accelerators
474 if( (pWindow
->GetStyle() & WB_CHILDDLGCTRL
) != 0 )
476 sal_uInt16 nChildIndex
;
477 sal_uInt16 nChildFormStart
;
478 sal_uInt16 nChildFormEnd
;
480 // get form start and end
481 ::ImplFindDlgCtrlWindow( pWindow
, nullptr,
482 nChildIndex
, nChildFormStart
, nChildFormEnd
);
483 vcl::Window
* pAccelWin
= ImplFindAccelWindow( pWindow
, nChildIndex
, cCharCode
,
484 nChildFormStart
, nChildFormEnd
,
495 pWindow
= ImplGetNextWindow( pParent
, i
, i
, bCheckEnable
);
497 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, bCheckEnable
);
500 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, bCheckEnable
);
508 void Window::SetMnemonicActivateHdl(const Link
<vcl::Window
&, bool>& rLink
)
510 if (mpWindowImpl
) // may be called after dispose
512 mpWindowImpl
->maMnemonicActivateHdl
= rLink
;
516 void Window::ImplControlFocus( GetFocusFlags nFlags
)
518 if ( nFlags
& GetFocusFlags::Mnemonic
)
520 if (mpWindowImpl
->maMnemonicActivateHdl
.Call(*this))
523 if ( GetType() == WindowType::RADIOBUTTON
)
525 if ( !static_cast<RadioButton
*>(this)->IsChecked() )
526 static_cast<RadioButton
*>(this)->ImplCallClick( true, nFlags
);
528 ImplGrabFocus( nFlags
);
532 ImplGrabFocus( nFlags
);
533 if ( nFlags
& GetFocusFlags::UniqueMnemonic
)
535 if ( GetType() == WindowType::CHECKBOX
)
536 static_cast<CheckBox
*>(this)->ImplCheck();
537 else if ( mpWindowImpl
->mbPushButton
)
539 static_cast<PushButton
*>(this)->SetPressed( true );
540 static_cast<PushButton
*>(this)->SetPressed( false );
541 static_cast<PushButton
*>(this)->Click();
548 if ( GetType() == WindowType::RADIOBUTTON
)
550 if ( !static_cast<RadioButton
*>(this)->IsChecked() )
551 static_cast<RadioButton
*>(this)->ImplCallClick( true, nFlags
);
553 ImplGrabFocus( nFlags
);
556 ImplGrabFocus( nFlags
);
560 } /* namespace vcl */
564 bool isSuitableDestination(vcl::Window
const *pWindow
)
566 return (pWindow
&& isVisibleInLayout(pWindow
) &&
567 isEnabledInLayout(pWindow
) && pWindow
->IsInputEnabled() &&
568 //Pure window shouldn't get window after controls such as
570 (pWindow
->GetType() != WindowType::WINDOW
&&
571 pWindow
->GetType() != WindowType::WORKWINDOW
&& pWindow
->GetType() != WindowType::CONTROL
)
575 bool focusNextInGroup(const std::vector
<VclPtr
<RadioButton
> >::iterator
& aStart
, std::vector
<VclPtr
<RadioButton
> > &rGroup
)
577 std::vector
<VclPtr
<RadioButton
> >::iterator
aI(aStart
);
579 if (aStart
!= rGroup
.end())
582 aI
= std::find_if(aI
, rGroup
.end(), isSuitableDestination
);
583 if (aI
!= rGroup
.end())
585 vcl::Window
*pWindow
= *aI
;
586 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Forward
);
589 aI
= std::find_if(rGroup
.begin(), aStart
, isSuitableDestination
);
592 vcl::Window
*pWindow
= *aI
;
593 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Forward
);
599 bool nextInGroup(RadioButton
*pSourceWindow
, bool bBackward
)
601 std::vector
<VclPtr
<RadioButton
> > aGroup(pSourceWindow
->GetRadioButtonGroup());
603 if (aGroup
.size() < 2) // have to have at last 2 buttons to be a useful group
607 std::reverse(aGroup
.begin(), aGroup
.end());
609 auto aStart(std::find(aGroup
.begin(), aGroup
.end(), VclPtr
<RadioButton
>(pSourceWindow
)));
611 assert(aStart
!= aGroup
.end());
613 return focusNextInGroup(aStart
, aGroup
);
619 bool Window::ImplDlgCtrl( const KeyEvent
& rKEvt
, bool bKeyInput
)
621 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
622 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
623 vcl::Window
* pSWindow
;
624 vcl::Window
* pTempWindow
;
625 vcl::Window
* pButtonWindow
;
628 sal_uInt16 iButtonStart
;
631 sal_uInt16 nFormStart
;
633 DialogControlFlags nDlgCtrlFlags
;
635 // we cannot take over control without Focus-window
636 vcl::Window
* pFocusWindow
= Application::GetFocusWindow();
637 if ( !pFocusWindow
|| !ImplIsWindowOrChild( pFocusWindow
) )
640 // find Focus-Window in the child list
641 pSWindow
= ::ImplFindDlgCtrlWindow( this, pFocusWindow
,
642 nIndex
, nFormStart
, nFormEnd
);
647 nDlgCtrlFlags
= DialogControlFlags::NONE
;
648 pTempWindow
= pSWindow
;
651 nDlgCtrlFlags
|= pTempWindow
->GetDialogControlFlags();
652 if ( pTempWindow
== this )
654 pTempWindow
= pTempWindow
->ImplGetParent();
656 while ( pTempWindow
);
658 pButtonWindow
= nullptr;
660 if ( nKeyCode
== KEY_RETURN
)
662 // search first for a DefPushButton/CancelButton
663 pButtonWindow
= ImplGetChildWindow( this, nFormStart
, iButton
, true );
664 iButtonStart
= iButton
;
665 while ( pButtonWindow
)
667 if ( (pButtonWindow
->GetStyle() & WB_DEFBUTTON
) &&
668 pButtonWindow
->mpWindowImpl
->mbPushButton
)
671 pButtonWindow
= ImplGetNextWindow( this, iButton
, iButton
, true );
672 if ( (iButton
<= iButtonStart
) || (iButton
> nFormEnd
) )
673 pButtonWindow
= nullptr;
676 if ( bKeyInput
&& !pButtonWindow
&& (nDlgCtrlFlags
& DialogControlFlags::Return
) )
678 GetDlgWindowType nType
;
679 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Tab
;
680 sal_uInt16 nNewIndex
;
682 if ( aKeyCode
.IsShift() )
684 nType
= GetDlgWindowType::Prev
;
685 nGetFocusFlags
|= GetFocusFlags::Backward
;
689 nType
= GetDlgWindowType::Next
;
690 nGetFocusFlags
|= GetFocusFlags::Forward
;
693 pTempWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
694 while ( pTempWindow
&& (pTempWindow
!= pSWindow
) )
696 if ( !pTempWindow
->mpWindowImpl
->mbPushButton
)
699 if ( nType
== GetDlgWindowType::Prev
)
701 if ( nNewIndex
> iStart
)
702 nGetFocusFlags
|= GetFocusFlags::Around
;
706 if ( nNewIndex
< iStart
)
707 nGetFocusFlags
|= GetFocusFlags::Around
;
709 pTempWindow
->ImplControlFocus( nGetFocusFlags
);
715 pTempWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
717 if ( (i
<= iStart
) || (i
> nFormEnd
) )
718 pTempWindow
= nullptr;
720 // if this is the same window, simulate a Get/LoseFocus,
721 // in case AROUND is being processed
722 if ( pTempWindow
&& (pTempWindow
== pSWindow
) )
724 NotifyEvent
aNEvt1( MouseNotifyEvent::LOSEFOCUS
, pSWindow
);
725 if ( !ImplCallPreNotify( aNEvt1
) )
726 pSWindow
->CompatLoseFocus();
727 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= nGetFocusFlags
| GetFocusFlags::Around
;
728 NotifyEvent
aNEvt2( MouseNotifyEvent::GETFOCUS
, pSWindow
);
729 if ( !ImplCallPreNotify( aNEvt2
) )
730 pSWindow
->CompatGetFocus();
731 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= GetFocusFlags::NONE
;
736 else if ( nKeyCode
== KEY_ESCAPE
)
738 // search first for a DefPushButton/CancelButton
739 pButtonWindow
= ImplGetChildWindow( this, nFormStart
, iButton
, true );
740 iButtonStart
= iButton
;
741 while ( pButtonWindow
)
743 if ( pButtonWindow
->GetType() == WindowType::CANCELBUTTON
)
746 pButtonWindow
= ImplGetNextWindow( this, iButton
, iButton
, true );
747 if ( (iButton
<= iButtonStart
) || (iButton
> nFormEnd
) )
748 pButtonWindow
= nullptr;
751 if ( bKeyInput
&& mpWindowImpl
->mpDlgCtrlDownWindow
)
753 if ( mpWindowImpl
->mpDlgCtrlDownWindow
.get() != pButtonWindow
)
755 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
756 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
761 else if ( bKeyInput
)
763 if ( nKeyCode
== KEY_TAB
)
765 // do not skip Alt key, for MS Windows
766 if ( !aKeyCode
.IsMod2() )
768 sal_uInt16 nNewIndex
;
771 // for Ctrl-Tab check if we want to jump to next template
772 if ( aKeyCode
.IsMod1() )
775 vcl::Window
* pFormFirstWindow
= nullptr;
776 vcl::Window
* pLastFormFirstWindow
= nullptr;
777 pTempWindow
= ImplGetChildWindow( this, 0, iTemp
, false );
778 vcl::Window
* pPrevFirstFormFirstWindow
= nullptr;
779 vcl::Window
* pFirstFormFirstWindow
= pTempWindow
;
780 while ( pTempWindow
)
782 if ( pTempWindow
->ImplGetWindow()->IsDialogControlStart() )
786 if ( aKeyCode
.IsShift() )
788 if ( iTemp
<= nIndex
)
789 pFormFirstWindow
= pPrevFirstFormFirstWindow
;
790 pPrevFirstFormFirstWindow
= pTempWindow
;
794 if ( (iTemp
> nIndex
) && !pFormFirstWindow
)
795 pFormFirstWindow
= pTempWindow
;
797 pLastFormFirstWindow
= pTempWindow
;
800 pTempWindow
= ImplGetNextWindow( this, iTemp
, iTemp
, false );
802 pTempWindow
= nullptr;
807 if ( !pFormFirstWindow
)
809 if ( aKeyCode
.IsShift() )
810 pFormFirstWindow
= pLastFormFirstWindow
;
812 pFormFirstWindow
= pFirstFormFirstWindow
;
815 sal_uInt16 nFoundFormStart
= 0;
816 sal_uInt16 nFoundFormEnd
= 0;
817 sal_uInt16 nTempIndex
= 0;
818 if ( ::ImplFindDlgCtrlWindow( this, pFormFirstWindow
, nTempIndex
,
819 nFoundFormStart
, nFoundFormEnd
) )
821 nTempIndex
= nFoundFormStart
;
822 pFormFirstWindow
= ImplGetDlgWindow( nTempIndex
, GetDlgWindowType::First
, nFoundFormStart
, nFoundFormEnd
);
823 if ( pFormFirstWindow
)
825 pFormFirstWindow
->ImplControlFocus();
834 // Only use Ctrl-TAB if it was allowed for the whole
835 // dialog or for the current control (#103667#)
836 if (!aKeyCode
.IsMod1() || (pSWindow
->GetStyle() & WB_NODIALOGCONTROL
))
838 GetDlgWindowType nType
;
839 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Tab
;
840 if ( aKeyCode
.IsShift() )
842 nType
= GetDlgWindowType::Prev
;
843 nGetFocusFlags
|= GetFocusFlags::Backward
;
847 nType
= GetDlgWindowType::Next
;
848 nGetFocusFlags
|= GetFocusFlags::Forward
;
850 vcl::Window
* pWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
851 // if this is the same window, simulate a Get/LoseFocus,
852 // in case AROUND is being processed
853 if ( pWindow
== pSWindow
)
855 NotifyEvent
aNEvt1( MouseNotifyEvent::LOSEFOCUS
, pSWindow
);
856 if ( !ImplCallPreNotify( aNEvt1
) )
857 pSWindow
->CompatLoseFocus();
858 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= nGetFocusFlags
| GetFocusFlags::Around
;
859 NotifyEvent
aNEvt2( MouseNotifyEvent::GETFOCUS
, pSWindow
);
860 if ( !ImplCallPreNotify( aNEvt2
) )
861 pSWindow
->CompatGetFocus();
862 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= GetFocusFlags::NONE
;
868 if ( nType
== GetDlgWindowType::Prev
)
871 nGetFocusFlags
|= GetFocusFlags::Around
;
876 nGetFocusFlags
|= GetFocusFlags::Around
;
878 pWindow
->ImplControlFocus( nGetFocusFlags
);
885 else if ( (nKeyCode
== KEY_LEFT
) || (nKeyCode
== KEY_UP
) )
887 if (pSWindow
->GetType() == WindowType::RADIOBUTTON
)
888 return nextInGroup(static_cast<RadioButton
*>(pSWindow
), true);
891 WinBits nStyle
= pSWindow
->GetStyle();
892 if ( !(nStyle
& WB_GROUP
) )
894 vcl::Window
* pWindow
= prevLogicalChildOfParent(this, pSWindow
);
897 pWindow
= pWindow
->ImplGetWindow();
899 nStyle
= pWindow
->GetStyle();
901 if (isSuitableDestination(pWindow
))
903 if ( pWindow
!= pSWindow
)
904 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Backward
);
908 if ( nStyle
& WB_GROUP
)
911 pWindow
= prevLogicalChildOfParent(this, pWindow
);
916 else if ( (nKeyCode
== KEY_RIGHT
) || (nKeyCode
== KEY_DOWN
) )
918 if (pSWindow
->GetType() == WindowType::RADIOBUTTON
)
919 return nextInGroup(static_cast<RadioButton
*>(pSWindow
), false);
922 vcl::Window
* pWindow
= nextLogicalChildOfParent(this, pSWindow
);
925 pWindow
= pWindow
->ImplGetWindow();
927 WinBits nStyle
= pWindow
->GetStyle();
929 if ( nStyle
& WB_GROUP
)
932 if (isSuitableDestination(pWindow
))
934 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Backward
);
938 pWindow
= nextLogicalChildOfParent(this, pWindow
);
944 sal_Unicode c
= rKEvt
.GetCharCode();
947 pSWindow
= ::ImplFindAccelWindow( this, i
, c
, nFormStart
, nFormEnd
);
950 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Mnemonic
;
951 if ( pSWindow
== ::ImplFindAccelWindow( this, i
, c
, nFormStart
, nFormEnd
) )
952 nGetFocusFlags
|= GetFocusFlags::UniqueMnemonic
;
953 pSWindow
->ImplControlFocus( nGetFocusFlags
);
960 if (isSuitableDestination(pButtonWindow
))
964 if ( mpWindowImpl
->mpDlgCtrlDownWindow
&& (mpWindowImpl
->mpDlgCtrlDownWindow
.get() != pButtonWindow
) )
966 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
967 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
970 static_cast<PushButton
*>(pButtonWindow
)->SetPressed( true );
971 mpWindowImpl
->mpDlgCtrlDownWindow
= pButtonWindow
;
973 else if ( mpWindowImpl
->mpDlgCtrlDownWindow
.get() == pButtonWindow
)
975 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
976 static_cast<PushButton
*>(pButtonWindow
)->SetPressed( false );
977 static_cast<PushButton
*>(pButtonWindow
)->Click();
986 // checks if this window has dialog control
987 bool Window::ImplHasDlgCtrl() const
989 vcl::Window
* pDlgCtrlParent
;
991 // lookup window for dialog control
992 pDlgCtrlParent
= ImplGetParent();
993 while ( pDlgCtrlParent
&&
994 !pDlgCtrlParent
->ImplIsOverlapWindow() &&
995 ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
996 pDlgCtrlParent
= pDlgCtrlParent
->ImplGetParent();
998 return pDlgCtrlParent
&& ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) == WB_DIALOGCONTROL
);
1001 void Window::ImplDlgCtrlNextWindow()
1003 vcl::Window
* pDlgCtrlParent
;
1004 vcl::Window
* pDlgCtrl
;
1005 vcl::Window
* pSWindow
;
1007 sal_uInt16 nFormStart
;
1008 sal_uInt16 nFormEnd
;
1010 // lookup window for dialog control
1012 pDlgCtrlParent
= ImplGetParent();
1013 while ( pDlgCtrlParent
&&
1014 !pDlgCtrlParent
->ImplIsOverlapWindow() &&
1015 ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
1016 pDlgCtrlParent
= pDlgCtrlParent
->ImplGetParent();
1018 if ( !pDlgCtrlParent
|| (GetStyle() & WB_NODIALOGCONTROL
) || ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
1021 // lookup window in child list
1022 pSWindow
= ::ImplFindDlgCtrlWindow( pDlgCtrlParent
, pDlgCtrl
,
1023 nIndex
, nFormStart
, nFormEnd
);
1027 vcl::Window
* pWindow
= pDlgCtrlParent
->ImplGetDlgWindow( nIndex
, GetDlgWindowType::Next
, nFormStart
, nFormEnd
);
1028 if ( pWindow
&& (pWindow
!= pSWindow
) )
1029 pWindow
->ImplControlFocus();
1032 static void ImplDlgCtrlUpdateDefButton( vcl::Window
* pParent
, vcl::Window
* pFocusWindow
,
1035 PushButton
* pOldDefButton
= nullptr;
1036 PushButton
* pNewDefButton
= nullptr;
1037 vcl::Window
* pSWindow
;
1039 sal_uInt16 nFormStart
;
1040 sal_uInt16 nFormEnd
;
1043 pSWindow
= ::ImplFindDlgCtrlWindow( pParent
, pFocusWindow
, i
, nFormStart
, nFormEnd
);
1050 pSWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, false );
1053 if ( pSWindow
->ImplIsPushButton() )
1055 PushButton
* pPushButton
= static_cast<PushButton
*>(pSWindow
);
1056 if ( pPushButton
->ImplIsDefButton() )
1057 pOldDefButton
= pPushButton
;
1058 if ( pPushButton
->HasChildPathFocus() )
1059 pNewDefButton
= pPushButton
;
1060 else if ( !pNewDefButton
&& (pPushButton
->GetStyle() & WB_DEFBUTTON
) )
1061 pNewDefButton
= pPushButton
;
1064 pSWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
1065 if ( !i
|| (i
> nFormEnd
) )
1072 vcl::Window
* pNewFocusWindow
= Application::GetFocusWindow();
1073 if ( !pNewFocusWindow
|| !pParent
->ImplIsWindowOrChild( pNewFocusWindow
) )
1074 pNewDefButton
= nullptr;
1075 else if ( !::ImplFindDlgCtrlWindow( pParent
, pNewFocusWindow
, i
, nDummy
, nDummy
) ||
1076 (i
< nFormStart
) || (i
> nFormEnd
) )
1077 pNewDefButton
= nullptr;
1080 if ( pOldDefButton
!= pNewDefButton
)
1082 if ( pOldDefButton
)
1083 pOldDefButton
->ImplSetDefButton( false );
1084 if ( pNewDefButton
)
1085 pNewDefButton
->ImplSetDefButton( true );
1089 void Window::ImplDlgCtrlFocusChanged( vcl::Window
* pWindow
, bool bGetFocus
)
1091 if ( mpWindowImpl
->mpDlgCtrlDownWindow
&& !bGetFocus
)
1093 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
1094 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
1097 ImplDlgCtrlUpdateDefButton( this, pWindow
, bGetFocus
);
1100 vcl::Window
* Window::ImplFindDlgCtrlWindow( vcl::Window
* pWindow
)
1103 sal_uInt16 nFormStart
;
1104 sal_uInt16 nFormEnd
;
1106 // find Focus-Window in the Child-List and return
1107 return ::ImplFindDlgCtrlWindow( this, pWindow
, nIndex
, nFormStart
, nFormEnd
);
1110 KeyEvent
Window::GetActivationKey() const
1114 sal_Unicode nAccel
= getAccel( GetText() );
1117 vcl::Window
* pWindow
= GetAccessibleRelationLabeledBy();
1119 nAccel
= getAccel( pWindow
->GetText() );
1123 sal_uInt16 nCode
= 0;
1124 if( nAccel
>= 'a' && nAccel
<= 'z' )
1125 nCode
= KEY_A
+ (nAccel
-'a');
1126 else if( nAccel
>= 'A' && nAccel
<= 'Z' )
1127 nCode
= KEY_A
+ (nAccel
-'A');
1128 else if( nAccel
>= '0' && nAccel
<= '9' )
1129 nCode
= KEY_0
+ (nAccel
-'0');
1130 else if( nAccel
== '.' )
1132 else if( nAccel
== '-' )
1133 nCode
= KEY_SUBTRACT
;
1134 vcl::KeyCode
aKeyCode( nCode
, false, false, true, false );
1135 aKeyEvent
= KeyEvent( nAccel
, aKeyCode
);
1140 } /* namespace vcl */
1142 sal_Unicode
getAccel( const OUString
& rStr
)
1144 sal_Unicode nChar
= 0;
1148 nPos
= rStr
.indexOf( '~', nPos
);
1149 if( nPos
!= -1 && nPos
< rStr
.getLength() )
1150 nChar
= rStr
[ ++nPos
];
1153 } while( nChar
== '~' );
1157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */