| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <tools/rcid.h> |
| |
| #include <vcl/dockwin.hxx> |
| #include <vcl/taskpanelist.hxx> |
| |
| #include <svdata.hxx> |
| |
| #include <functional> |
| #include <algorithm> |
| |
| // can't have static linkage because SUNPRO 5.2 complains |
| Point ImplTaskPaneListGetPos( const Window *w ) |
| { |
| Point pos; |
| if( w->ImplIsDockingWindow() ) |
| { |
| pos = ((DockingWindow*)w)->GetPosPixel(); |
| Window *pF = ((DockingWindow*)w)->GetFloatingWindow(); |
| if( pF ) |
| pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) ); |
| else |
| pos = w->OutputToAbsoluteScreenPixel( pos ); |
| } |
| else |
| pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() ); |
| |
| return pos; |
| } |
| |
| // compares window pos left-to-right |
| struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool > |
| { |
| bool operator()( const Window* w1, const Window* w2 ) const |
| { |
| Point pos1(ImplTaskPaneListGetPos( w1 )); |
| Point pos2(ImplTaskPaneListGetPos( w2 )); |
| |
| if( pos1.X() == pos2.X() ) |
| return ( pos1.Y() < pos2.Y() ); |
| else |
| return ( pos1.X() < pos2.X() ); |
| } |
| }; |
| struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool > |
| { |
| bool operator()( const Window* w2, const Window* w1 ) const |
| { |
| Point pos1(ImplTaskPaneListGetPos( w1 )); |
| Point pos2(ImplTaskPaneListGetPos( w2 )); |
| |
| if( pos1.X() == pos2.X() ) |
| return ( pos1.Y() < pos2.Y() ); |
| else |
| return ( pos1.X() < pos2.X() ); |
| } |
| }; |
| |
| // -------------------------------------------------- |
| |
| static void ImplTaskPaneListGrabFocus( Window *pWindow ) |
| { |
| // put focus in child of floating windows which is typically a toolbar |
| // that can deal with the focus |
| if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) ) |
| pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD ); |
| pWindow->GrabFocus(); |
| } |
| |
| // -------------------------------------------------- |
| |
| TaskPaneList::TaskPaneList() |
| { |
| } |
| |
| TaskPaneList::~TaskPaneList() |
| { |
| } |
| |
| // -------------------------------------------------- |
| |
| void TaskPaneList::AddWindow( Window *pWindow ) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| bool bDockingWindow=false; |
| bool bToolbox=false; |
| bool bDialog=false; |
| bool bUnknown=false; |
| #endif |
| |
| if( pWindow ) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| if( pWindow->GetType() == RSC_DOCKINGWINDOW ) |
| bDockingWindow = true; |
| else if( pWindow->GetType() == RSC_TOOLBOX ) |
| bToolbox = true; |
| else if( pWindow->IsDialog() ) |
| bDialog = true; |
| else |
| bUnknown = true; |
| #endif |
| |
| ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end(); |
| for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin(); |
| p != mTaskPanes.end(); |
| ++p |
| ) |
| { |
| if ( *p == pWindow ) |
| // avoid duplicates |
| return; |
| |
| // If the new window is the child of an existing pane window, or vice versa, |
| // ensure that in our pane list, *first* the child window appears, *then* |
| // the ancestor window. |
| // This is necessary for HandleKeyEvent: There, the list is traveled from the |
| // beginning, until the first window is found which has the ChildPathFocus. Now |
| // if this would be the ancestor window of another pane window, this would fudge |
| // the result |
| // 2004-09-27 - fs@openoffice.org, while fixing #i33573#, which included replacing |
| // the original fix for #98916# with this one here. |
| if ( pWindow->IsWindowOrChild( *p ) ) |
| { |
| insertionPos = p + 1; |
| break; |
| } |
| if ( (*p)->IsWindowOrChild( pWindow ) ) |
| { |
| insertionPos = p; |
| break; |
| } |
| } |
| |
| mTaskPanes.insert( insertionPos, pWindow ); |
| pWindow->ImplIsInTaskPaneList( sal_True ); |
| } |
| } |
| |
| // -------------------------------------------------- |
| |
| void TaskPaneList::RemoveWindow( Window *pWindow ) |
| { |
| ::std::vector< Window* >::iterator p; |
| p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); |
| if( p != mTaskPanes.end() ) |
| { |
| mTaskPanes.erase( p ); |
| pWindow->ImplIsInTaskPaneList( sal_False ); |
| } |
| } |
| |
| // -------------------------------------------------- |
| |
| sal_Bool TaskPaneList::IsInList( Window *pWindow ) |
| { |
| ::std::vector< Window* >::iterator p; |
| p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); |
| if( p != mTaskPanes.end() ) |
| return sal_True; |
| else |
| return sal_False; |
| } |
| |
| // -------------------------------------------------- |
| |
| sal_Bool TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent ) |
| { |
| |
| // F6 cycles through everything and works always |
| |
| // MAV, #i104204# |
| // The old design was the following one: |
| // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is |
| // < only active if one of those items has the focus |
| // |
| // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable |
| // and the shortcut conflicts with tab-control shortcut ), it is no more supported |
| sal_Bool bSplitterOnly = sal_False; |
| sal_Bool bFocusInList = sal_False; |
| KeyCode aKeyCode = aKeyEvent.GetKeyCode(); |
| sal_Bool bForward = !aKeyCode.IsShift(); |
| if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6 |
| { |
| bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift(); |
| |
| // is the focus in the list ? |
| ::std::vector< Window* >::iterator p = mTaskPanes.begin(); |
| while( p != mTaskPanes.end() ) |
| { |
| Window *pWin = *p; |
| if( pWin->HasChildPathFocus( sal_True ) ) |
| { |
| bFocusInList = sal_True; |
| |
| // Ctrl-F6 goes directly to the document |
| if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() ) |
| { |
| pWin->GrabFocusToDocument(); |
| return sal_True; |
| } |
| |
| // activate next task pane |
| Window *pNextWin = NULL; |
| |
| if( bSplitterOnly ) |
| pNextWin = FindNextSplitter( *p, sal_True ); |
| else |
| pNextWin = FindNextFloat( *p, bForward ); |
| |
| if( pNextWin != pWin ) |
| { |
| ImplGetSVData()->maWinData.mbNoSaveFocus = sal_True; |
| ImplTaskPaneListGrabFocus( pNextWin ); |
| ImplGetSVData()->maWinData.mbNoSaveFocus = sal_False; |
| } |
| else |
| { |
| // forward key if no splitter found |
| if( bSplitterOnly ) |
| return sal_False; |
| |
| // we did not find another taskpane, so |
| // put focus back into document |
| pWin->GrabFocusToDocument(); |
| } |
| |
| return sal_True; |
| } |
| else |
| p++; |
| } |
| |
| // the focus is not in the list: activate first float if F6 was pressed |
| if( !bFocusInList ) |
| { |
| Window *pWin; |
| if( bSplitterOnly ) |
| pWin = FindNextSplitter( NULL, sal_True ); |
| else |
| pWin = FindNextFloat( NULL, bForward ); |
| if( pWin ) |
| { |
| ImplTaskPaneListGrabFocus( pWin ); |
| return sal_True; |
| } |
| } |
| } |
| |
| return sal_False; |
| } |
| |
| // -------------------------------------------------- |
| |
| // returns next valid pane |
| Window* TaskPaneList::FindNextPane( Window *pWindow, sal_Bool bForward ) |
| { |
| if( bForward ) |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); |
| else |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); |
| |
| ::std::vector< Window* >::iterator p = mTaskPanes.begin(); |
| while( p != mTaskPanes.end() ) |
| { |
| if( *p == pWindow ) |
| { |
| unsigned n = mTaskPanes.size(); |
| while( --n ) |
| { |
| if( ++p == mTaskPanes.end() ) |
| p = mTaskPanes.begin(); |
| if( (*p)->IsReallyVisible() && !(*p)->IsDialog() && !(*p)->ImplIsSplitter() ) |
| { |
| pWindow = *p; |
| break; |
| } |
| } |
| break; |
| } |
| else |
| ++p; |
| } |
| |
| return pWindow; |
| } |
| |
| // -------------------------------------------------- |
| |
| // returns next splitter |
| Window* TaskPaneList::FindNextSplitter( Window *pWindow, sal_Bool bForward ) |
| { |
| if( bForward ) |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); |
| else |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); |
| |
| ::std::vector< Window* >::iterator p = mTaskPanes.begin(); |
| while( p != mTaskPanes.end() ) |
| { |
| if( !pWindow || *p == pWindow ) |
| { |
| unsigned n = mTaskPanes.size(); |
| while( --n ) |
| { |
| if( pWindow ) // increment before test |
| ++p; |
| if( p == mTaskPanes.end() ) |
| p = mTaskPanes.begin(); |
| if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() ) |
| { |
| pWindow = *p; |
| break; |
| } |
| if( !pWindow ) // increment after test, otherwise first element is skipped |
| ++p; |
| } |
| break; |
| } |
| else |
| ++p; |
| } |
| |
| return pWindow; |
| } |
| |
| // -------------------------------------------------- |
| |
| // returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float |
| Window* TaskPaneList::FindNextFloat( Window *pWindow, sal_Bool bForward ) |
| { |
| if( bForward ) |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); |
| else |
| ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); |
| |
| ::std::vector< Window* >::iterator p = mTaskPanes.begin(); |
| while( p != mTaskPanes.end() ) |
| { |
| if( !pWindow || *p == pWindow ) |
| { |
| while( p != mTaskPanes.end() ) |
| { |
| if( pWindow ) // increment before test |
| ++p; |
| if( p == mTaskPanes.end() ) |
| break; // do not wrap, send focus back to document at end of list |
| /* #i83908# do not use the menubar if it is native and invisible |
| this relies on MenuBar::ImplCreate setting the height of the menubar |
| to 0 in this case |
| */ |
| if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() && |
| ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 ) |
| ) |
| { |
| pWindow = *p; |
| break; |
| } |
| if( !pWindow ) // increment after test, otherwise first element is skipped |
| ++p; |
| } |
| break; |
| } |
| else |
| ++p; |
| } |
| |
| return pWindow; |
| } |
| |
| // -------------------------------------------------- |
| |