xref: /trunk/main/vcl/source/window/taskpanelist.cxx (revision 9f62ea84)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <tools/rcid.h>
28 
29 #include <vcl/dockwin.hxx>
30 #include <vcl/taskpanelist.hxx>
31 
32 #include <svdata.hxx>
33 
34 #include <functional>
35 #include <algorithm>
36 
37 // can't have static linkage because SUNPRO 5.2 complains
ImplTaskPaneListGetPos(const Window * w)38 Point ImplTaskPaneListGetPos( const Window *w )
39 {
40     Point pos;
41 	if( w->ImplIsDockingWindow() )
42     {
43         pos = ((DockingWindow*)w)->GetPosPixel();
44         Window *pF = ((DockingWindow*)w)->GetFloatingWindow();
45         if( pF )
46             pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) );
47         else
48             pos = w->OutputToAbsoluteScreenPixel( pos );
49     }
50     else
51         pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() );
52 
53     return pos;
54 }
55 
56 // compares window pos left-to-right
57 struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool >
58 {
operator ()LTRSort59     bool operator()( const Window* w1, const Window* w2 ) const
60     {
61         Point pos1(ImplTaskPaneListGetPos( w1 ));
62         Point pos2(ImplTaskPaneListGetPos( w2 ));
63 
64         if( pos1.X() == pos2.X() )
65             return ( pos1.Y() < pos2.Y() );
66         else
67             return ( pos1.X() < pos2.X() );
68     }
69 };
70 struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool >
71 {
operator ()LTRSortBackward72     bool operator()( const Window* w2, const Window* w1 ) const
73     {
74         Point pos1(ImplTaskPaneListGetPos( w1 ));
75         Point pos2(ImplTaskPaneListGetPos( w2 ));
76 
77         if( pos1.X() == pos2.X() )
78             return ( pos1.Y() < pos2.Y() );
79         else
80             return ( pos1.X() < pos2.X() );
81     }
82 };
83 
84 // --------------------------------------------------
85 
ImplTaskPaneListGrabFocus(Window * pWindow)86 static void ImplTaskPaneListGrabFocus( Window *pWindow )
87 {
88 	// put focus in child of floating windows which is typically a toolbar
89 	// that can deal with the focus
90 	if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) )
91 		pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD );
92 	pWindow->GrabFocus();
93 }
94 
95 // --------------------------------------------------
96 
TaskPaneList()97 TaskPaneList::TaskPaneList()
98 {
99 }
100 
~TaskPaneList()101 TaskPaneList::~TaskPaneList()
102 {
103 }
104 
105 // --------------------------------------------------
106 
AddWindow(Window * pWindow)107 void TaskPaneList::AddWindow( Window *pWindow )
108 {
109 #if OSL_DEBUG_LEVEL > 0
110     bool bDockingWindow=false;
111     bool bToolbox=false;
112     bool bDialog=false;
113     bool bUnknown=false;
114 #endif
115 
116     if( pWindow )
117     {
118 #if OSL_DEBUG_LEVEL > 0
119         if( pWindow->GetType() == RSC_DOCKINGWINDOW )
120             bDockingWindow = true;
121         else if( pWindow->GetType() == RSC_TOOLBOX )
122             bToolbox = true;
123         else if( pWindow->IsDialog() )
124             bDialog = true;
125         else
126             bUnknown = true;
127 #endif
128 
129         ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end();
130         for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin();
131               p != mTaskPanes.end();
132               ++p
133             )
134         {
135             if ( *p == pWindow )
136                 // avoid duplicates
137                 return;
138 
139             // If the new window is the child of an existing pane window, or vice versa,
140             // ensure that in our pane list, *first* the child window appears, *then*
141             // the ancestor window.
142             // This is necessary for HandleKeyEvent: There, the list is traveled from the
143             // beginning, until the first window is found which has the ChildPathFocus. Now
144             // if this would be the ancestor window of another pane window, this would fudge
145             // the result
146             // 2004-09-27 - fs@openoffice.org, while fixing #i33573#, which included replacing
147             // the original fix for #98916# with this one here.
148             if ( pWindow->IsWindowOrChild( *p ) )
149             {
150                 insertionPos = p + 1;
151                 break;
152             }
153             if ( (*p)->IsWindowOrChild( pWindow ) )
154             {
155                 insertionPos = p;
156                 break;
157             }
158         }
159 
160         mTaskPanes.insert( insertionPos, pWindow );
161         pWindow->ImplIsInTaskPaneList( sal_True );
162     }
163 }
164 
165 // --------------------------------------------------
166 
RemoveWindow(Window * pWindow)167 void TaskPaneList::RemoveWindow( Window *pWindow )
168 {
169 	::std::vector< Window* >::iterator p;
170     p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
171     if( p != mTaskPanes.end() )
172     {
173 	    mTaskPanes.erase( p );
174         pWindow->ImplIsInTaskPaneList( sal_False );
175     }
176 }
177 
178 // --------------------------------------------------
179 
IsInList(Window * pWindow)180 sal_Bool TaskPaneList::IsInList( Window *pWindow )
181 {
182 	::std::vector< Window* >::iterator p;
183     p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
184     if( p != mTaskPanes.end() )
185 	    return sal_True;
186     else
187         return sal_False;
188 }
189 
190 // --------------------------------------------------
191 
HandleKeyEvent(KeyEvent aKeyEvent)192 sal_Bool TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent )
193 {
194 
195     // F6 cycles through everything and works always
196 
197     // MAV, #i104204#
198     // The old design was the following one:
199     // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is
200     // < only active if one of those items has the focus
201     //
202     // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable
203     // and the shortcut conflicts with tab-control shortcut ), it is no more supported
204     sal_Bool bSplitterOnly = sal_False;
205     sal_Bool bFocusInList = sal_False;
206 	KeyCode aKeyCode = aKeyEvent.GetKeyCode();
207     sal_Bool bForward = !aKeyCode.IsShift();
208 	if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6
209 	{
210         bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
211 
212 		// is the focus in the list ?
213 		::std::vector< Window* >::iterator p = mTaskPanes.begin();
214 		while( p != mTaskPanes.end() )
215         {
216             Window *pWin = *p;
217 			if( pWin->HasChildPathFocus( sal_True ) )
218 			{
219                 bFocusInList = sal_True;
220 
221                 // Ctrl-F6 goes directly to the document
222                 if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() )
223                 {
224 		            pWin->GrabFocusToDocument();
225 		            return sal_True;
226                 }
227 
228 				// activate next task pane
229                 Window *pNextWin = NULL;
230 
231                 if( bSplitterOnly )
232                     pNextWin = FindNextSplitter( *p, sal_True );
233                 else
234                     pNextWin = FindNextFloat( *p, bForward );
235 
236 				if( pNextWin != pWin )
237 				{
238 					ImplGetSVData()->maWinData.mbNoSaveFocus = sal_True;
239 					ImplTaskPaneListGrabFocus( pNextWin );
240 					ImplGetSVData()->maWinData.mbNoSaveFocus = sal_False;
241 				}
242                 else
243                 {
244                     // forward key if no splitter found
245                     if( bSplitterOnly )
246                         return sal_False;
247 
248                     // we did not find another taskpane, so
249                     // put focus back into document
250                     pWin->GrabFocusToDocument();
251                 }
252 
253 				return sal_True;
254 			}
255 			else
256 				p++;
257         }
258 
259         // the focus is not in the list: activate first float if F6 was pressed
260         if( !bFocusInList )
261         {
262             Window *pWin;
263             if( bSplitterOnly )
264                 pWin = FindNextSplitter( NULL, sal_True );
265             else
266                 pWin = FindNextFloat( NULL, bForward );
267             if( pWin )
268             {
269 				ImplTaskPaneListGrabFocus( pWin );
270                 return sal_True;
271             }
272         }
273 	}
274 
275 	return sal_False;
276 }
277 
278 // --------------------------------------------------
279 
280 //  returns next valid pane
FindNextPane(Window * pWindow,sal_Bool bForward)281 Window* TaskPaneList::FindNextPane( Window *pWindow, sal_Bool bForward )
282 {
283     if( bForward )
284         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
285     else
286         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
287 
288 	::std::vector< Window* >::iterator p = mTaskPanes.begin();
289 	while( p != mTaskPanes.end() )
290     {
291         if( *p == pWindow )
292         {
293             unsigned n = mTaskPanes.size();
294             while( --n )
295             {
296 		        if( ++p == mTaskPanes.end() )
297 			        p = mTaskPanes.begin();
298                 if( (*p)->IsReallyVisible() && !(*p)->IsDialog() && !(*p)->ImplIsSplitter() )
299 				{
300 					pWindow = *p;
301 					break;
302 				}
303             }
304             break;
305         }
306         else
307             ++p;
308     }
309 
310 	return pWindow;
311 }
312 
313 // --------------------------------------------------
314 
315 // returns next splitter
FindNextSplitter(Window * pWindow,sal_Bool bForward)316 Window* TaskPaneList::FindNextSplitter( Window *pWindow, sal_Bool bForward )
317 {
318     if( bForward )
319         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
320     else
321         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
322 
323 	::std::vector< Window* >::iterator p = mTaskPanes.begin();
324 	while( p != mTaskPanes.end() )
325     {
326         if( !pWindow || *p == pWindow )
327         {
328             unsigned n = mTaskPanes.size();
329             while( --n )
330             {
331                 if( pWindow )   // increment before test
332                     ++p;
333 		        if( p == mTaskPanes.end() )
334 			        p = mTaskPanes.begin();
335                 if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() )
336 				{
337 					pWindow = *p;
338 					break;
339 				}
340                 if( !pWindow )  // increment after test, otherwise first element is skipped
341                     ++p;
342             }
343             break;
344         }
345         else
346             ++p;
347     }
348 
349 	return pWindow;
350 }
351 
352 // --------------------------------------------------
353 
354 // returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float
FindNextFloat(Window * pWindow,sal_Bool bForward)355 Window* TaskPaneList::FindNextFloat( Window *pWindow, sal_Bool bForward )
356 {
357     if( bForward )
358         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
359     else
360         ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
361 
362 	::std::vector< Window* >::iterator p = mTaskPanes.begin();
363 	while( p != mTaskPanes.end() )
364     {
365         if( !pWindow || *p == pWindow )
366         {
367             while( p != mTaskPanes.end() )
368             {
369                 if( pWindow )   // increment before test
370                     ++p;
371 		        if( p == mTaskPanes.end() )
372 			        break; // do not wrap, send focus back to document at end of list
373                 /* #i83908# do not use the menubar if it is native and invisible
374                    this relies on MenuBar::ImplCreate setting the height of the menubar
375                    to 0 in this case
376                 */
377                 if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() &&
378                     ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 )
379                     )
380 				{
381                     pWindow = *p;
382 					break;
383 				}
384                 if( !pWindow )  // increment after test, otherwise first element is skipped
385                     ++p;
386             }
387             break;
388         }
389         else
390             ++p;
391     }
392 
393 	return pWindow;
394 }
395 
396 // --------------------------------------------------
397 
398