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 :
21 : #include <tools/rcid.h>
22 :
23 : #include <vcl/dockwin.hxx>
24 : #include <vcl/taskpanelist.hxx>
25 :
26 : #include <svdata.hxx>
27 :
28 : #include <functional>
29 : #include <algorithm>
30 :
31 : // can't have static linkage because SUNPRO 5.2 complains
32 0 : Point ImplTaskPaneListGetPos( const Window *w )
33 : {
34 0 : Point pos;
35 0 : if( w->ImplIsDockingWindow() )
36 : {
37 0 : pos = ((DockingWindow*)w)->GetPosPixel();
38 0 : Window *pF = ((DockingWindow*)w)->GetFloatingWindow();
39 0 : if( pF )
40 0 : pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) );
41 : else
42 0 : pos = w->OutputToAbsoluteScreenPixel( pos );
43 : }
44 : else
45 0 : pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() );
46 :
47 0 : return pos;
48 : }
49 :
50 : // compares window pos left-to-right
51 : struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool >
52 : {
53 0 : bool operator()( const Window* w1, const Window* w2 ) const
54 : {
55 0 : Point pos1(ImplTaskPaneListGetPos( w1 ));
56 0 : Point pos2(ImplTaskPaneListGetPos( w2 ));
57 :
58 0 : if( pos1.X() == pos2.X() )
59 0 : return ( pos1.Y() < pos2.Y() );
60 : else
61 0 : return ( pos1.X() < pos2.X() );
62 : }
63 : };
64 : struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool >
65 : {
66 0 : bool operator()( const Window* w2, const Window* w1 ) const
67 : {
68 0 : Point pos1(ImplTaskPaneListGetPos( w1 ));
69 0 : Point pos2(ImplTaskPaneListGetPos( w2 ));
70 :
71 0 : if( pos1.X() == pos2.X() )
72 0 : return ( pos1.Y() < pos2.Y() );
73 : else
74 0 : return ( pos1.X() < pos2.X() );
75 : }
76 : };
77 :
78 : // --------------------------------------------------
79 :
80 0 : static void ImplTaskPaneListGrabFocus( Window *pWindow )
81 : {
82 : // put focus in child of floating windows which is typically a toolbar
83 : // that can deal with the focus
84 0 : if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) )
85 0 : pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD );
86 0 : pWindow->GrabFocus();
87 0 : }
88 :
89 : // --------------------------------------------------
90 :
91 236 : TaskPaneList::TaskPaneList()
92 : {
93 236 : }
94 :
95 63 : TaskPaneList::~TaskPaneList()
96 : {
97 63 : }
98 :
99 : // --------------------------------------------------
100 :
101 1203 : void TaskPaneList::AddWindow( Window *pWindow )
102 : {
103 1203 : if( pWindow )
104 : {
105 1203 : ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end();
106 11037 : for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin();
107 7358 : p != mTaskPanes.end();
108 : ++p
109 : )
110 : {
111 2476 : if ( *p == pWindow )
112 : // avoid duplicates
113 1203 : return;
114 :
115 : // If the new window is the child of an existing pane window, or vice versa,
116 : // ensure that in our pane list, *first* the child window appears, *then*
117 : // the ancestor window.
118 : // This is necessary for HandleKeyEvent: There, the list is traveled from the
119 : // beginning, until the first window is found which has the ChildPathFocus. Now
120 : // if this would be the ancestor window of another pane window, this would fudge
121 : // the result
122 2476 : if ( pWindow->IsWindowOrChild( *p ) )
123 : {
124 0 : insertionPos = p + 1;
125 0 : break;
126 : }
127 2476 : if ( (*p)->IsWindowOrChild( pWindow ) )
128 : {
129 0 : insertionPos = p;
130 0 : break;
131 : }
132 : }
133 :
134 1203 : mTaskPanes.insert( insertionPos, pWindow );
135 1203 : pWindow->ImplIsInTaskPaneList( sal_True );
136 : }
137 : }
138 :
139 : // --------------------------------------------------
140 :
141 316 : void TaskPaneList::RemoveWindow( Window *pWindow )
142 : {
143 316 : ::std::vector< Window* >::iterator p;
144 316 : p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
145 316 : if( p != mTaskPanes.end() )
146 : {
147 316 : mTaskPanes.erase( p );
148 316 : pWindow->ImplIsInTaskPaneList( sal_False );
149 : }
150 316 : }
151 :
152 : // --------------------------------------------------
153 :
154 385 : sal_Bool TaskPaneList::IsInList( Window *pWindow )
155 : {
156 385 : ::std::vector< Window* >::iterator p;
157 385 : p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
158 385 : if( p != mTaskPanes.end() )
159 385 : return sal_True;
160 : else
161 0 : return sal_False;
162 : }
163 :
164 : // --------------------------------------------------
165 :
166 0 : sal_Bool TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent )
167 : {
168 :
169 : // F6 cycles through everything and works always
170 :
171 : // MAV, #i104204#
172 : // The old design was the following one:
173 : // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is
174 : // < only active if one of those items has the focus
175 : //
176 : // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable
177 : // and the shortcut conflicts with tab-control shortcut ), it is no more supported
178 0 : sal_Bool bSplitterOnly = sal_False;
179 0 : sal_Bool bFocusInList = sal_False;
180 0 : KeyCode aKeyCode = aKeyEvent.GetKeyCode();
181 0 : sal_Bool bForward = !aKeyCode.IsShift();
182 0 : if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6
183 : {
184 0 : bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
185 :
186 : // is the focus in the list ?
187 0 : ::std::vector< Window* >::iterator p = mTaskPanes.begin();
188 0 : while( p != mTaskPanes.end() )
189 : {
190 0 : Window *pWin = *p;
191 0 : if( pWin->HasChildPathFocus( sal_True ) )
192 : {
193 0 : bFocusInList = sal_True;
194 :
195 : // Ctrl-F6 goes directly to the document
196 0 : if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() )
197 : {
198 0 : pWin->GrabFocusToDocument();
199 0 : return sal_True;
200 : }
201 :
202 : // activate next task pane
203 0 : Window *pNextWin = NULL;
204 :
205 0 : if( bSplitterOnly )
206 0 : pNextWin = FindNextSplitter( *p, sal_True );
207 : else
208 0 : pNextWin = FindNextFloat( *p, bForward );
209 :
210 0 : if( pNextWin != pWin )
211 : {
212 0 : ImplGetSVData()->maWinData.mbNoSaveFocus = sal_True;
213 0 : ImplTaskPaneListGrabFocus( pNextWin );
214 0 : ImplGetSVData()->maWinData.mbNoSaveFocus = sal_False;
215 : }
216 : else
217 : {
218 : // forward key if no splitter found
219 0 : if( bSplitterOnly )
220 0 : return sal_False;
221 :
222 : // we did not find another taskpane, so
223 : // put focus back into document
224 0 : pWin->GrabFocusToDocument();
225 : }
226 :
227 0 : return sal_True;
228 : }
229 : else
230 0 : ++p;
231 : }
232 :
233 : // the focus is not in the list: activate first float if F6 was pressed
234 0 : if( !bFocusInList )
235 : {
236 : Window *pWin;
237 0 : if( bSplitterOnly )
238 0 : pWin = FindNextSplitter( NULL, sal_True );
239 : else
240 0 : pWin = FindNextFloat( NULL, bForward );
241 0 : if( pWin )
242 : {
243 0 : ImplTaskPaneListGrabFocus( pWin );
244 0 : return sal_True;
245 : }
246 : }
247 : }
248 :
249 0 : return sal_False;
250 : }
251 :
252 : // --------------------------------------------------
253 :
254 : // returns next splitter
255 0 : Window* TaskPaneList::FindNextSplitter( Window *pWindow, sal_Bool bForward )
256 : {
257 0 : if( bForward )
258 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
259 : else
260 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
261 :
262 0 : ::std::vector< Window* >::iterator p = mTaskPanes.begin();
263 0 : while( p != mTaskPanes.end() )
264 : {
265 0 : if( !pWindow || *p == pWindow )
266 : {
267 0 : unsigned n = mTaskPanes.size();
268 0 : while( --n )
269 : {
270 0 : if( pWindow ) // increment before test
271 0 : ++p;
272 0 : if( p == mTaskPanes.end() )
273 0 : p = mTaskPanes.begin();
274 0 : if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() )
275 : {
276 0 : pWindow = *p;
277 0 : break;
278 : }
279 0 : if( !pWindow ) // increment after test, otherwise first element is skipped
280 0 : ++p;
281 : }
282 0 : break;
283 : }
284 : else
285 0 : ++p;
286 : }
287 :
288 0 : return pWindow;
289 : }
290 :
291 : // --------------------------------------------------
292 :
293 : // returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float
294 0 : Window* TaskPaneList::FindNextFloat( Window *pWindow, sal_Bool bForward )
295 : {
296 0 : if( bForward )
297 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
298 : else
299 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
300 :
301 0 : ::std::vector< Window* >::iterator p = mTaskPanes.begin();
302 0 : while( p != mTaskPanes.end() )
303 : {
304 0 : if( !pWindow || *p == pWindow )
305 : {
306 0 : while( p != mTaskPanes.end() )
307 : {
308 0 : if( pWindow ) // increment before test
309 0 : ++p;
310 0 : if( p == mTaskPanes.end() )
311 0 : break; // do not wrap, send focus back to document at end of list
312 : /* #i83908# do not use the menubar if it is native and invisible
313 : this relies on MenuBar::ImplCreate setting the height of the menubar
314 : to 0 in this case
315 : */
316 0 : if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() &&
317 0 : ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 )
318 : )
319 : {
320 0 : pWindow = *p;
321 0 : break;
322 : }
323 0 : if( !pWindow ) // increment after test, otherwise first element is skipped
324 0 : ++p;
325 : }
326 0 : break;
327 : }
328 : else
329 0 : ++p;
330 : }
331 :
332 0 : return pWindow;
333 : }
334 :
335 : // --------------------------------------------------
336 :
337 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|