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