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