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 .
20 #include <tools/debug.hxx>
24 #include <dlgctrl.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/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/tabdlg.hxx>
32 #include <vcl/button.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/unohelp.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
* ImplGetSubChildWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
)
73 vcl::Window
* pTabPage
= nullptr;
74 vcl::Window
* pFoundWindow
= nullptr;
76 vcl::Window
* pWindow
= firstLogicalChildOfParent(pParent
);
77 vcl::Window
* pNextWindow
= pWindow
;
80 pWindow
= pWindow
->ImplGetWindow();
82 // skip invisible and disabled windows
83 if ( pTabPage
|| isVisibleInLayout(pWindow
) )
85 // if the last control was a TabControl, take its TabPage
88 pFoundWindow
= ImplGetSubChildWindow( pTabPage
, n
, nIndex
);
93 pFoundWindow
= pWindow
;
95 // for a TabControl, remember the current TabPage for later use
96 if ( pWindow
->GetType() == WINDOW_TABCONTROL
)
98 TabControl
* pTabControl
= static_cast<TabControl
*>(pWindow
);
99 // Check if the TabPage is a Child of the TabControl and still exists (by
100 // walking all child windows); because it could be that the TabPage has been
101 // destroyed already by a Dialog-Dtor, event that the TabControl still exists.
102 TabPage
* pTempTabPage
= pTabControl
->GetTabPage( pTabControl
->GetCurPageId() );
105 vcl::Window
* pTempWindow
= pTabControl
->GetWindow( GetWindowType::FirstChild
);
106 while ( pTempWindow
)
108 if ( pTempWindow
->ImplGetWindow() == pTempTabPage
)
110 pTabPage
= pTempTabPage
;
113 pTempWindow
= nextLogicalChildOfParent(pTabControl
, pTempWindow
);
117 else if ( ( pWindow
->GetStyle() & WB_DIALOGCONTROL
)
118 || ( pWindow
->GetStyle() & WB_CHILDDLGCTRL
) )
119 pFoundWindow
= ImplGetSubChildWindow( pWindow
, n
, nIndex
);
131 pWindow
= nextLogicalChildOfParent(pParent
, pNextWindow
);
132 pNextWindow
= pWindow
;
140 vcl::Window
* ImplGetChildWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
, bool bTestEnable
)
142 pParent
= ImplGetTopParentOfTabHierarchy( pParent
);
145 vcl::Window
* pWindow
= ImplGetSubChildWindow( pParent
, n
, nIndex
);
148 sal_uInt16 n2
= nIndex
;
149 while ( pWindow
&& (!isEnabledInLayout(pWindow
) || !pWindow
->IsInputEnabled()) )
153 pWindow
= ImplGetSubChildWindow( pParent
, n2
, nIndex
);
158 if ( (nIndex
< n2
) && n
)
164 pWindow
= ImplGetSubChildWindow( pParent
, n
, nIndex
);
166 while ( pWindow
&& n
&& (!isEnabledInLayout(pWindow
) || !pWindow
->IsInputEnabled()) );
172 static vcl::Window
* ImplGetNextWindow( vcl::Window
* pParent
, sal_uInt16 n
, sal_uInt16
& nIndex
, bool bTestEnable
)
174 vcl::Window
* pWindow
= ImplGetChildWindow( pParent
, n
+1, nIndex
, bTestEnable
);
178 pWindow
= ImplGetChildWindow( pParent
, n
, nIndex
, bTestEnable
);
185 vcl::Window
* Window::ImplGetDlgWindow( sal_uInt16 nIndex
, GetDlgWindowType nType
,
186 sal_uInt16 nFormStart
, sal_uInt16 nFormEnd
,
189 SAL_WARN_IF( (nIndex
< nFormStart
) || (nIndex
> nFormEnd
), "vcl",
190 "Window::ImplGetDlgWindow() - nIndex not in Form" );
192 vcl::Window
* pWindow
= nullptr;
195 sal_uInt16 nStartIndex
;
197 if ( nType
== GetDlgWindowType::Prev
)
202 if ( i
> nFormStart
)
206 pWindow
= ImplGetChildWindow( this, i
, nTemp
, true );
209 if ( (i
== nTemp
) && (pWindow
->GetStyle() & WB_TABSTOP
) )
212 while ( i
!= nIndex
);
217 pWindow
= ImplGetChildWindow( this, i
, i
, (nType
== GetDlgWindowType::First
) );
222 if ( nType
== GetDlgWindowType::Next
)
226 pWindow
= ImplGetNextWindow( this, i
, i
, true );
227 if ( (i
> nFormEnd
) || (i
< nFormStart
) )
228 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
231 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
234 if (i
<= nFormEnd
&& pWindow
)
236 // carry the 2nd index, in case all controls are disabled
237 sal_uInt16 nStartIndex2
= i
;
238 sal_uInt16 nOldIndex
= i
+1;
242 if ( pWindow
->GetStyle() & WB_TABSTOP
)
244 if( i
== nOldIndex
) // only disabled controls ?
250 if ( (i
> nFormEnd
) || (i
< nFormStart
) )
251 pWindow
= ImplGetChildWindow( this, nFormStart
, i
, true );
253 pWindow
= ImplGetNextWindow( this, i
, i
, true );
255 while (i
!= nStartIndex
&& i
!= nStartIndex2
&& pWindow
);
257 if ( (i
== nStartIndex2
) && pWindow
&&
258 (!(pWindow
->GetStyle() & WB_TABSTOP
) || !isEnabledInLayout(pWindow
)) )
263 if ( nType
== GetDlgWindowType::First
)
267 if ( pWindow
->GetType() == WINDOW_TABCONTROL
)
269 vcl::Window
* pNextWindow
= ImplGetDlgWindow( i
, GetDlgWindowType::Next
);
272 if ( pWindow
->IsChild( pNextWindow
) )
273 pWindow
= pNextWindow
;
277 if ( !(pWindow
->GetStyle() & WB_TABSTOP
) )
289 } /* namespace vcl */
291 vcl::Window
* ImplFindDlgCtrlWindow( vcl::Window
* pParent
, vcl::Window
* pWindow
, sal_uInt16
& rIndex
,
292 sal_uInt16
& rFormStart
, sal_uInt16
& rFormEnd
)
294 vcl::Window
* pSWindow
;
295 vcl::Window
* pSecondWindow
= nullptr;
296 vcl::Window
* pTempWindow
= nullptr;
298 sal_uInt16 nSecond_i
= 0;
299 sal_uInt16 nFormStart
= 0;
300 sal_uInt16 nSecondFormStart
= 0;
303 // find focus window in the child list
304 vcl::Window
* pFirstChildWindow
= pSWindow
= ImplGetChildWindow( pParent
, 0, i
, false );
306 if( pWindow
== nullptr )
311 // the DialogControlStart mark is only accepted for the direct children
312 if ( !ImplHasIndirectTabParent( pSWindow
)
313 && pSWindow
->ImplGetWindow()->IsDialogControlStart() )
316 // SecondWindow for composite controls like ComboBoxes and arrays
317 if ( pSWindow
->ImplIsWindowOrChild( pWindow
) )
319 pSecondWindow
= pSWindow
;
321 nSecondFormStart
= nFormStart
;
322 if ( pSWindow
== pWindow
)
326 pSWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
333 // Window not found; we cannot handle it
334 if ( !pSecondWindow
)
338 pSWindow
= pSecondWindow
;
340 nFormStart
= nSecondFormStart
;
346 rFormStart
= nFormStart
;
348 // find end of template
349 sal_Int32 nIteration
= 0;
353 pTempWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
355 // the DialogControlStart mark is only accepted for the direct children
357 || ( pTempWindow
&& !ImplHasIndirectTabParent( pTempWindow
)
358 && pTempWindow
->ImplGetWindow()->IsDialogControlStart() ) )
361 if ( pTempWindow
&& pTempWindow
== pFirstChildWindow
)
363 // It is possible to go through the begin of hierarchy once
364 // while looking for DialogControlStart mark.
365 // If it happens second time, it looks like an endless loop,
366 // that should be impossible, but just for the case...
368 if ( nIteration
>= 2 )
370 // this is an unexpected scenario
371 SAL_WARN( "vcl", "It seems to be an endless loop!" );
377 while ( pTempWindow
);
383 vcl::Window
* ImplFindAccelWindow( vcl::Window
* pParent
, sal_uInt16
& rIndex
, sal_Unicode cCharCode
,
384 sal_uInt16 nFormStart
, sal_uInt16 nFormEnd
, bool bCheckEnable
)
386 SAL_WARN_IF( (rIndex
< nFormStart
) || (rIndex
> nFormEnd
), "vcl",
387 "Window::ImplFindAccelWindow() - rIndex not in Form" );
389 sal_Unicode cCompareChar
;
390 sal_uInt16 nStart
= rIndex
;
391 sal_uInt16 i
= rIndex
;
392 vcl::Window
* pWindow
;
394 // MT: Where can we keep the CharClass?!
395 static uno::Reference
< i18n::XCharacterClassification
> xCharClass
;
396 if ( !xCharClass
.is() )
397 xCharClass
= vcl::unohelper::CreateCharacterClassification();
399 const css::lang::Locale
& rLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
400 cCharCode
= xCharClass
->toUpper( OUString(cCharCode
), 0, 1, rLocale
)[0];
403 pWindow
= ImplGetNextWindow( pParent
, i
, i
, true );
405 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, true );
408 const OUString aStr
= pWindow
->GetText();
409 sal_Int32 nPos
= aStr
.indexOf( '~' );
412 cCompareChar
= aStr
[nPos
+1];
413 cCompareChar
= xCharClass
->toUpper( OUString(cCompareChar
), 0, 1, rLocale
)[0];
414 if ( cCompareChar
== cCharCode
)
416 if (pWindow
->GetType() == WINDOW_FIXEDTEXT
)
418 FixedText
*pFixedText
= static_cast<FixedText
*>(pWindow
);
419 vcl::Window
*pMnemonicWidget
= pFixedText
->get_mnemonic_widget();
420 SAL_WARN_IF(isContainerWindow(pFixedText
->GetParent()) && !pMnemonicWidget
,
421 "vcl.a11y", "label missing mnemonic_widget?");
423 return pMnemonicWidget
;
426 // skip Static-Controls
427 if ( (pWindow
->GetType() == WINDOW_FIXEDTEXT
) ||
428 (pWindow
->GetType() == WINDOW_FIXEDLINE
) ||
429 (pWindow
->GetType() == WINDOW_GROUPBOX
) )
430 pWindow
= pParent
->ImplGetDlgWindow( i
, GetDlgWindowType::Next
);
434 nPos
= aStr
.indexOf( '~', nPos
+1 );
437 // #i93011# it would have made sense to have this really recursive
438 // right from the start. However this would cause unpredictable side effects now
439 // so instead we have a style bit for some child windows, that want their
440 // children checked for accelerators
441 if( (pWindow
->GetStyle() & WB_CHILDDLGCTRL
) != 0 )
443 sal_uInt16 nChildIndex
;
444 sal_uInt16 nChildFormStart
;
445 sal_uInt16 nChildFormEnd
;
447 // get form start and end
448 ::ImplFindDlgCtrlWindow( pWindow
, nullptr,
449 nChildIndex
, nChildFormStart
, nChildFormEnd
);
450 vcl::Window
* pAccelWin
= ImplFindAccelWindow( pWindow
, nChildIndex
, cCharCode
,
451 nChildFormStart
, nChildFormEnd
,
462 pWindow
= ImplGetNextWindow( pParent
, i
, i
, bCheckEnable
);
464 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, bCheckEnable
);
467 pWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, bCheckEnable
);
475 void Window::ImplControlFocus( GetFocusFlags nFlags
)
477 if ( nFlags
& GetFocusFlags::Mnemonic
)
479 if ( GetType() == WINDOW_RADIOBUTTON
)
481 if ( !static_cast<RadioButton
*>(this)->IsChecked() )
482 static_cast<RadioButton
*>(this)->ImplCallClick( true, nFlags
);
484 ImplGrabFocus( nFlags
);
488 ImplGrabFocus( nFlags
);
489 if ( nFlags
& GetFocusFlags::UniqueMnemonic
)
491 if ( GetType() == WINDOW_CHECKBOX
)
492 static_cast<CheckBox
*>(this)->ImplCheck();
493 else if ( mpWindowImpl
->mbPushButton
)
495 static_cast<PushButton
*>(this)->SetPressed( true );
496 static_cast<PushButton
*>(this)->SetPressed( false );
497 static_cast<PushButton
*>(this)->Click();
504 if ( GetType() == WINDOW_RADIOBUTTON
)
506 if ( !static_cast<RadioButton
*>(this)->IsChecked() )
507 static_cast<RadioButton
*>(this)->ImplCallClick( true, nFlags
);
509 ImplGrabFocus( nFlags
);
512 ImplGrabFocus( nFlags
);
516 } /* namespace vcl */
520 bool isSuitableDestination(vcl::Window
*pWindow
)
522 return (pWindow
&& isVisibleInLayout(pWindow
) &&
523 isEnabledInLayout(pWindow
) && pWindow
->IsInputEnabled() &&
524 //Pure window shouldn't get window after controls such as
526 (pWindow
->GetType() != WINDOW_WINDOW
&& pWindow
->GetType() != WINDOW_SYSWINDOW
&&
527 pWindow
->GetType() != WINDOW_WORKWINDOW
&& pWindow
->GetType() != WINDOW_CONTROL
)
531 bool focusNextInGroup(const std::vector
<VclPtr
<RadioButton
> >::iterator
& aStart
, std::vector
<VclPtr
<RadioButton
> > &rGroup
)
533 std::vector
<VclPtr
<RadioButton
> >::iterator
aI(aStart
);
535 if (aStart
!= rGroup
.end())
538 for (; aI
!= rGroup
.end(); ++aI
)
540 vcl::Window
*pWindow
= *aI
;
542 if (isSuitableDestination(pWindow
))
544 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Forward
);
549 for (aI
= rGroup
.begin(); aI
!= aStart
; ++aI
)
551 vcl::Window
*pWindow
= *aI
;
553 if (isSuitableDestination(pWindow
))
555 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Forward
);
563 bool nextInGroup(RadioButton
*pSourceWindow
, bool bBackward
)
565 std::vector
<VclPtr
<RadioButton
> > aGroup(pSourceWindow
->GetRadioButtonGroup());
567 if (aGroup
.size() == 1) //only one button in group
571 std::reverse(aGroup
.begin(), aGroup
.end());
573 auto aStart(std::find(aGroup
.begin(), aGroup
.end(), VclPtr
<RadioButton
>(pSourceWindow
)));
575 assert(aStart
!= aGroup
.end());
577 return focusNextInGroup(aStart
, aGroup
);
583 bool Window::ImplDlgCtrl( const KeyEvent
& rKEvt
, bool bKeyInput
)
585 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
586 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
587 vcl::Window
* pSWindow
;
588 vcl::Window
* pTempWindow
;
589 vcl::Window
* pButtonWindow
;
592 sal_uInt16 iButtonStart
;
595 sal_uInt16 nFormStart
;
597 DialogControlFlags nDlgCtrlFlags
;
599 // we cannot take over control without Focus-window
600 vcl::Window
* pFocusWindow
= Application::GetFocusWindow();
601 if ( !pFocusWindow
|| !ImplIsWindowOrChild( pFocusWindow
) )
604 // find Focus-Window in the child list
605 pSWindow
= ::ImplFindDlgCtrlWindow( this, pFocusWindow
,
606 nIndex
, nFormStart
, nFormEnd
);
611 nDlgCtrlFlags
= DialogControlFlags::NONE
;
612 pTempWindow
= pSWindow
;
615 nDlgCtrlFlags
|= pTempWindow
->GetDialogControlFlags();
616 if ( pTempWindow
== this )
618 pTempWindow
= pTempWindow
->ImplGetParent();
620 while ( pTempWindow
);
622 pButtonWindow
= nullptr;
624 if ( nKeyCode
== KEY_RETURN
)
626 // search first for a DefPushButton/CancelButton
627 pButtonWindow
= ImplGetChildWindow( this, nFormStart
, iButton
, true );
628 iButtonStart
= iButton
;
629 while ( pButtonWindow
)
631 if ( (pButtonWindow
->GetStyle() & WB_DEFBUTTON
) &&
632 pButtonWindow
->mpWindowImpl
->mbPushButton
)
635 pButtonWindow
= ImplGetNextWindow( this, iButton
, iButton
, true );
636 if ( (iButton
<= iButtonStart
) || (iButton
> nFormEnd
) )
637 pButtonWindow
= nullptr;
640 if ( bKeyInput
&& !pButtonWindow
&& (nDlgCtrlFlags
& DialogControlFlags::Return
) )
642 GetDlgWindowType nType
;
643 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Tab
;
644 sal_uInt16 nNewIndex
;
646 if ( aKeyCode
.IsShift() )
648 nType
= GetDlgWindowType::Prev
;
649 nGetFocusFlags
|= GetFocusFlags::Backward
;
653 nType
= GetDlgWindowType::Next
;
654 nGetFocusFlags
|= GetFocusFlags::Forward
;
657 pTempWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
658 while ( pTempWindow
&& (pTempWindow
!= pSWindow
) )
660 if ( !pTempWindow
->mpWindowImpl
->mbPushButton
)
663 if ( nType
== GetDlgWindowType::Prev
)
665 if ( nNewIndex
> iStart
)
666 nGetFocusFlags
|= GetFocusFlags::Around
;
670 if ( nNewIndex
< iStart
)
671 nGetFocusFlags
|= GetFocusFlags::Around
;
673 pTempWindow
->ImplControlFocus( nGetFocusFlags
);
679 pTempWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
681 if ( (i
<= iStart
) || (i
> nFormEnd
) )
682 pTempWindow
= nullptr;
684 // if this is the same window, simulate a Get/LoseFocus,
685 // in case AROUND is being processed
686 if ( pTempWindow
&& (pTempWindow
== pSWindow
) )
688 NotifyEvent
aNEvt1( MouseNotifyEvent::LOSEFOCUS
, pSWindow
);
689 if ( !ImplCallPreNotify( aNEvt1
) )
690 pSWindow
->CompatLoseFocus();
691 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= nGetFocusFlags
| GetFocusFlags::Around
;
692 NotifyEvent
aNEvt2( MouseNotifyEvent::GETFOCUS
, pSWindow
);
693 if ( !ImplCallPreNotify( aNEvt2
) )
694 pSWindow
->CompatGetFocus();
695 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= GetFocusFlags::NONE
;
700 else if ( nKeyCode
== KEY_ESCAPE
)
702 // search first for a DefPushButton/CancelButton
703 pButtonWindow
= ImplGetChildWindow( this, nFormStart
, iButton
, true );
704 iButtonStart
= iButton
;
705 while ( pButtonWindow
)
707 if ( pButtonWindow
->GetType() == WINDOW_CANCELBUTTON
)
710 pButtonWindow
= ImplGetNextWindow( this, iButton
, iButton
, true );
711 if ( (iButton
<= iButtonStart
) || (iButton
> nFormEnd
) )
712 pButtonWindow
= nullptr;
715 if ( bKeyInput
&& mpWindowImpl
->mpDlgCtrlDownWindow
)
717 if ( mpWindowImpl
->mpDlgCtrlDownWindow
.get() != pButtonWindow
)
719 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
720 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
725 else if ( bKeyInput
)
727 if ( nKeyCode
== KEY_TAB
)
729 // do not skip Alt key, for MS Windows
730 if ( !aKeyCode
.IsMod2() )
732 GetDlgWindowType nType
;
733 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Tab
;
734 sal_uInt16 nNewIndex
;
735 bool bFormular
= false;
737 // for Ctrl-Tab check if we want to jump to next template
738 if ( aKeyCode
.IsMod1() )
741 vcl::Window
* pFormularFirstWindow
= nullptr;
742 vcl::Window
* pLastFormularFirstWindow
= nullptr;
743 pTempWindow
= ImplGetChildWindow( this, 0, iTemp
, false );
744 vcl::Window
* pPrevFirstFormularFirstWindow
= nullptr;
745 vcl::Window
* pFirstFormularFirstWindow
= pTempWindow
;
746 while ( pTempWindow
)
748 if ( pTempWindow
->ImplGetWindow()->IsDialogControlStart() )
752 if ( aKeyCode
.IsShift() )
754 if ( iTemp
<= nIndex
)
755 pFormularFirstWindow
= pPrevFirstFormularFirstWindow
;
756 pPrevFirstFormularFirstWindow
= pTempWindow
;
760 if ( (iTemp
> nIndex
) && !pFormularFirstWindow
)
761 pFormularFirstWindow
= pTempWindow
;
763 pLastFormularFirstWindow
= pTempWindow
;
766 pTempWindow
= ImplGetNextWindow( this, iTemp
, iTemp
, false );
768 pTempWindow
= nullptr;
773 if ( !pFormularFirstWindow
)
775 if ( aKeyCode
.IsShift() )
776 pFormularFirstWindow
= pLastFormularFirstWindow
;
778 pFormularFirstWindow
= pFirstFormularFirstWindow
;
781 sal_uInt16 nFoundFormStart
= 0;
782 sal_uInt16 nFoundFormEnd
= 0;
783 sal_uInt16 nTempIndex
= 0;
784 if ( ::ImplFindDlgCtrlWindow( this, pFormularFirstWindow
, nTempIndex
,
785 nFoundFormStart
, nFoundFormEnd
) )
787 nTempIndex
= nFoundFormStart
;
788 pFormularFirstWindow
= ImplGetDlgWindow( nTempIndex
, GetDlgWindowType::First
, nFoundFormStart
, nFoundFormEnd
);
789 if ( pFormularFirstWindow
)
791 pFormularFirstWindow
->ImplControlFocus();
800 // Only use Ctrl-TAB if it was allowed for the whole
801 // dialog or for the current control (#103667#)
802 if (!aKeyCode
.IsMod1() || (pSWindow
->GetStyle() & WB_NODIALOGCONTROL
))
804 if ( aKeyCode
.IsShift() )
806 nType
= GetDlgWindowType::Prev
;
807 nGetFocusFlags
|= GetFocusFlags::Backward
;
811 nType
= GetDlgWindowType::Next
;
812 nGetFocusFlags
|= GetFocusFlags::Forward
;
814 vcl::Window
* pWindow
= ImplGetDlgWindow( i
, nType
, nFormStart
, nFormEnd
, &nNewIndex
);
815 // if this is the same window, simulate a Get/LoseFocus,
816 // in case AROUND is being processed
817 if ( pWindow
== pSWindow
)
819 NotifyEvent
aNEvt1( MouseNotifyEvent::LOSEFOCUS
, pSWindow
);
820 if ( !ImplCallPreNotify( aNEvt1
) )
821 pSWindow
->CompatLoseFocus();
822 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= nGetFocusFlags
| GetFocusFlags::Around
;
823 NotifyEvent
aNEvt2( MouseNotifyEvent::GETFOCUS
, pSWindow
);
824 if ( !ImplCallPreNotify( aNEvt2
) )
825 pSWindow
->CompatGetFocus();
826 pSWindow
->mpWindowImpl
->mnGetFocusFlags
= GetFocusFlags::NONE
;
832 if ( nType
== GetDlgWindowType::Prev
)
835 nGetFocusFlags
|= GetFocusFlags::Around
;
840 nGetFocusFlags
|= GetFocusFlags::Around
;
842 pWindow
->ImplControlFocus( nGetFocusFlags
);
849 else if ( (nKeyCode
== KEY_LEFT
) || (nKeyCode
== KEY_UP
) )
851 if (pSWindow
->GetType() == WINDOW_RADIOBUTTON
)
852 return nextInGroup(static_cast<RadioButton
*>(pSWindow
), true);
855 WinBits nStyle
= pSWindow
->GetStyle();
856 if ( !(nStyle
& WB_GROUP
) )
858 vcl::Window
* pWindow
= prevLogicalChildOfParent(this, pSWindow
);
861 pWindow
= pWindow
->ImplGetWindow();
863 nStyle
= pWindow
->GetStyle();
865 if (isSuitableDestination(pWindow
))
867 if ( pWindow
!= pSWindow
)
868 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Backward
);
872 if ( nStyle
& WB_GROUP
)
875 pWindow
= prevLogicalChildOfParent(this, pWindow
);
880 else if ( (nKeyCode
== KEY_RIGHT
) || (nKeyCode
== KEY_DOWN
) )
882 if (pSWindow
->GetType() == WINDOW_RADIOBUTTON
)
883 return nextInGroup(static_cast<RadioButton
*>(pSWindow
), false);
886 vcl::Window
* pWindow
= nextLogicalChildOfParent(this, pSWindow
);
889 pWindow
= pWindow
->ImplGetWindow();
891 WinBits nStyle
= pWindow
->GetStyle();
893 if ( nStyle
& WB_GROUP
)
896 if (isSuitableDestination(pWindow
))
898 pWindow
->ImplControlFocus( GetFocusFlags::CURSOR
| GetFocusFlags::Backward
);
902 pWindow
= nextLogicalChildOfParent(this, pWindow
);
908 sal_Unicode c
= rKEvt
.GetCharCode();
911 pSWindow
= ::ImplFindAccelWindow( this, i
, c
, nFormStart
, nFormEnd
);
914 GetFocusFlags nGetFocusFlags
= GetFocusFlags::Mnemonic
;
915 if ( pSWindow
== ::ImplFindAccelWindow( this, i
, c
, nFormStart
, nFormEnd
) )
916 nGetFocusFlags
|= GetFocusFlags::UniqueMnemonic
;
917 pSWindow
->ImplControlFocus( nGetFocusFlags
);
924 if (isSuitableDestination(pButtonWindow
))
928 if ( mpWindowImpl
->mpDlgCtrlDownWindow
&& (mpWindowImpl
->mpDlgCtrlDownWindow
.get() != pButtonWindow
) )
930 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
931 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
934 static_cast<PushButton
*>(pButtonWindow
)->SetPressed( true );
935 mpWindowImpl
->mpDlgCtrlDownWindow
= pButtonWindow
;
937 else if ( mpWindowImpl
->mpDlgCtrlDownWindow
.get() == pButtonWindow
)
939 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
940 static_cast<PushButton
*>(pButtonWindow
)->SetPressed( false );
941 static_cast<PushButton
*>(pButtonWindow
)->Click();
950 // checks if this window has dialog control
951 bool Window::ImplHasDlgCtrl()
953 vcl::Window
* pDlgCtrlParent
;
955 // lookup window for dialog control
956 pDlgCtrlParent
= ImplGetParent();
957 while ( pDlgCtrlParent
&&
958 !pDlgCtrlParent
->ImplIsOverlapWindow() &&
959 ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
960 pDlgCtrlParent
= pDlgCtrlParent
->ImplGetParent();
962 if ( !pDlgCtrlParent
|| ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
968 void Window::ImplDlgCtrlNextWindow()
970 vcl::Window
* pDlgCtrlParent
;
971 vcl::Window
* pDlgCtrl
;
972 vcl::Window
* pSWindow
;
974 sal_uInt16 nFormStart
;
977 // lookup window for dialog control
979 pDlgCtrlParent
= ImplGetParent();
980 while ( pDlgCtrlParent
&&
981 !pDlgCtrlParent
->ImplIsOverlapWindow() &&
982 ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
983 pDlgCtrlParent
= pDlgCtrlParent
->ImplGetParent();
985 if ( !pDlgCtrlParent
|| (GetStyle() & WB_NODIALOGCONTROL
) || ((pDlgCtrlParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) != WB_DIALOGCONTROL
) )
988 // lookup window in child list
989 pSWindow
= ::ImplFindDlgCtrlWindow( pDlgCtrlParent
, pDlgCtrl
,
990 nIndex
, nFormStart
, nFormEnd
);
994 vcl::Window
* pWindow
= pDlgCtrlParent
->ImplGetDlgWindow( nIndex
, GetDlgWindowType::Next
, nFormStart
, nFormEnd
);
995 if ( pWindow
&& (pWindow
!= pSWindow
) )
996 pWindow
->ImplControlFocus();
999 static void ImplDlgCtrlUpdateDefButton( vcl::Window
* pParent
, vcl::Window
* pFocusWindow
,
1002 PushButton
* pOldDefButton
= nullptr;
1003 PushButton
* pNewDefButton
= nullptr;
1004 vcl::Window
* pSWindow
;
1006 sal_uInt16 nFormStart
;
1007 sal_uInt16 nFormEnd
;
1010 pSWindow
= ::ImplFindDlgCtrlWindow( pParent
, pFocusWindow
, i
, nFormStart
, nFormEnd
);
1017 pSWindow
= ImplGetChildWindow( pParent
, nFormStart
, i
, false );
1020 if ( pSWindow
->ImplIsPushButton() )
1022 PushButton
* pPushButton
= static_cast<PushButton
*>(pSWindow
);
1023 if ( pPushButton
->ImplIsDefButton() )
1024 pOldDefButton
= pPushButton
;
1025 if ( pPushButton
->HasChildPathFocus() )
1026 pNewDefButton
= pPushButton
;
1027 else if ( !pNewDefButton
&& (pPushButton
->GetStyle() & WB_DEFBUTTON
) )
1028 pNewDefButton
= pPushButton
;
1031 pSWindow
= ImplGetNextWindow( pParent
, i
, i
, false );
1032 if ( !i
|| (i
> nFormEnd
) )
1039 vcl::Window
* pNewFocusWindow
= Application::GetFocusWindow();
1040 if ( !pNewFocusWindow
|| !pParent
->ImplIsWindowOrChild( pNewFocusWindow
) )
1041 pNewDefButton
= nullptr;
1042 else if ( !::ImplFindDlgCtrlWindow( pParent
, pNewFocusWindow
, i
, nDummy
, nDummy
) ||
1043 (i
< nFormStart
) || (i
> nFormEnd
) )
1044 pNewDefButton
= nullptr;
1047 if ( pOldDefButton
!= pNewDefButton
)
1049 if ( pOldDefButton
)
1050 pOldDefButton
->ImplSetDefButton( false );
1051 if ( pNewDefButton
)
1052 pNewDefButton
->ImplSetDefButton( true );
1056 void Window::ImplDlgCtrlFocusChanged( vcl::Window
* pWindow
, bool bGetFocus
)
1058 if ( mpWindowImpl
->mpDlgCtrlDownWindow
&& !bGetFocus
)
1060 static_cast<PushButton
*>(mpWindowImpl
->mpDlgCtrlDownWindow
.get())->SetPressed( false );
1061 mpWindowImpl
->mpDlgCtrlDownWindow
= nullptr;
1064 ImplDlgCtrlUpdateDefButton( this, pWindow
, bGetFocus
);
1067 vcl::Window
* Window::ImplFindDlgCtrlWindow( vcl::Window
* pWindow
)
1070 sal_uInt16 nFormStart
;
1071 sal_uInt16 nFormEnd
;
1073 // find Focus-Window in the Child-List and return
1074 return ::ImplFindDlgCtrlWindow( this, pWindow
, nIndex
, nFormStart
, nFormEnd
);
1077 vcl::Window
* Window::GetParentLabelFor( const vcl::Window
* ) const
1082 vcl::Window
* Window::GetParentLabeledBy( const vcl::Window
* ) const
1087 KeyEvent
Window::GetActivationKey() const
1091 sal_Unicode nAccel
= getAccel( GetText() );
1094 vcl::Window
* pWindow
= GetAccessibleRelationLabeledBy();
1096 nAccel
= getAccel( pWindow
->GetText() );
1100 sal_uInt16 nCode
= 0;
1101 if( nAccel
>= 'a' && nAccel
<= 'z' )
1102 nCode
= KEY_A
+ (nAccel
-'a');
1103 else if( nAccel
>= 'A' && nAccel
<= 'Z' )
1104 nCode
= KEY_A
+ (nAccel
-'A');
1105 else if( nAccel
>= '0' && nAccel
<= '9' )
1106 nCode
= KEY_0
+ (nAccel
-'0');
1107 else if( nAccel
== '.' )
1109 else if( nAccel
== '-' )
1110 nCode
= KEY_SUBTRACT
;
1111 vcl::KeyCode
aKeyCode( nCode
, false, false, true, false );
1112 aKeyEvent
= KeyEvent( nAccel
, aKeyCode
);
1117 } /* namespace vcl */
1119 sal_Unicode
getAccel( const OUString
& rStr
)
1121 sal_Unicode nChar
= 0;
1125 nPos
= rStr
.indexOf( '~', nPos
);
1126 if( nPos
!= -1 && nPos
< rStr
.getLength() )
1127 nChar
= rStr
[ ++nPos
];
1130 } while( nChar
== '~' );
1134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */