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