build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / dlgctrl.cxx
blob3cb40abf84dbb8d17c3f96ef292204d43ff29dbf
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 .
20 #include <tools/debug.hxx>
22 #include <svdata.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;
58 if ( pResult )
60 vcl::Window* pNonLayoutParent = getNonLayoutParent(pResult);
61 while ( pNonLayoutParent && ( pResult->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) )
63 pResult = pNonLayoutParent;
64 pNonLayoutParent = getNonLayoutParent(pResult);
68 return 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;
78 while ( 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
86 if ( pTabPage )
88 pFoundWindow = ImplGetSubChildWindow( pTabPage, n, nIndex );
89 pTabPage = nullptr;
91 else
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() );
103 if ( pTempTabPage )
105 vcl::Window* pTempWindow = pTabControl->GetWindow( GetWindowType::FirstChild );
106 while ( pTempWindow )
108 if ( pTempWindow->ImplGetWindow() == pTempTabPage )
110 pTabPage = pTempTabPage;
111 break;
113 pTempWindow = nextLogicalChildOfParent(pTabControl, pTempWindow);
117 else if ( ( pWindow->GetStyle() & WB_DIALOGCONTROL )
118 || ( pWindow->GetStyle() & WB_CHILDDLGCTRL ) )
119 pFoundWindow = ImplGetSubChildWindow( pWindow, n, nIndex );
122 if ( n == nIndex )
123 return pFoundWindow;
124 nIndex++;
127 if ( pTabPage )
128 pWindow = pTabPage;
129 else
131 pWindow = nextLogicalChildOfParent(pParent, pNextWindow);
132 pNextWindow = pWindow;
136 nIndex--;
137 return pFoundWindow;
140 vcl::Window* ImplGetChildWindow( vcl::Window* pParent, sal_uInt16 n, sal_uInt16& nIndex, bool bTestEnable )
142 pParent = ImplGetTopParentOfTabHierarchy( pParent );
144 nIndex = 0;
145 vcl::Window* pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
146 if ( bTestEnable )
148 sal_uInt16 n2 = nIndex;
149 while ( pWindow && (!isEnabledInLayout(pWindow) || !pWindow->IsInputEnabled()) )
151 n2 = nIndex+1;
152 nIndex = 0;
153 pWindow = ImplGetSubChildWindow( pParent, n2, nIndex );
154 if ( nIndex < n2 )
155 break;
158 if ( (nIndex < n2) && n )
162 n--;
163 nIndex = 0;
164 pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
166 while ( pWindow && n && (!isEnabledInLayout(pWindow) || !pWindow->IsInputEnabled()) );
169 return pWindow;
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 );
175 if ( n == nIndex )
177 n = 0;
178 pWindow = ImplGetChildWindow( pParent, n, nIndex, bTestEnable );
180 return pWindow;
183 namespace vcl {
185 vcl::Window* Window::ImplGetDlgWindow( sal_uInt16 nIndex, GetDlgWindowType nType,
186 sal_uInt16 nFormStart, sal_uInt16 nFormEnd,
187 sal_uInt16* pIndex )
189 SAL_WARN_IF( (nIndex < nFormStart) || (nIndex > nFormEnd), "vcl",
190 "Window::ImplGetDlgWindow() - nIndex not in Form" );
192 vcl::Window* pWindow = nullptr;
193 sal_uInt16 i;
194 sal_uInt16 nTemp;
195 sal_uInt16 nStartIndex;
197 if ( nType == GetDlgWindowType::Prev )
199 i = nIndex;
202 if ( i > nFormStart )
203 i--;
204 else
205 i = nFormEnd;
206 pWindow = ImplGetChildWindow( this, i, nTemp, true );
207 if ( !pWindow )
208 break;
209 if ( (i == nTemp) && (pWindow->GetStyle() & WB_TABSTOP) )
210 break;
212 while ( i != nIndex );
214 else
216 i = nIndex;
217 pWindow = ImplGetChildWindow( this, i, i, (nType == GetDlgWindowType::First) );
218 if ( pWindow )
220 nStartIndex = i;
222 if ( nType == GetDlgWindowType::Next )
224 if ( i < nFormEnd )
226 pWindow = ImplGetNextWindow( this, i, i, true );
227 if ( (i > nFormEnd) || (i < nFormStart) )
228 pWindow = ImplGetChildWindow( this, nFormStart, i, true );
230 else
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 )
243 break;
244 if( i == nOldIndex ) // only disabled controls ?
246 i = nStartIndex2;
247 break;
249 nOldIndex = i;
250 if ( (i > nFormEnd) || (i < nFormStart) )
251 pWindow = ImplGetChildWindow( this, nFormStart, i, true );
252 else
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)) )
259 i = nStartIndex;
263 if ( nType == GetDlgWindowType::First )
265 if ( pWindow )
267 if ( pWindow->GetType() == WINDOW_TABCONTROL )
269 vcl::Window* pNextWindow = ImplGetDlgWindow( i, GetDlgWindowType::Next );
270 if ( pNextWindow )
272 if ( pWindow->IsChild( pNextWindow ) )
273 pWindow = pNextWindow;
277 if ( !(pWindow->GetStyle() & WB_TABSTOP) )
278 pWindow = nullptr;
283 if ( pIndex )
284 *pIndex = i;
286 return pWindow;
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;
297 sal_uInt16 i;
298 sal_uInt16 nSecond_i = 0;
299 sal_uInt16 nFormStart = 0;
300 sal_uInt16 nSecondFormStart = 0;
301 sal_uInt16 nFormEnd;
303 // find focus window in the child list
304 vcl::Window* pFirstChildWindow = pSWindow = ImplGetChildWindow( pParent, 0, i, false );
306 if( pWindow == nullptr )
307 pWindow = pSWindow;
309 while ( pSWindow )
311 // the DialogControlStart mark is only accepted for the direct children
312 if ( !ImplHasIndirectTabParent( pSWindow )
313 && pSWindow->ImplGetWindow()->IsDialogControlStart() )
314 nFormStart = i;
316 // SecondWindow for composite controls like ComboBoxes and arrays
317 if ( pSWindow->ImplIsWindowOrChild( pWindow ) )
319 pSecondWindow = pSWindow;
320 nSecond_i = i;
321 nSecondFormStart = nFormStart;
322 if ( pSWindow == pWindow )
323 break;
326 pSWindow = ImplGetNextWindow( pParent, i, i, false );
327 if ( !i )
328 pSWindow = nullptr;
331 if ( !pSWindow )
333 // Window not found; we cannot handle it
334 if ( !pSecondWindow )
335 return nullptr;
336 else
338 pSWindow = pSecondWindow;
339 i = nSecond_i;
340 nFormStart = nSecondFormStart;
344 // initialize
345 rIndex = i;
346 rFormStart = nFormStart;
348 // find end of template
349 sal_Int32 nIteration = 0;
352 nFormEnd = i;
353 pTempWindow = ImplGetNextWindow( pParent, i, i, false );
355 // the DialogControlStart mark is only accepted for the direct children
356 if ( !i
357 || ( pTempWindow && !ImplHasIndirectTabParent( pTempWindow )
358 && pTempWindow->ImplGetWindow()->IsDialogControlStart() ) )
359 break;
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...
367 nIteration++;
368 if ( nIteration >= 2 )
370 // this is an unexpected scenario
371 SAL_WARN( "vcl", "It seems to be an endless loop!" );
372 rFormStart = 0;
373 break;
377 while ( pTempWindow );
378 rFormEnd = nFormEnd;
380 return pSWindow;
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];
402 if ( i < nFormEnd )
403 pWindow = ImplGetNextWindow( pParent, i, i, true );
404 else
405 pWindow = ImplGetChildWindow( pParent, nFormStart, i, true );
406 while( pWindow )
408 const OUString aStr = pWindow->GetText();
409 sal_Int32 nPos = aStr.indexOf( '~' );
410 while (nPos != -1)
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?");
422 if (pMnemonicWidget)
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 );
431 rIndex = i;
432 return pWindow;
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,
452 bCheckEnable );
453 if( pAccelWin )
454 return pAccelWin;
457 if ( i == nStart )
458 break;
460 if ( i < nFormEnd )
462 pWindow = ImplGetNextWindow( pParent, i, i, bCheckEnable );
463 if( ! pWindow )
464 pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
466 else
467 pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
470 return nullptr;
473 namespace vcl {
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 );
483 else
484 ImplGrabFocus( nFlags );
486 else
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();
502 else
504 if ( GetType() == WINDOW_RADIOBUTTON )
506 if ( !static_cast<RadioButton*>(this)->IsChecked() )
507 static_cast<RadioButton*>(this)->ImplCallClick( true, nFlags );
508 else
509 ImplGrabFocus( nFlags );
511 else
512 ImplGrabFocus( nFlags );
516 } /* namespace vcl */
518 namespace
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
525 //buttons.
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())
536 ++aI;
538 for (; aI != rGroup.end(); ++aI)
540 vcl::Window *pWindow = *aI;
542 if (isSuitableDestination(pWindow))
544 pWindow->ImplControlFocus( GetFocusFlags::CURSOR | GetFocusFlags::Forward );
545 return true;
549 for (aI = rGroup.begin(); aI != aStart; ++aI)
551 vcl::Window *pWindow = *aI;
553 if (isSuitableDestination(pWindow))
555 pWindow->ImplControlFocus( GetFocusFlags::CURSOR | GetFocusFlags::Forward );
556 return true;
560 return false;
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
568 return false;
570 if (bBackward)
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);
581 namespace vcl {
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;
590 sal_uInt16 i;
591 sal_uInt16 iButton;
592 sal_uInt16 iButtonStart;
593 sal_uInt16 iTemp;
594 sal_uInt16 nIndex;
595 sal_uInt16 nFormStart;
596 sal_uInt16 nFormEnd;
597 DialogControlFlags nDlgCtrlFlags;
599 // we cannot take over control without Focus-window
600 vcl::Window* pFocusWindow = Application::GetFocusWindow();
601 if ( !pFocusWindow || !ImplIsWindowOrChild( pFocusWindow ) )
602 return false;
604 // find Focus-Window in the child list
605 pSWindow = ::ImplFindDlgCtrlWindow( this, pFocusWindow,
606 nIndex, nFormStart, nFormEnd );
607 if ( !pSWindow )
608 return false;
609 i = nIndex;
611 nDlgCtrlFlags = DialogControlFlags::NONE;
612 pTempWindow = pSWindow;
615 nDlgCtrlFlags |= pTempWindow->GetDialogControlFlags();
616 if ( pTempWindow == this )
617 break;
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 )
633 break;
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;
645 sal_uInt16 iStart;
646 if ( aKeyCode.IsShift() )
648 nType = GetDlgWindowType::Prev;
649 nGetFocusFlags |= GetFocusFlags::Backward;
651 else
653 nType = GetDlgWindowType::Next;
654 nGetFocusFlags |= GetFocusFlags::Forward;
656 iStart = i;
657 pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
658 while ( pTempWindow && (pTempWindow != pSWindow) )
660 if ( !pTempWindow->mpWindowImpl->mbPushButton )
662 // get Around-Flag
663 if ( nType == GetDlgWindowType::Prev )
665 if ( nNewIndex > iStart )
666 nGetFocusFlags |= GetFocusFlags::Around;
668 else
670 if ( nNewIndex < iStart )
671 nGetFocusFlags |= GetFocusFlags::Around;
673 pTempWindow->ImplControlFocus( nGetFocusFlags );
674 return true;
676 else
678 i = nNewIndex;
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;
696 return true;
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 )
708 break;
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;
721 return true;
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() )
740 // search group
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() )
750 if ( iTemp != 0 )
751 bFormular = true;
752 if ( aKeyCode.IsShift() )
754 if ( iTemp <= nIndex )
755 pFormularFirstWindow = pPrevFirstFormularFirstWindow;
756 pPrevFirstFormularFirstWindow = pTempWindow;
758 else
760 if ( (iTemp > nIndex) && !pFormularFirstWindow )
761 pFormularFirstWindow = pTempWindow;
763 pLastFormularFirstWindow = pTempWindow;
766 pTempWindow = ImplGetNextWindow( this, iTemp, iTemp, false );
767 if ( !iTemp )
768 pTempWindow = nullptr;
771 if ( bFormular )
773 if ( !pFormularFirstWindow )
775 if ( aKeyCode.IsShift() )
776 pFormularFirstWindow = pLastFormularFirstWindow;
777 else
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();
792 return true;
798 if ( !bFormular )
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;
809 else
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;
827 return true;
829 else if ( pWindow )
831 // get Around-Flag
832 if ( nType == GetDlgWindowType::Prev )
834 if ( nNewIndex > i )
835 nGetFocusFlags |= GetFocusFlags::Around;
837 else
839 if ( nNewIndex < i )
840 nGetFocusFlags |= GetFocusFlags::Around;
842 pWindow->ImplControlFocus( nGetFocusFlags );
843 return true;
849 else if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_UP) )
851 if (pSWindow->GetType() == WINDOW_RADIOBUTTON)
852 return nextInGroup(static_cast<RadioButton*>(pSWindow), true);
853 else
855 WinBits nStyle = pSWindow->GetStyle();
856 if ( !(nStyle & WB_GROUP) )
858 vcl::Window* pWindow = prevLogicalChildOfParent(this, pSWindow);
859 while ( pWindow )
861 pWindow = pWindow->ImplGetWindow();
863 nStyle = pWindow->GetStyle();
865 if (isSuitableDestination(pWindow))
867 if ( pWindow != pSWindow )
868 pWindow->ImplControlFocus( GetFocusFlags::CURSOR | GetFocusFlags::Backward );
869 return true;
872 if ( nStyle & WB_GROUP )
873 break;
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);
884 else
886 vcl::Window* pWindow = nextLogicalChildOfParent(this, pSWindow);
887 while ( pWindow )
889 pWindow = pWindow->ImplGetWindow();
891 WinBits nStyle = pWindow->GetStyle();
893 if ( nStyle & WB_GROUP )
894 break;
896 if (isSuitableDestination(pWindow))
898 pWindow->ImplControlFocus( GetFocusFlags::CURSOR | GetFocusFlags::Backward );
899 return true;
902 pWindow = nextLogicalChildOfParent(this, pWindow);
906 else
908 sal_Unicode c = rKEvt.GetCharCode();
909 if ( c )
911 pSWindow = ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd );
912 if ( pSWindow )
914 GetFocusFlags nGetFocusFlags = GetFocusFlags::Mnemonic;
915 if ( pSWindow == ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd ) )
916 nGetFocusFlags |= GetFocusFlags::UniqueMnemonic;
917 pSWindow->ImplControlFocus( nGetFocusFlags );
918 return true;
924 if (isSuitableDestination(pButtonWindow))
926 if ( bKeyInput )
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();
944 return true;
947 return false;
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) )
963 return false;
964 else
965 return true;
968 void Window::ImplDlgCtrlNextWindow()
970 vcl::Window* pDlgCtrlParent;
971 vcl::Window* pDlgCtrl;
972 vcl::Window* pSWindow;
973 sal_uInt16 nIndex;
974 sal_uInt16 nFormStart;
975 sal_uInt16 nFormEnd;
977 // lookup window for dialog control
978 pDlgCtrl = this;
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) )
986 return;
988 // lookup window in child list
989 pSWindow = ::ImplFindDlgCtrlWindow( pDlgCtrlParent, pDlgCtrl,
990 nIndex, nFormStart, nFormEnd );
991 if ( !pSWindow )
992 return;
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,
1000 bool bGetFocus )
1002 PushButton* pOldDefButton = nullptr;
1003 PushButton* pNewDefButton = nullptr;
1004 vcl::Window* pSWindow;
1005 sal_uInt16 i;
1006 sal_uInt16 nFormStart;
1007 sal_uInt16 nFormEnd;
1009 // find template
1010 pSWindow = ::ImplFindDlgCtrlWindow( pParent, pFocusWindow, i, nFormStart, nFormEnd );
1011 if ( !pSWindow )
1013 nFormStart = 0;
1014 nFormEnd = 0xFFFF;
1017 pSWindow = ImplGetChildWindow( pParent, nFormStart, i, false );
1018 while ( pSWindow )
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) )
1033 pSWindow = nullptr;
1036 if ( !bGetFocus )
1038 sal_uInt16 nDummy;
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 )
1069 sal_uInt16 nIndex;
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
1079 return nullptr;
1082 vcl::Window* Window::GetParentLabeledBy( const vcl::Window* ) const
1084 return nullptr;
1087 KeyEvent Window::GetActivationKey() const
1089 KeyEvent aKeyEvent;
1091 sal_Unicode nAccel = getAccel( GetText() );
1092 if( ! nAccel )
1094 vcl::Window* pWindow = GetAccessibleRelationLabeledBy();
1095 if( pWindow )
1096 nAccel = getAccel( pWindow->GetText() );
1098 if( nAccel )
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 == '.' )
1108 nCode = KEY_POINT;
1109 else if( nAccel == '-' )
1110 nCode = KEY_SUBTRACT;
1111 vcl::KeyCode aKeyCode( nCode, false, false, true, false );
1112 aKeyEvent = KeyEvent( nAccel, aKeyCode );
1114 return aKeyEvent;
1117 } /* namespace vcl */
1119 sal_Unicode getAccel( const OUString& rStr )
1121 sal_Unicode nChar = 0;
1122 sal_Int32 nPos = 0;
1125 nPos = rStr.indexOf( '~', nPos );
1126 if( nPos != -1 && nPos < rStr.getLength() )
1127 nChar = rStr[ ++nPos ];
1128 else
1129 nChar = 0;
1130 } while( nChar == '~' );
1131 return nChar;
1134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */