Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 :
22 : #include <svdata.hxx>
23 :
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>
35 :
36 : #include <com/sun/star/i18n/XCharacterClassification.hpp>
37 :
38 : using namespace ::com::sun::star;
39 :
40 23491 : static bool ImplHasIndirectTabParent( vcl::Window* pWindow )
41 : {
42 : // The window has inderect tab parent if it is included in tab hierarchy
43 : // of the indirect parent window
44 :
45 23491 : vcl::Window* pNonLayoutParent = getNonLayoutParent(pWindow);
46 : return ( pNonLayoutParent
47 23491 : && ( pNonLayoutParent->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) );
48 : }
49 :
50 95502 : static vcl::Window* ImplGetTopParentOfTabHierarchy( vcl::Window* pParent )
51 : {
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
55 :
56 95502 : vcl::Window* pResult = pParent;
57 :
58 95502 : if ( pResult )
59 : {
60 95502 : vcl::Window* pNonLayoutParent = getNonLayoutParent(pResult);
61 191004 : while ( pNonLayoutParent && ( pResult->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) )
62 : {
63 0 : pResult = pNonLayoutParent;
64 0 : pNonLayoutParent = getNonLayoutParent(pResult);
65 : }
66 : }
67 :
68 95502 : return pResult;
69 : }
70 :
71 186044 : static vcl::Window* ImplGetSubChildWindow( vcl::Window* pParent, sal_uInt16 n, sal_uInt16& nIndex )
72 : {
73 186044 : vcl::Window* pTabPage = NULL;
74 186044 : vcl::Window* pFoundWindow = NULL;
75 :
76 186044 : vcl::Window* pWindow = firstLogicalChildOfParent(pParent);
77 186044 : vcl::Window* pNextWindow = pWindow;
78 596685 : while ( pWindow )
79 : {
80 313980 : pWindow = pWindow->ImplGetWindow();
81 :
82 : // skip invisible and disabled windows
83 313980 : if ( pTabPage || isVisibleInLayout(pWindow) )
84 : {
85 : // if the last control was a TabControl, take its TabPage
86 257435 : if ( pTabPage )
87 : {
88 0 : pFoundWindow = ImplGetSubChildWindow( pTabPage, n, nIndex );
89 0 : pTabPage = NULL;
90 : }
91 : else
92 : {
93 257435 : pFoundWindow = pWindow;
94 :
95 : // for a TabControl, remember the current TabPage for later use
96 257435 : if ( pWindow->GetType() == WINDOW_TABCONTROL )
97 : {
98 0 : 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 0 : TabPage* pTempTabPage = pTabControl->GetTabPage( pTabControl->GetCurPageId() );
103 0 : if ( pTempTabPage )
104 : {
105 0 : vcl::Window* pTempWindow = pTabControl->GetWindow( WINDOW_FIRSTCHILD );
106 0 : while ( pTempWindow )
107 : {
108 0 : if ( pTempWindow->ImplGetWindow() == pTempTabPage )
109 : {
110 0 : pTabPage = pTempTabPage;
111 0 : break;
112 : }
113 0 : pTempWindow = nextLogicalChildOfParent(pTabControl, pTempWindow);
114 : }
115 : }
116 : }
117 514870 : else if ( ( pWindow->GetStyle() & WB_DIALOGCONTROL )
118 257435 : || ( pWindow->GetStyle() & WB_CHILDDLGCTRL ) )
119 90542 : pFoundWindow = ImplGetSubChildWindow( pWindow, n, nIndex );
120 : }
121 :
122 257435 : if ( n == nIndex )
123 89383 : return pFoundWindow;
124 168052 : nIndex++;
125 : }
126 :
127 224597 : if ( pTabPage )
128 0 : pWindow = pTabPage;
129 : else
130 : {
131 224597 : pWindow = nextLogicalChildOfParent(pParent, pNextWindow);
132 224597 : pNextWindow = pWindow;
133 : }
134 : }
135 :
136 96661 : nIndex--;
137 96661 : return pFoundWindow;
138 : }
139 :
140 95502 : vcl::Window* ImplGetChildWindow( vcl::Window* pParent, sal_uInt16 n, sal_uInt16& nIndex, bool bTestEnable )
141 : {
142 95502 : pParent = ImplGetTopParentOfTabHierarchy( pParent );
143 :
144 95502 : nIndex = 0;
145 95502 : vcl::Window* pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
146 95502 : if ( bTestEnable )
147 : {
148 1448 : sal_uInt16 n2 = nIndex;
149 2896 : while ( pWindow && (!isEnabledInLayout(pWindow) || !pWindow->IsInputEnabled()) )
150 : {
151 0 : n2 = nIndex+1;
152 0 : nIndex = 0;
153 0 : pWindow = ImplGetSubChildWindow( pParent, n2, nIndex );
154 0 : if ( nIndex < n2 )
155 0 : break;
156 : }
157 :
158 1448 : if ( (nIndex < n2) && n )
159 : {
160 0 : do
161 : {
162 0 : n--;
163 0 : nIndex = 0;
164 0 : pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
165 : }
166 0 : while ( pWindow && n && (!isEnabledInLayout(pWindow) || !pWindow->IsInputEnabled()) );
167 : }
168 : }
169 95502 : return pWindow;
170 : }
171 :
172 36484 : static vcl::Window* ImplGetNextWindow( vcl::Window* pParent, sal_uInt16 n, sal_uInt16& nIndex, bool bTestEnable )
173 : {
174 36484 : vcl::Window* pWindow = ImplGetChildWindow( pParent, n+1, nIndex, bTestEnable );
175 36484 : if ( n == nIndex )
176 : {
177 15953 : n = 0;
178 15953 : pWindow = ImplGetChildWindow( pParent, n, nIndex, bTestEnable );
179 : }
180 36484 : return pWindow;
181 : }
182 :
183 : namespace vcl {
184 :
185 516 : vcl::Window* Window::ImplGetDlgWindow( sal_uInt16 nIndex, sal_uInt16 nType,
186 : sal_uInt16 nFormStart, sal_uInt16 nFormEnd,
187 : sal_uInt16* pIndex )
188 : {
189 : DBG_ASSERT( (nIndex >= nFormStart) && (nIndex <= nFormEnd),
190 : "Window::ImplGetDlgWindow() - nIndex not in Form" );
191 :
192 516 : vcl::Window* pWindow = NULL;
193 : sal_uInt16 i;
194 : sal_uInt16 nTemp;
195 : sal_uInt16 nStartIndex;
196 :
197 516 : if ( nType == DLGWINDOW_PREV )
198 : {
199 0 : i = nIndex;
200 0 : do
201 : {
202 0 : if ( i > nFormStart )
203 0 : i--;
204 : else
205 0 : i = nFormEnd;
206 0 : pWindow = ImplGetChildWindow( this, i, nTemp, true );
207 0 : if ( !pWindow )
208 0 : break;
209 0 : if ( (i == nTemp) && (pWindow->GetStyle() & WB_TABSTOP) )
210 0 : break;
211 : }
212 0 : while ( i != nIndex );
213 : }
214 : else
215 : {
216 516 : i = nIndex;
217 516 : pWindow = ImplGetChildWindow( this, i, i, (nType == DLGWINDOW_FIRST) );
218 516 : if ( pWindow )
219 : {
220 286 : nStartIndex = i;
221 :
222 286 : if ( nType == DLGWINDOW_NEXT )
223 : {
224 0 : if ( i < nFormEnd )
225 : {
226 0 : pWindow = ImplGetNextWindow( this, i, i, true );
227 0 : if ( (i > nFormEnd) || (i < nFormStart) )
228 0 : pWindow = ImplGetChildWindow( this, nFormStart, i, true );
229 : }
230 : else
231 0 : pWindow = ImplGetChildWindow( this, nFormStart, i, true );
232 : }
233 :
234 286 : if ( i <= nFormEnd )
235 : {
236 : // carry the 2nd index, in case all controls are disabled
237 286 : sal_uInt16 nStartIndex2 = i;
238 286 : sal_uInt16 nOldIndex = i+1;
239 :
240 782 : do
241 : {
242 918 : if ( pWindow->GetStyle() & WB_TABSTOP )
243 136 : break;
244 782 : if( i == nOldIndex ) // only disabled controls ?
245 : {
246 0 : i = nStartIndex2;
247 0 : break;
248 : }
249 782 : nOldIndex = i;
250 782 : if ( (i > nFormEnd) || (i < nFormStart) )
251 0 : pWindow = ImplGetChildWindow( this, nFormStart, i, true );
252 : else
253 782 : pWindow = ImplGetNextWindow( this, i, i, true );
254 : }
255 1414 : while ( (i != nStartIndex) && (i != nStartIndex2) );
256 :
257 708 : if ( (i == nStartIndex2) &&
258 394 : (!(pWindow->GetStyle() & WB_TABSTOP) || !isEnabledInLayout(pWindow)) )
259 150 : i = nStartIndex;
260 : }
261 : }
262 :
263 516 : if ( nType == DLGWINDOW_FIRST )
264 : {
265 516 : if ( pWindow )
266 : {
267 286 : if ( pWindow->GetType() == WINDOW_TABCONTROL )
268 : {
269 0 : vcl::Window* pNextWindow = ImplGetDlgWindow( i, DLGWINDOW_NEXT );
270 0 : if ( pNextWindow )
271 : {
272 0 : if ( pWindow->IsChild( pNextWindow ) )
273 0 : pWindow = pNextWindow;
274 : }
275 : }
276 :
277 286 : if ( !(pWindow->GetStyle() & WB_TABSTOP) )
278 150 : pWindow = NULL;
279 : }
280 : }
281 : }
282 :
283 516 : if ( pIndex )
284 0 : *pIndex = i;
285 :
286 516 : return pWindow;
287 : }
288 :
289 : } /* namespace vcl */
290 :
291 27462 : vcl::Window* ImplFindDlgCtrlWindow( vcl::Window* pParent, vcl::Window* pWindow, sal_uInt16& rIndex,
292 : sal_uInt16& rFormStart, sal_uInt16& rFormEnd )
293 : {
294 : vcl::Window* pSWindow;
295 27462 : vcl::Window* pSecondWindow = NULL;
296 27462 : vcl::Window* pTempWindow = NULL;
297 : sal_uInt16 i;
298 27462 : sal_uInt16 nSecond_i = 0;
299 27462 : sal_uInt16 nFormStart = 0;
300 27462 : sal_uInt16 nSecondFormStart = 0;
301 : sal_uInt16 nFormEnd;
302 :
303 : // find focus window in the child list
304 27462 : vcl::Window* pFirstChildWindow = pSWindow = ImplGetChildWindow( pParent, 0, i, false );
305 :
306 27462 : if( pWindow == NULL )
307 0 : pWindow = pSWindow;
308 :
309 74633 : while ( pSWindow )
310 : {
311 : // the DialogControlStart mark is only accepted for the direct children
312 42454 : if ( !ImplHasIndirectTabParent( pSWindow )
313 21227 : && pSWindow->ImplGetWindow()->IsDialogControlStart() )
314 0 : nFormStart = i;
315 :
316 : // SecondWindow for composit controls like ComboBoxes and arrays
317 21227 : if ( pSWindow->ImplIsWindowOrChild( pWindow ) )
318 : {
319 2955 : pSecondWindow = pSWindow;
320 2955 : nSecond_i = i;
321 2955 : nSecondFormStart = nFormStart;
322 2955 : if ( pSWindow == pWindow )
323 1518 : break;
324 : }
325 :
326 19709 : pSWindow = ImplGetNextWindow( pParent, i, i, false );
327 19709 : if ( !i )
328 9611 : pSWindow = NULL;
329 : }
330 :
331 27462 : if ( !pSWindow )
332 : {
333 : // Window not found; we cannot handle it
334 25944 : if ( !pSecondWindow )
335 24507 : return NULL;
336 : else
337 : {
338 1437 : pSWindow = pSecondWindow;
339 1437 : i = nSecond_i;
340 1437 : nFormStart = nSecondFormStart;
341 : }
342 : }
343 :
344 : // initialize
345 2955 : rIndex = i;
346 2955 : rFormStart = nFormStart;
347 :
348 : // find end of template
349 2955 : nFormEnd = nFormStart;
350 2955 : pTempWindow = pSWindow;
351 2955 : sal_Int32 nIteration = 0;
352 2264 : do
353 : {
354 5219 : nFormEnd = i;
355 5219 : pTempWindow = ImplGetNextWindow( pParent, i, i, false );
356 :
357 : // the DialogControlStart mark is only accepted for the direct children
358 10438 : if ( !i
359 8174 : || ( pTempWindow && !ImplHasIndirectTabParent( pTempWindow )
360 2264 : && pTempWindow->ImplGetWindow()->IsDialogControlStart() ) )
361 2955 : break;
362 :
363 2264 : if ( pTempWindow && pTempWindow == pFirstChildWindow )
364 : {
365 : // It is possible to go through the begin of hierarchy once
366 : // while looking for DialogControlStart mark.
367 : // If it happens second time, it looks like an endless loop,
368 : // that should be impossible, but just for the case...
369 0 : nIteration++;
370 0 : if ( nIteration >= 2 )
371 : {
372 : // this is an unexpected scenario
373 : DBG_ASSERT( false, "It seems to be an endless loop!" );
374 0 : rFormStart = 0;
375 0 : break;
376 : }
377 : }
378 : }
379 : while ( pTempWindow );
380 2955 : rFormEnd = nFormEnd;
381 :
382 2955 : return pSWindow;
383 : }
384 :
385 0 : vcl::Window* ImplFindAccelWindow( vcl::Window* pParent, sal_uInt16& rIndex, sal_Unicode cCharCode,
386 : sal_uInt16 nFormStart, sal_uInt16 nFormEnd, bool bCheckEnable )
387 : {
388 : DBG_ASSERT( (rIndex >= nFormStart) && (rIndex <= nFormEnd),
389 : "Window::ImplFindAccelWindow() - rIndex not in Form" );
390 :
391 : sal_Unicode cCompareChar;
392 0 : sal_uInt16 nStart = rIndex;
393 0 : sal_uInt16 i = rIndex;
394 : vcl::Window* pWindow;
395 :
396 : // MT: Where can we keep the CharClass?!
397 0 : static uno::Reference< i18n::XCharacterClassification > xCharClass;
398 0 : if ( !xCharClass.is() )
399 0 : xCharClass = vcl::unohelper::CreateCharacterClassification();
400 :
401 0 : const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILanguageTag().getLocale();
402 0 : cCharCode = xCharClass->toUpper( OUString(cCharCode), 0, 1, rLocale )[0];
403 :
404 0 : if ( i < nFormEnd )
405 0 : pWindow = ImplGetNextWindow( pParent, i, i, true );
406 : else
407 0 : pWindow = ImplGetChildWindow( pParent, nFormStart, i, true );
408 0 : while( pWindow )
409 : {
410 0 : const OUString aStr = pWindow->GetText();
411 0 : sal_Int32 nPos = aStr.indexOf( '~' );
412 0 : while (nPos != -1)
413 : {
414 0 : cCompareChar = aStr[nPos+1];
415 0 : cCompareChar = xCharClass->toUpper( OUString(cCompareChar), 0, 1, rLocale )[0];
416 0 : if ( cCompareChar == cCharCode )
417 : {
418 0 : if (pWindow->GetType() == WINDOW_FIXEDTEXT)
419 : {
420 0 : FixedText *pFixedText = static_cast<FixedText*>(pWindow);
421 0 : vcl::Window *pMnemonicWidget = pFixedText->get_mnemonic_widget();
422 : SAL_WARN_IF(isContainerWindow(pFixedText->GetParent()) && !pMnemonicWidget,
423 : "vcl.a11y", "label missing mnemonic_widget?");
424 0 : if (pMnemonicWidget)
425 0 : return pMnemonicWidget;
426 : }
427 :
428 : // skip Static-Controls
429 0 : if ( (pWindow->GetType() == WINDOW_FIXEDTEXT) ||
430 0 : (pWindow->GetType() == WINDOW_FIXEDLINE) ||
431 0 : (pWindow->GetType() == WINDOW_GROUPBOX) )
432 0 : pWindow = pParent->ImplGetDlgWindow( i, DLGWINDOW_NEXT );
433 0 : rIndex = i;
434 0 : return pWindow;
435 : }
436 0 : nPos = aStr.indexOf( '~', nPos+1 );
437 : }
438 :
439 : // #i93011# it would have made sense to have this really recursive
440 : // right from the start. However this would cause unpredictable side effects now
441 : // so instead we have a style bit for some child windows, that want their
442 : // children checked for accelerators
443 0 : if( (pWindow->GetStyle() & WB_CHILDDLGCTRL) != 0 )
444 : {
445 : sal_uInt16 nChildIndex;
446 : sal_uInt16 nChildFormStart;
447 : sal_uInt16 nChildFormEnd;
448 :
449 : // get form start and end
450 : ::ImplFindDlgCtrlWindow( pWindow, NULL,
451 0 : nChildIndex, nChildFormStart, nChildFormEnd );
452 : vcl::Window* pAccelWin = ImplFindAccelWindow( pWindow, nChildIndex, cCharCode,
453 : nChildFormStart, nChildFormEnd,
454 0 : bCheckEnable );
455 0 : if( pAccelWin )
456 0 : return pAccelWin;
457 : }
458 :
459 0 : if ( i == nStart )
460 0 : break;
461 :
462 0 : if ( i < nFormEnd )
463 : {
464 0 : pWindow = ImplGetNextWindow( pParent, i, i, bCheckEnable );
465 0 : if( ! pWindow )
466 0 : pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
467 : }
468 : else
469 0 : pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
470 0 : }
471 :
472 0 : return NULL;
473 : }
474 :
475 : namespace vcl {
476 :
477 136 : void Window::ImplControlFocus( sal_uInt16 nFlags )
478 : {
479 136 : if ( nFlags & GETFOCUS_MNEMONIC )
480 : {
481 0 : if ( GetType() == WINDOW_RADIOBUTTON )
482 : {
483 0 : if ( !static_cast<RadioButton*>(this)->IsChecked() )
484 0 : static_cast<RadioButton*>(this)->ImplCallClick( true, nFlags );
485 : else
486 0 : ImplGrabFocus( nFlags );
487 : }
488 : else
489 : {
490 0 : ImplGrabFocus( nFlags );
491 0 : if ( nFlags & GETFOCUS_UNIQUEMNEMONIC )
492 : {
493 0 : if ( GetType() == WINDOW_CHECKBOX )
494 0 : static_cast<CheckBox*>(this)->ImplCheck();
495 0 : else if ( mpWindowImpl->mbPushButton )
496 : {
497 0 : static_cast<PushButton*>(this)->SetPressed( true );
498 0 : static_cast<PushButton*>(this)->SetPressed( false );
499 0 : static_cast<PushButton*>(this)->Click();
500 : }
501 : }
502 : }
503 : }
504 : else
505 : {
506 136 : if ( GetType() == WINDOW_RADIOBUTTON )
507 : {
508 0 : if ( !static_cast<RadioButton*>(this)->IsChecked() )
509 0 : static_cast<RadioButton*>(this)->ImplCallClick( true, nFlags );
510 : else
511 0 : ImplGrabFocus( nFlags );
512 : }
513 : else
514 136 : ImplGrabFocus( nFlags );
515 : }
516 136 : }
517 :
518 : } /* namespace vcl */
519 :
520 : namespace
521 : {
522 0 : bool isSuitableDestination(vcl::Window *pWindow)
523 : {
524 0 : return (pWindow && isVisibleInLayout(pWindow) &&
525 0 : isEnabledInLayout(pWindow) && pWindow->IsInputEnabled() &&
526 : //Pure window shouldn't get window after controls such as
527 : //buttons.
528 0 : (pWindow->GetType() != WINDOW_WINDOW && pWindow->GetType() != WINDOW_SYSWINDOW &&
529 0 : pWindow->GetType() != WINDOW_WORKWINDOW && pWindow->GetType() != WINDOW_CONTROL)
530 0 : );
531 : }
532 :
533 0 : bool focusNextInGroup(std::vector<RadioButton*>::iterator aStart, std::vector<RadioButton*> &rGroup)
534 : {
535 0 : std::vector<RadioButton*>::iterator aI(aStart);
536 :
537 0 : if (aStart != rGroup.end())
538 0 : ++aI;
539 :
540 0 : for (; aI != rGroup.end(); ++aI)
541 : {
542 0 : vcl::Window *pWindow = *aI;
543 :
544 0 : if (isSuitableDestination(pWindow))
545 : {
546 0 : pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_FORWARD );
547 0 : return true;
548 : }
549 : }
550 :
551 0 : for (aI = rGroup.begin(); aI != aStart; ++aI)
552 : {
553 0 : vcl::Window *pWindow = *aI;
554 :
555 0 : if (isSuitableDestination(pWindow))
556 : {
557 0 : pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_FORWARD );
558 0 : return true;
559 : }
560 : }
561 :
562 0 : return false;
563 : }
564 :
565 0 : bool nextInGroup(RadioButton *pSourceWindow, bool bBackward)
566 : {
567 0 : std::vector<RadioButton*> aGroup(pSourceWindow->GetRadioButtonGroup(true));
568 :
569 0 : if (aGroup.size() == 1) //only one button in group
570 0 : return false;
571 :
572 0 : if (bBackward)
573 0 : std::reverse(aGroup.begin(), aGroup.end());
574 :
575 0 : std::vector<RadioButton*>::iterator aStart(std::find(aGroup.begin(), aGroup.end(), pSourceWindow));
576 :
577 : assert(aStart != aGroup.end());
578 :
579 0 : return focusNextInGroup(aStart, aGroup);
580 : }
581 : }
582 :
583 : namespace vcl {
584 :
585 0 : bool Window::ImplDlgCtrl( const KeyEvent& rKEvt, bool bKeyInput )
586 : {
587 0 : vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
588 0 : sal_uInt16 nKeyCode = aKeyCode.GetCode();
589 : vcl::Window* pSWindow;
590 : vcl::Window* pTempWindow;
591 : vcl::Window* pButtonWindow;
592 : sal_uInt16 i;
593 : sal_uInt16 iButton;
594 : sal_uInt16 iButtonStart;
595 : sal_uInt16 iTemp;
596 : sal_uInt16 nIndex;
597 : sal_uInt16 nFormStart;
598 : sal_uInt16 nFormEnd;
599 : sal_uInt16 nDlgCtrlFlags;
600 :
601 : // we cannot take over control without Focus-window
602 0 : vcl::Window* pFocusWindow = Application::GetFocusWindow();
603 0 : if ( !pFocusWindow || !ImplIsWindowOrChild( pFocusWindow ) )
604 0 : return false;
605 :
606 : // find Focus-Window in the child list
607 : pSWindow = ::ImplFindDlgCtrlWindow( this, pFocusWindow,
608 0 : nIndex, nFormStart, nFormEnd );
609 0 : if ( !pSWindow )
610 0 : return false;
611 0 : i = nIndex;
612 :
613 0 : nDlgCtrlFlags = 0;
614 0 : pTempWindow = pSWindow;
615 0 : do
616 : {
617 0 : nDlgCtrlFlags |= pTempWindow->GetDialogControlFlags();
618 0 : if ( pTempWindow == this )
619 0 : break;
620 0 : pTempWindow = pTempWindow->ImplGetParent();
621 : }
622 : while ( pTempWindow );
623 :
624 0 : pButtonWindow = NULL;
625 :
626 0 : if ( nKeyCode == KEY_RETURN )
627 : {
628 : // search first for a DefPushButton/CancelButton
629 0 : pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, true );
630 0 : iButtonStart = iButton;
631 0 : while ( pButtonWindow )
632 : {
633 0 : if ( (pButtonWindow->GetStyle() & WB_DEFBUTTON) &&
634 : pButtonWindow->mpWindowImpl->mbPushButton )
635 0 : break;
636 :
637 0 : pButtonWindow = ImplGetNextWindow( this, iButton, iButton, true );
638 0 : if ( (iButton <= iButtonStart) || (iButton > nFormEnd) )
639 0 : pButtonWindow = NULL;
640 : }
641 :
642 0 : if ( bKeyInput && !pButtonWindow && (nDlgCtrlFlags & WINDOW_DLGCTRL_RETURN) )
643 : {
644 : sal_uInt16 nType;
645 0 : sal_uInt16 nGetFocusFlags = GETFOCUS_TAB;
646 : sal_uInt16 nNewIndex;
647 : sal_uInt16 iStart;
648 0 : if ( aKeyCode.IsShift() )
649 : {
650 0 : nType = DLGWINDOW_PREV;
651 0 : nGetFocusFlags |= GETFOCUS_BACKWARD;
652 : }
653 : else
654 : {
655 0 : nType = DLGWINDOW_NEXT;
656 0 : nGetFocusFlags |= GETFOCUS_FORWARD;
657 : }
658 0 : iStart = i;
659 0 : pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
660 0 : while ( pTempWindow && (pTempWindow != pSWindow) )
661 : {
662 0 : if ( !pTempWindow->mpWindowImpl->mbPushButton )
663 : {
664 : // get Around-Flag
665 0 : if ( nType == DLGWINDOW_PREV )
666 : {
667 0 : if ( nNewIndex > iStart )
668 0 : nGetFocusFlags |= GETFOCUS_AROUND;
669 : }
670 : else
671 : {
672 0 : if ( nNewIndex < iStart )
673 0 : nGetFocusFlags |= GETFOCUS_AROUND;
674 : }
675 0 : pTempWindow->ImplControlFocus( nGetFocusFlags );
676 0 : return true;
677 : }
678 : else
679 : {
680 0 : i = nNewIndex;
681 0 : pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
682 : }
683 0 : if ( (i <= iStart) || (i > nFormEnd) )
684 0 : pTempWindow = NULL;
685 : }
686 : // if this is the same window, simulate a Get/LoseFocus,
687 : // in case AROUND is being processed
688 0 : if ( pTempWindow && (pTempWindow == pSWindow) )
689 : {
690 0 : NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow );
691 0 : if ( !ImplCallPreNotify( aNEvt1 ) )
692 0 : pSWindow->LoseFocus();
693 0 : pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND;
694 0 : NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow );
695 0 : if ( !ImplCallPreNotify( aNEvt2 ) )
696 0 : pSWindow->GetFocus();
697 0 : pSWindow->mpWindowImpl->mnGetFocusFlags = 0;
698 0 : return true;
699 : }
700 : }
701 : }
702 0 : else if ( nKeyCode == KEY_ESCAPE )
703 : {
704 : // search first for a DefPushButton/CancelButton
705 0 : pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, true );
706 0 : iButtonStart = iButton;
707 0 : while ( pButtonWindow )
708 : {
709 0 : if ( pButtonWindow->GetType() == WINDOW_CANCELBUTTON )
710 0 : break;
711 :
712 0 : pButtonWindow = ImplGetNextWindow( this, iButton, iButton, true );
713 0 : if ( (iButton <= iButtonStart) || (iButton > nFormEnd) )
714 0 : pButtonWindow = NULL;
715 : }
716 :
717 0 : if ( bKeyInput && mpWindowImpl->mpDlgCtrlDownWindow )
718 : {
719 0 : if ( mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow )
720 : {
721 0 : static_cast<PushButton*>(mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( false );
722 0 : mpWindowImpl->mpDlgCtrlDownWindow = NULL;
723 0 : return true;
724 : }
725 : }
726 : }
727 0 : else if ( bKeyInput )
728 : {
729 0 : if ( nKeyCode == KEY_TAB )
730 : {
731 : // do not skip Alt key, for MS Windows
732 0 : if ( !aKeyCode.IsMod2() )
733 : {
734 : sal_uInt16 nType;
735 0 : sal_uInt16 nGetFocusFlags = GETFOCUS_TAB;
736 : sal_uInt16 nNewIndex;
737 0 : bool bFormular = false;
738 :
739 : // for Ctrl-Tab check if we want to jump to next template
740 0 : if ( aKeyCode.IsMod1() )
741 : {
742 : // search group
743 0 : vcl::Window* pFormularFirstWindow = NULL;
744 0 : vcl::Window* pLastFormularFirstWindow = NULL;
745 0 : pTempWindow = ImplGetChildWindow( this, 0, iTemp, false );
746 0 : vcl::Window* pPrevFirstFormularFirstWindow = NULL;
747 0 : vcl::Window* pFirstFormularFirstWindow = pTempWindow;
748 0 : while ( pTempWindow )
749 : {
750 0 : if ( pTempWindow->ImplGetWindow()->IsDialogControlStart() )
751 : {
752 0 : if ( iTemp != 0 )
753 0 : bFormular = true;
754 0 : if ( aKeyCode.IsShift() )
755 : {
756 0 : if ( iTemp <= nIndex )
757 0 : pFormularFirstWindow = pPrevFirstFormularFirstWindow;
758 0 : pPrevFirstFormularFirstWindow = pTempWindow;
759 : }
760 : else
761 : {
762 0 : if ( (iTemp > nIndex) && !pFormularFirstWindow )
763 0 : pFormularFirstWindow = pTempWindow;
764 : }
765 0 : pLastFormularFirstWindow = pTempWindow;
766 : }
767 :
768 0 : pTempWindow = ImplGetNextWindow( this, iTemp, iTemp, false );
769 0 : if ( !iTemp )
770 0 : pTempWindow = NULL;
771 : }
772 :
773 0 : if ( bFormular )
774 : {
775 0 : if ( !pFormularFirstWindow )
776 : {
777 0 : if ( aKeyCode.IsShift() )
778 0 : pFormularFirstWindow = pLastFormularFirstWindow;
779 : else
780 0 : pFormularFirstWindow = pFirstFormularFirstWindow;
781 : }
782 :
783 0 : sal_uInt16 nFoundFormStart = 0;
784 0 : sal_uInt16 nFoundFormEnd = 0;
785 0 : sal_uInt16 nTempIndex = 0;
786 0 : if ( ::ImplFindDlgCtrlWindow( this, pFormularFirstWindow, nTempIndex,
787 0 : nFoundFormStart, nFoundFormEnd ) )
788 : {
789 0 : nTempIndex = nFoundFormStart;
790 0 : pFormularFirstWindow = ImplGetDlgWindow( nTempIndex, DLGWINDOW_FIRST, nFoundFormStart, nFoundFormEnd );
791 0 : if ( pFormularFirstWindow )
792 : {
793 0 : pFormularFirstWindow->ImplControlFocus();
794 0 : return true;
795 : }
796 : }
797 : }
798 : }
799 :
800 0 : if ( !bFormular )
801 : {
802 : // Only use Ctrl-TAB if it was allowed for the whole
803 : // dialog or for the current control (#103667#)
804 0 : if ( !aKeyCode.IsMod1() || (nDlgCtrlFlags & WINDOW_DLGCTRL_MOD1TAB) ||
805 0 : ( pSWindow->GetStyle() & WINDOW_DLGCTRL_MOD1TAB) )
806 : {
807 0 : if ( aKeyCode.IsShift() )
808 : {
809 0 : nType = DLGWINDOW_PREV;
810 0 : nGetFocusFlags |= GETFOCUS_BACKWARD;
811 : }
812 : else
813 : {
814 0 : nType = DLGWINDOW_NEXT;
815 0 : nGetFocusFlags |= GETFOCUS_FORWARD;
816 : }
817 0 : vcl::Window* pWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
818 : // if this is the same window, simulate a Get/LoseFocus,
819 : // in case AROUND is being processed
820 0 : if ( pWindow == pSWindow )
821 : {
822 0 : NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow );
823 0 : if ( !ImplCallPreNotify( aNEvt1 ) )
824 0 : pSWindow->LoseFocus();
825 0 : pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND;
826 0 : NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow );
827 0 : if ( !ImplCallPreNotify( aNEvt2 ) )
828 0 : pSWindow->GetFocus();
829 0 : pSWindow->mpWindowImpl->mnGetFocusFlags = 0;
830 0 : return true;
831 : }
832 0 : else if ( pWindow )
833 : {
834 : // get Around-Flag
835 0 : if ( nType == DLGWINDOW_PREV )
836 : {
837 0 : if ( nNewIndex > i )
838 0 : nGetFocusFlags |= GETFOCUS_AROUND;
839 : }
840 : else
841 : {
842 0 : if ( nNewIndex < i )
843 0 : nGetFocusFlags |= GETFOCUS_AROUND;
844 : }
845 0 : pWindow->ImplControlFocus( nGetFocusFlags );
846 0 : return true;
847 : }
848 : }
849 : }
850 : }
851 : }
852 0 : else if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_UP) )
853 : {
854 0 : if (pSWindow->GetType() == WINDOW_RADIOBUTTON)
855 0 : return nextInGroup(static_cast<RadioButton*>(pSWindow), true);
856 : else
857 : {
858 0 : WinBits nStyle = pSWindow->GetStyle();
859 0 : if ( !(nStyle & WB_GROUP) )
860 : {
861 0 : vcl::Window* pWindow = prevLogicalChildOfParent(this, pSWindow);
862 0 : while ( pWindow )
863 : {
864 0 : pWindow = pWindow->ImplGetWindow();
865 :
866 0 : nStyle = pWindow->GetStyle();
867 :
868 0 : if (isSuitableDestination(pWindow))
869 : {
870 0 : if ( pWindow != pSWindow )
871 0 : pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD );
872 0 : return true;
873 : }
874 :
875 0 : if ( nStyle & WB_GROUP )
876 0 : break;
877 :
878 0 : pWindow = prevLogicalChildOfParent(this, pWindow);
879 : }
880 : }
881 0 : }
882 : }
883 0 : else if ( (nKeyCode == KEY_RIGHT) || (nKeyCode == KEY_DOWN) )
884 : {
885 0 : if (pSWindow->GetType() == WINDOW_RADIOBUTTON)
886 0 : return nextInGroup(static_cast<RadioButton*>(pSWindow), false);
887 : else
888 : {
889 0 : vcl::Window* pWindow = nextLogicalChildOfParent(this, pSWindow);
890 0 : while ( pWindow )
891 : {
892 0 : pWindow = pWindow->ImplGetWindow();
893 :
894 0 : WinBits nStyle = pWindow->GetStyle();
895 :
896 0 : if ( nStyle & WB_GROUP )
897 0 : break;
898 :
899 0 : if (isSuitableDestination(pWindow))
900 : {
901 0 : pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD );
902 0 : return true;
903 : }
904 :
905 0 : pWindow = nextLogicalChildOfParent(this, pWindow);
906 : }
907 0 : }
908 : }
909 : else
910 : {
911 0 : sal_Unicode c = rKEvt.GetCharCode();
912 0 : if ( c )
913 : {
914 0 : pSWindow = ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd );
915 0 : if ( pSWindow )
916 : {
917 0 : sal_uInt16 nGetFocusFlags = GETFOCUS_MNEMONIC;
918 0 : if ( pSWindow == ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd ) )
919 0 : nGetFocusFlags |= GETFOCUS_UNIQUEMNEMONIC;
920 0 : pSWindow->ImplControlFocus( nGetFocusFlags );
921 0 : return true;
922 : }
923 : }
924 : }
925 : }
926 :
927 0 : if (isSuitableDestination(pButtonWindow))
928 : {
929 0 : if ( bKeyInput )
930 : {
931 0 : if ( mpWindowImpl->mpDlgCtrlDownWindow && (mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow) )
932 : {
933 0 : static_cast<PushButton*>(mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( false );
934 0 : mpWindowImpl->mpDlgCtrlDownWindow = NULL;
935 : }
936 :
937 0 : static_cast<PushButton*>(pButtonWindow)->SetPressed( true );
938 0 : mpWindowImpl->mpDlgCtrlDownWindow = pButtonWindow;
939 : }
940 0 : else if ( mpWindowImpl->mpDlgCtrlDownWindow == pButtonWindow )
941 : {
942 0 : mpWindowImpl->mpDlgCtrlDownWindow = NULL;
943 0 : static_cast<PushButton*>(pButtonWindow)->SetPressed( false );
944 0 : static_cast<PushButton*>(pButtonWindow)->Click();
945 : }
946 :
947 0 : return true;
948 : }
949 :
950 0 : return false;
951 : }
952 :
953 : // checks if this window has dialog control
954 0 : bool Window::ImplHasDlgCtrl()
955 : {
956 : vcl::Window* pDlgCtrlParent;
957 :
958 : // lookup window for dialog control
959 0 : pDlgCtrlParent = ImplGetParent();
960 0 : while ( pDlgCtrlParent &&
961 0 : !pDlgCtrlParent->ImplIsOverlapWindow() &&
962 0 : ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
963 0 : pDlgCtrlParent = pDlgCtrlParent->ImplGetParent();
964 :
965 0 : if ( !pDlgCtrlParent || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
966 0 : return false;
967 : else
968 0 : return true;
969 : }
970 :
971 1028 : void Window::ImplDlgCtrlNextWindow()
972 : {
973 : vcl::Window* pDlgCtrlParent;
974 : vcl::Window* pDlgCtrl;
975 : vcl::Window* pSWindow;
976 : sal_uInt16 nIndex;
977 : sal_uInt16 nFormStart;
978 : sal_uInt16 nFormEnd;
979 :
980 : // lookup window for dialog control
981 1028 : pDlgCtrl = this;
982 1028 : pDlgCtrlParent = ImplGetParent();
983 11308 : while ( pDlgCtrlParent &&
984 9252 : !pDlgCtrlParent->ImplIsOverlapWindow() &&
985 4112 : ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
986 4112 : pDlgCtrlParent = pDlgCtrlParent->ImplGetParent();
987 :
988 1028 : if ( !pDlgCtrlParent || (GetStyle() & WB_NODIALOGCONTROL) || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
989 2056 : return;
990 :
991 : // lookup window in child list
992 : pSWindow = ::ImplFindDlgCtrlWindow( pDlgCtrlParent, pDlgCtrl,
993 0 : nIndex, nFormStart, nFormEnd );
994 0 : if ( !pSWindow )
995 0 : return;
996 :
997 0 : vcl::Window* pWindow = pDlgCtrlParent->ImplGetDlgWindow( nIndex, DLGWINDOW_NEXT, nFormStart, nFormEnd );
998 0 : if ( pWindow && (pWindow != pSWindow) )
999 0 : pWindow->ImplControlFocus();
1000 : }
1001 :
1002 13694 : static void ImplDlgCtrlUpdateDefButton( vcl::Window* pParent, vcl::Window* pFocusWindow,
1003 : bool bGetFocus )
1004 : {
1005 13694 : PushButton* pOldDefButton = NULL;
1006 13694 : PushButton* pNewDefButton = NULL;
1007 : vcl::Window* pSWindow;
1008 : sal_uInt16 i;
1009 : sal_uInt16 nFormStart;
1010 : sal_uInt16 nFormEnd;
1011 :
1012 : // find template
1013 13694 : pSWindow = ::ImplFindDlgCtrlWindow( pParent, pFocusWindow, i, nFormStart, nFormEnd );
1014 13694 : if ( !pSWindow )
1015 : {
1016 12962 : nFormStart = 0;
1017 12962 : nFormEnd = 0xFFFF;
1018 : }
1019 :
1020 13694 : pSWindow = ImplGetChildWindow( pParent, nFormStart, i, false );
1021 38162 : while ( pSWindow )
1022 : {
1023 10774 : if ( pSWindow->ImplIsPushButton() )
1024 : {
1025 622 : PushButton* pPushButton = static_cast<PushButton*>(pSWindow);
1026 622 : if ( pPushButton->ImplIsDefButton() )
1027 6 : pOldDefButton = pPushButton;
1028 622 : if ( pPushButton->HasChildPathFocus() )
1029 6 : pNewDefButton = pPushButton;
1030 616 : else if ( !pNewDefButton && (pPushButton->GetStyle() & WB_DEFBUTTON) )
1031 0 : pNewDefButton = pPushButton;
1032 : }
1033 :
1034 10774 : pSWindow = ImplGetNextWindow( pParent, i, i, false );
1035 10774 : if ( !i || (i > nFormEnd) )
1036 3237 : pSWindow = NULL;
1037 : }
1038 :
1039 13694 : if ( !bGetFocus )
1040 : {
1041 : sal_uInt16 nDummy;
1042 6999 : vcl::Window* pNewFocusWindow = Application::GetFocusWindow();
1043 6999 : if ( !pNewFocusWindow || !pParent->ImplIsWindowOrChild( pNewFocusWindow ) )
1044 5333 : pNewDefButton = NULL;
1045 3722 : else if ( !::ImplFindDlgCtrlWindow( pParent, pNewFocusWindow, i, nDummy, nDummy ) ||
1046 2056 : (i < nFormStart) || (i > nFormEnd) )
1047 1276 : pNewDefButton = NULL;
1048 : }
1049 :
1050 13694 : if ( pOldDefButton != pNewDefButton )
1051 : {
1052 8 : if ( pOldDefButton )
1053 4 : pOldDefButton->ImplSetDefButton( false );
1054 8 : if ( pNewDefButton )
1055 4 : pNewDefButton->ImplSetDefButton( true );
1056 : }
1057 13694 : }
1058 :
1059 13694 : void Window::ImplDlgCtrlFocusChanged( vcl::Window* pWindow, bool bGetFocus )
1060 : {
1061 13694 : if ( mpWindowImpl->mpDlgCtrlDownWindow && !bGetFocus )
1062 : {
1063 0 : static_cast<PushButton*>(mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( false );
1064 0 : mpWindowImpl->mpDlgCtrlDownWindow = NULL;
1065 : }
1066 :
1067 13694 : ImplDlgCtrlUpdateDefButton( this, pWindow, bGetFocus );
1068 13694 : }
1069 :
1070 0 : vcl::Window* Window::ImplFindDlgCtrlWindow( vcl::Window* pWindow )
1071 : {
1072 : sal_uInt16 nIndex;
1073 : sal_uInt16 nFormStart;
1074 : sal_uInt16 nFormEnd;
1075 :
1076 : // find Focus-Window in the Child-List and return
1077 0 : return ::ImplFindDlgCtrlWindow( this, pWindow, nIndex, nFormStart, nFormEnd );
1078 : }
1079 :
1080 2 : vcl::Window* Window::GetParentLabelFor( const vcl::Window* ) const
1081 : {
1082 2 : return NULL;
1083 : }
1084 :
1085 6044 : vcl::Window* Window::GetParentLabeledBy( const vcl::Window* ) const
1086 : {
1087 6044 : return NULL;
1088 : }
1089 :
1090 0 : KeyEvent Window::GetActivationKey() const
1091 : {
1092 0 : KeyEvent aKeyEvent;
1093 :
1094 0 : sal_Unicode nAccel = getAccel( GetText() );
1095 0 : if( ! nAccel )
1096 : {
1097 0 : vcl::Window* pWindow = GetAccessibleRelationLabeledBy();
1098 0 : if( pWindow )
1099 0 : nAccel = getAccel( pWindow->GetText() );
1100 : }
1101 0 : if( nAccel )
1102 : {
1103 0 : sal_uInt16 nCode = 0;
1104 0 : if( nAccel >= 'a' && nAccel <= 'z' )
1105 0 : nCode = KEY_A + (nAccel-'a');
1106 0 : else if( nAccel >= 'A' && nAccel <= 'Z' )
1107 0 : nCode = KEY_A + (nAccel-'A');
1108 0 : else if( nAccel >= '0' && nAccel <= '9' )
1109 0 : nCode = KEY_0 + (nAccel-'0');
1110 0 : else if( nAccel == '.' )
1111 0 : nCode = KEY_POINT;
1112 0 : else if( nAccel == '-' )
1113 0 : nCode = KEY_SUBTRACT;
1114 0 : vcl::KeyCode aKeyCode( nCode, false, false, true, false );
1115 0 : aKeyEvent = KeyEvent( nAccel, aKeyCode );
1116 : }
1117 0 : return aKeyEvent;
1118 : }
1119 :
1120 : } /* namespace vcl */
1121 :
1122 2 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */sal_Unicode getAccel( const OUString& rStr )
1123 : {
1124 2 : sal_Unicode nChar = 0;
1125 2 : sal_Int32 nPos = 0;
1126 2 : do
1127 : {
1128 2 : nPos = rStr.indexOf( '~', nPos );
1129 2 : if( nPos != -1 && nPos < rStr.getLength() )
1130 0 : nChar = rStr[ ++nPos ];
1131 : else
1132 2 : nChar = 0;
1133 : } while( nChar == '~' );
1134 2 : return nChar;
1135 1233 : }
1136 :
1137 :
|