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