blob: e1efcad1720af709d9ce0f82bb2964bed8fa26c9 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
#include "precompiled_svtools.hxx"
#include "svtools/toolpanel/drawerlayouter.hxx"
#include "toolpaneldrawer.hxx"
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <comphelper/accimplaccess.hxx>
#include <tools/diagnose_ex.h>
//......................................................................................................................
namespace svt
{
//......................................................................................................................
/** === begin UNO using === **/
using ::com::sun::star::uno::Reference;
using ::com::sun::star::accessibility::XAccessible;
/** === end UNO using === **/
//==================================================================================================================
//= DrawerDeckLayouter
//==================================================================================================================
//------------------------------------------------------------------------------------------------------------------
DrawerDeckLayouter::DrawerDeckLayouter( ::Window& i_rParentWindow, IToolPanelDeck& i_rPanels )
:m_rParentWindow( i_rParentWindow )
,m_rPanelDeck( i_rPanels )
,m_aDrawers()
,m_aLastKnownActivePanel()
{
m_rPanelDeck.AddListener( *this );
// simulate PanelInserted events for the panels which are already there
for ( size_t i=0; i<m_rPanelDeck.GetPanelCount(); ++i )
PanelInserted( m_rPanelDeck.GetPanel( i ), i );
}
//------------------------------------------------------------------------------------------------------------------
DrawerDeckLayouter::~DrawerDeckLayouter()
{
}
//------------------------------------------------------------------------------------------------------------------
IMPLEMENT_IREFERENCE( DrawerDeckLayouter )
//------------------------------------------------------------------------------------------------------------------
Rectangle DrawerDeckLayouter::Layout( const Rectangle& i_rDeckPlayground )
{
const size_t nPanelCount( m_rPanelDeck.GetPanelCount() );
if ( nPanelCount == 0 )
return i_rDeckPlayground;
const int nWidth( i_rDeckPlayground.GetWidth() );
::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() );
if ( !aActivePanel )
aActivePanel = m_aLastKnownActivePanel;
// arrange the title bars which are *above* the active panel (or *all* if there is no active panel), plus
// the title bar of the active panel itself
Point aUpperDrawerPos( i_rDeckPlayground.TopLeft() );
const size_t nUpperBound = !!aActivePanel ? *aActivePanel : nPanelCount - 1;
for ( size_t i=0; i<=nUpperBound; ++i )
{
long const nDrawerHeight = m_aDrawers[i]->GetPreferredHeightPixel();
m_aDrawers[i]->SetPosSizePixel(
aUpperDrawerPos, Size( nWidth, nDrawerHeight ) );
aUpperDrawerPos.Move( 0, nDrawerHeight );
}
// arrange title bars which are below the active panel (or *none* if there is no active panel)
Point aLowerDrawerPos( i_rDeckPlayground.BottomLeft() );
for ( size_t j = nPanelCount - 1; j > nUpperBound; --j )
{
long const nDrawerHeight = m_aDrawers[j]->GetPreferredHeightPixel();
m_aDrawers[j]->SetPosSizePixel(
Point( aLowerDrawerPos.X(), aLowerDrawerPos.Y() - nDrawerHeight + 1 ),
Size( nWidth, nDrawerHeight )
);
aLowerDrawerPos.Move( 0, -nDrawerHeight );
}
// fincally calculate the rectangle for the active panel
return Rectangle(
aUpperDrawerPos,
Size( nWidth, aLowerDrawerPos.Y() - aUpperDrawerPos.Y() + 1 )
);
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::Destroy()
{
while ( !m_aDrawers.empty() )
impl_removeDrawer( 0 );
m_rPanelDeck.RemoveListener( *this );
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::SetFocusToPanelSelector()
{
const size_t nPanelCount( m_rPanelDeck.GetPanelCount() );
if ( !nPanelCount )
// nothing to focus
return;
::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() );
if ( !aActivePanel )
aActivePanel = 0;
ENSURE_OR_RETURN_VOID( *aActivePanel < m_aDrawers.size(), "DrawerDeckLayouter::SetFocusToPanelSelector: invalid active panel, or inconsistent drawers!" );
m_aDrawers[ *aActivePanel ]->GrabFocus();
}
//------------------------------------------------------------------------------------------------------------------
size_t DrawerDeckLayouter::GetAccessibleChildCount() const
{
return m_aDrawers.size();
}
//------------------------------------------------------------------------------------------------------------------
Reference< XAccessible > DrawerDeckLayouter::GetAccessibleChild( const size_t i_nChildIndex, const Reference< XAccessible >& i_rParentAccessible )
{
ENSURE_OR_RETURN( i_nChildIndex < m_aDrawers.size(), "illegal index", NULL );
const PToolPanelDrawer pDrawer( m_aDrawers[ i_nChildIndex ] );
Reference< XAccessible > xItemAccessible = pDrawer->GetAccessible( sal_False );
if ( !xItemAccessible.is() )
{
xItemAccessible = pDrawer->GetAccessible( sal_True );
ENSURE_OR_RETURN( xItemAccessible.is(), "illegal accessible provided by the drawer implementation!", NULL );
OSL_VERIFY( ::comphelper::OAccessibleImplementationAccess::setAccessibleParent( xItemAccessible->getAccessibleContext(),
i_rParentAccessible ) );
}
return xItemAccessible;
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition )
{
OSL_PRECOND( i_nPosition <= m_aDrawers.size(), "DrawerDeckLayouter::PanelInserted: inconsistency!" );
PToolPanelDrawer pDrawer( new ToolPanelDrawer( m_rParentWindow, i_pPanel->GetDisplayName() ) );
pDrawer->SetHelpId( i_pPanel->GetHelpID() );
// proper Z-Order
if ( i_nPosition == 0 )
{
pDrawer->SetZOrder( NULL, WINDOW_ZORDER_FIRST );
}
else
{
const PToolPanelDrawer pFirstDrawer( m_aDrawers[ i_nPosition - 1 ] );
pDrawer->SetZOrder( pFirstDrawer.get(), WINDOW_ZORDER_BEHIND );
}
pDrawer->Show();
pDrawer->AddEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) );
m_aDrawers.insert( m_aDrawers.begin() + i_nPosition, pDrawer );
impl_triggerRearrange();
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::PanelRemoved( const size_t i_nPosition )
{
impl_removeDrawer( i_nPosition );
impl_triggerRearrange();
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::impl_triggerRearrange() const
{
// this is somewhat hacky, it assumes that the parent of our panels is a tool panel deck, which, in its
// Resize implementation, rearrances all elements.
m_rParentWindow.Resize();
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
{
if ( !!i_rOldActive )
{
OSL_ENSURE( *i_rOldActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal old index!" );
m_aDrawers[ *i_rOldActive ]->SetExpanded( false );
}
if ( !!i_rNewActive )
{
OSL_ENSURE( *i_rNewActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal new index!" );
m_aDrawers[ *i_rNewActive ]->SetExpanded( true );
}
impl_triggerRearrange();
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
{
// not interested in
(void)i_rNewLayouter;
}
//------------------------------------------------------------------------------------------------------------------
size_t DrawerDeckLayouter::impl_getPanelPositionFromWindow( const Window* i_pDrawerWindow ) const
{
for ( ::std::vector< PToolPanelDrawer >::const_iterator drawerPos = m_aDrawers.begin();
drawerPos != m_aDrawers.end();
++drawerPos
)
{
if ( drawerPos->get() == i_pDrawerWindow )
return drawerPos - m_aDrawers.begin();
}
return m_aDrawers.size();
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::impl_removeDrawer( const size_t i_nPosition )
{
OSL_PRECOND( i_nPosition < m_aDrawers.size(), "DrawerDeckLayouter::impl_removeDrawer: invalid panel position!" );
m_aDrawers[ i_nPosition ]->RemoveEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) );
OSL_ENSURE( m_aDrawers[ i_nPosition ].unique(), "DrawerDeckLayouter::impl_removeDrawer: somebody else is still holding a reference!" );
m_aDrawers.erase( m_aDrawers.begin() + i_nPosition );
}
//------------------------------------------------------------------------------------------------------------------
IMPL_LINK( DrawerDeckLayouter, OnWindowEvent, VclSimpleEvent*, i_pEvent )
{
const VclWindowEvent* pWindowEvent = PTR_CAST( VclWindowEvent, i_pEvent );
ENSURE_OR_RETURN( pWindowEvent, "no WindowEvent", 0L );
bool bActivatePanel = false;
switch ( pWindowEvent->GetId() )
{
case VCLEVENT_WINDOW_MOUSEBUTTONUP:
{
const MouseEvent* pMouseEvent = static_cast< const MouseEvent* >( pWindowEvent->GetData() );
ENSURE_OR_RETURN( pMouseEvent, "no mouse event with MouseButtonUp", 0L );
if ( pMouseEvent->GetButtons() == MOUSE_LEFT )
{
bActivatePanel = true;
}
}
break;
case VCLEVENT_WINDOW_KEYINPUT:
{
const KeyEvent* pKeyEvent = static_cast< const KeyEvent* >( pWindowEvent->GetData() );
ENSURE_OR_RETURN( pKeyEvent, "no key event with KeyInput", 0L );
const KeyCode& rKeyCode( pKeyEvent->GetKeyCode() );
if ( ( rKeyCode.GetModifier() == 0 ) && ( rKeyCode.GetCode() == KEY_RETURN ) )
{
bActivatePanel = true;
}
}
break;
}
if ( bActivatePanel )
{
const size_t nPanelPos = impl_getPanelPositionFromWindow( pWindowEvent->GetWindow() );
if ( nPanelPos != m_rPanelDeck.GetActivePanel() )
{
m_rPanelDeck.ActivatePanel( nPanelPos );
}
else
{
PToolPanel pPanel( m_rPanelDeck.GetPanel( nPanelPos ) );
pPanel->GrabFocus();
}
return 1L;
}
return 0L;
}
//------------------------------------------------------------------------------------------------------------------
void DrawerDeckLayouter::Dying()
{
Destroy();
}
//......................................................................................................................
} // namespace svt
//......................................................................................................................