/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: vclxtabcontrol.cxx,v $ * * $Revision: 1.5 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "vclxtabcontrol.hxx" #include #include #include #include #include #include #include "forward.hxx" namespace layoutimpl { using namespace ::com::sun::star::uno; using namespace ::com::sun::star::awt; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star; VCLXTabControl::ChildProps::ChildProps( VCLXTabControl::ChildData *pData ) { addProp( RTL_CONSTASCII_USTRINGPARAM( "Title" ), ::getCppuType( static_cast< const rtl::OUString* >( NULL ) ), &(pData->maTitle) ); } VCLXTabControl::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild ) : Box_Base::ChildData( xChild ) , maTitle() { } VCLXTabControl::ChildData* VCLXTabControl::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild ) { return new ChildData( xChild ); } VCLXTabControl::ChildProps* VCLXTabControl::createChildProps( Box_Base::ChildData *pData ) { return new ChildProps( static_cast ( pData ) ); } DBG_NAME( VCLXTabControl ); VCLXTabControl::VCLXTabControl() : VCLXWindow() , VCLXTabControl_Base() , Box_Base() , mnNextTabId( 1 ) { DBG_CTOR( VCLXTabControl, NULL ); } VCLXTabControl::~VCLXTabControl() { DBG_DTOR( VCLXTabControl, NULL ); } IMPLEMENT_2_FORWARD_XINTERFACE2( VCLXTabControl, VCLXWindow, Container, VCLXTabControl_Base ); IMPLEMENT_FORWARD_XTYPEPROVIDER2( VCLXTabControl, VCLXWindow, VCLXTabControl_Base ); void SAL_CALL VCLXTabControl::dispose( ) throw(RuntimeException) { { ::vos::OGuard aGuard( GetMutex() ); EventObject aDisposeEvent; aDisposeEvent.Source = W3K_EXPLICIT_CAST (*this); // maTabListeners.disposeAndClear( aDisposeEvent ); } VCLXWindow::dispose(); } #if 0 void SAL_CALL VCLXTabControl::addTabListener( const Reference< XTabListener >& listener ) throw (RuntimeException) { if ( listener.is() ) maTabListeners.addInterface( listener ); } void SAL_CALL VCLXTabControl::removeTabListener( const Reference< XTabListener >& listener ) throw (RuntimeException) { if ( listener.is() ) maTabListeners.removeInterface( listener ); } #endif TabControl *VCLXTabControl::getTabControl() const throw (RuntimeException) { TabControl *pTabControl = static_cast< TabControl* >( GetWindow() ); if ( pTabControl ) return pTabControl; throw RuntimeException(); } sal_Int32 SAL_CALL VCLXTabControl::insertTab() throw (RuntimeException) { TabControl *pTabControl = getTabControl(); USHORT id = sal::static_int_cast< USHORT >( mnNextTabId++ ); rtl::OUString title (RTL_CONSTASCII_USTRINGPARAM( "" ) ); pTabControl->InsertPage( id, title.getStr(), TAB_APPEND ); pTabControl->SetTabPage( id, new TabPage( pTabControl ) ); return id; } void SAL_CALL VCLXTabControl::removeTab( sal_Int32 ID ) throw (RuntimeException, IndexOutOfBoundsException) { TabControl *pTabControl = getTabControl(); if ( pTabControl->GetTabPage( sal::static_int_cast< USHORT >( ID ) ) == NULL ) throw IndexOutOfBoundsException(); pTabControl->RemovePage( sal::static_int_cast< USHORT >( ID ) ); } void SAL_CALL VCLXTabControl::activateTab( sal_Int32 ID ) throw (RuntimeException, IndexOutOfBoundsException) { TabControl *pTabControl = getTabControl(); if ( pTabControl->GetTabPage( sal::static_int_cast< USHORT >( ID ) ) == NULL ) throw IndexOutOfBoundsException(); pTabControl->SelectTabPage( sal::static_int_cast< USHORT >( ID ) ); } sal_Int32 SAL_CALL VCLXTabControl::getActiveTabID() throw (RuntimeException) { return getTabControl()->GetCurPageId( ); } void SAL_CALL VCLXTabControl::addTabListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTabListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) { for ( std::list< ::com::sun::star::uno::Reference < ::com::sun::star::awt::XTabListener > >::const_iterator it = mxTabListeners.begin(); it != mxTabListeners.end(); it++ ) { if ( *it == xListener ) // already added return; } mxTabListeners.push_back( xListener ); } void SAL_CALL VCLXTabControl::removeTabListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTabListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) { for ( std::list< ::com::sun::star::uno::Reference < ::com::sun::star::awt::XTabListener > >::iterator it = mxTabListeners.begin(); it != mxTabListeners.end(); it++ ) { if ( *it == xListener ) { mxTabListeners.erase( it ); break; } } } void SAL_CALL VCLXTabControl::setTabProps( sal_Int32 ID, const Sequence< NamedValue >& Properties ) throw (RuntimeException, IndexOutOfBoundsException) { TabControl *pTabControl = getTabControl(); if ( pTabControl->GetTabPage( sal::static_int_cast< USHORT >( ID ) ) == NULL ) throw IndexOutOfBoundsException(); for ( int i = 0; i < Properties.getLength(); i++ ) { const rtl::OUString &name = Properties[i].Name; const Any &value = Properties[i].Value; if ( name == rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ) ) { rtl::OUString title = value.get(); pTabControl->SetPageText( sal::static_int_cast< USHORT >( ID ), title.getStr() ); } } } Sequence< NamedValue > SAL_CALL VCLXTabControl::getTabProps( sal_Int32 ID ) throw (IndexOutOfBoundsException, RuntimeException) { TabControl *pTabControl = getTabControl(); if ( pTabControl->GetTabPage( sal::static_int_cast< USHORT >( ID ) ) == NULL ) throw IndexOutOfBoundsException(); #define ADD_PROP( seq, i, name, val ) { \ NamedValue value; \ value.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( name ) ); \ value.Value = makeAny( val ); \ seq[i] = value; \ } Sequence< NamedValue > props( 2 ); ADD_PROP( props, 0, "Title", rtl::OUString( pTabControl->GetPageText( sal::static_int_cast< USHORT >( ID ) ) ) ); ADD_PROP( props, 1, "Position", pTabControl->GetPagePos( sal::static_int_cast< USHORT >( ID ) ) ); #undef ADD_PROP return props; } // TODO: draw tab border here void SAL_CALL VCLXTabControl::draw( sal_Int32 nX, sal_Int32 nY ) throw(::com::sun::star::uno::RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); TabControl *pTabControl = getTabControl(); TabPage *pTabPage = pTabControl->GetTabPage( sal::static_int_cast< USHORT >( getActiveTabID() ) ); if ( pTabPage ) { ::Point aPos( nX, nY ); ::Size aSize = pTabPage->GetSizePixel(); OutputDevice* pDev = VCLUnoHelper::GetOutputDevice( GetViewGraphics() ); aPos = pDev->PixelToLogic( aPos ); aSize = pDev->PixelToLogic( aSize ); pTabPage->Draw( pDev, aPos, aSize, 0 ); } VCLXWindow::draw( nX, nY ); } void SAL_CALL VCLXTabControl::addChild( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XLayoutConstrains > &xChild ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::awt::MaxChildrenException) { mIdMap[ xChild ] = insertTab(); Box_Base::addChild( xChild ); } void SAL_CALL VCLXTabControl::removeChild( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XLayoutConstrains > &xChild ) throw (::com::sun::star::uno::RuntimeException) { removeTab( mIdMap[xChild] ); mIdMap[ xChild ] = -1; Box_Base::removeChild( xChild ); } static void setChildrenVisible( uno::Reference < awt::XLayoutConstrains > xChild, bool visible ) { uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY); if ( xWin.is() ) { xWin->setVisible( visible ); } uno::Reference < awt::XLayoutContainer > xCont( xChild, uno::UNO_QUERY ); if ( xCont.is()) { uno::Sequence< uno::Reference < awt::XLayoutConstrains > > children = xCont->getChildren(); for ( int i = 0; i < children.getLength(); i++ ) { setChildrenVisible( children[i], visible ); } } } void SAL_CALL VCLXTabControl::allocateArea( const ::com::sun::star::awt::Rectangle &rArea ) throw (::com::sun::star::uno::RuntimeException) { maAllocation = rArea; TabControl *pTabControl = getTabControl(); // FIXME: this is wrong. We just want to set tab controls pos/size for the tabs menu, // otherwise, it gets events that should go to children (I guess we could solve this // by making the tabcontrol as the actual XWindow parent of its children, when importing...) // Not sure about TabPage drawing... That doesn't work on gtk+; just ignoring that. // LATER: Nah, the proper fix is to get the XWindow hierarchy straight. setPosSize( rArea.X, rArea.Y, rArea.Width, rArea.Height, PosSize::POSSIZE ); // FIXME: we can save cycles by setting visibility more sensibly. Having // it here does makes it easier when changing tabs (just needs a recalc()) unsigned i = 0; for ( std::list::const_iterator it = maChildren.begin(); it != maChildren.end(); it++, i++ ) { ChildData *child = static_cast ( *it ); ::com::sun::star::uno::Reference < ::com::sun::star::awt::XLayoutConstrains > xChild( child->mxChild ); if ( xChild.is() ) { uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY ); bool active = (i+1 == (unsigned) getActiveTabID()); // HACK: since our layout:: container don't implement XWindow, we have no easy // way to set them invisible; lets just set all their children as such :P #if 0 if ( xWin.is() ) xWin->setVisible( active ); #else setChildrenVisible( xChild, active ); #endif if ( active ) { ::Rectangle label_rect = pTabControl->GetTabBounds( sal::static_int_cast< USHORT >( i+1 ) ); ::Rectangle page_rect = pTabControl->GetTabPageBounds( sal::static_int_cast< USHORT >( i+1 ) ); awt::Rectangle childRect; childRect.X = page_rect.Left(); childRect.Y = SAL_MAX( label_rect.Bottom(), page_rect.Top() ); childRect.Width = page_rect.Right() - page_rect.Left(); childRect.Height = page_rect.Bottom() - childRect.Y; allocateChildAt( xChild, childRect ); } } } } ::com::sun::star::awt::Size SAL_CALL VCLXTabControl::getMinimumSize() throw(::com::sun::star::uno::RuntimeException) { awt::Size size = VCLXWindow::getMinimumSize(); awt::Size childrenSize( 0, 0 ); TabControl* pTabControl = static_cast< TabControl* >( GetWindow() ); if ( !pTabControl ) return size; // calculate size to accomodate all children unsigned i = 0; for ( std::list::const_iterator it = maChildren.begin(); it != maChildren.end(); it++, i++ ) { ChildData *child = static_cast ( *it ); if ( child->mxChild.is() ) { // set the title prop here... pTabControl->SetPageText( sal::static_int_cast< USHORT >( i+1 ), child->maTitle.getStr() ); awt::Size childSize( child->mxChild->getMinimumSize() ); childrenSize.Width = SAL_MAX( childSize.Width, childrenSize.Width ); childrenSize.Height = SAL_MAX( childSize.Height, childrenSize.Height ); } } size.Width += childrenSize.Width; size.Height += childrenSize.Height + 20; maRequisition = size; return size; } void VCLXTabControl::ProcessWindowEvent( const VclWindowEvent& _rVclWindowEvent ) { ::vos::OClearableGuard aGuard( GetMutex() ); TabControl* pTabControl = static_cast< TabControl* >( GetWindow() ); if ( !pTabControl ) return; switch ( _rVclWindowEvent.GetId() ) { case VCLEVENT_TABPAGE_ACTIVATE: forceRecalc(); case VCLEVENT_TABPAGE_DEACTIVATE: case VCLEVENT_TABPAGE_INSERTED: case VCLEVENT_TABPAGE_REMOVED: case VCLEVENT_TABPAGE_REMOVEDALL: case VCLEVENT_TABPAGE_PAGETEXTCHANGED: { ULONG page = (ULONG) _rVclWindowEvent.GetData(); for ( std::list< ::com::sun::star::uno::Reference < ::com::sun::star::awt::XTabListener > >::iterator it = mxTabListeners.begin(); it != mxTabListeners.end(); it++) { ::com::sun::star::uno::Reference < ::com::sun::star::awt::XTabListener > listener = *it; switch ( _rVclWindowEvent.GetId() ) { case VCLEVENT_TABPAGE_ACTIVATE: listener->activated( page ); break; case VCLEVENT_TABPAGE_DEACTIVATE: listener->deactivated( page ); break; case VCLEVENT_TABPAGE_INSERTED: listener->inserted( page ); break; case VCLEVENT_TABPAGE_REMOVED: listener->removed( page ); break; case VCLEVENT_TABPAGE_REMOVEDALL: for ( int i = 1; i < mnNextTabId; i++) { if ( pTabControl->GetTabPage( sal::static_int_cast< USHORT >( i ) ) ) listener->removed( i ); } break; case VCLEVENT_TABPAGE_PAGETEXTCHANGED: listener->changed( page, getTabProps( page ) ); break; } } break; } default: aGuard.clear(); VCLXWindow::ProcessWindowEvent( _rVclWindowEvent ); break; } } void SAL_CALL VCLXTabControl::setProperty( const ::rtl::OUString& PropertyName, const Any &Value ) throw(RuntimeException) { VCLXWindow::setProperty( PropertyName, Value ); } Any SAL_CALL VCLXTabControl::getProperty( const ::rtl::OUString& PropertyName ) throw(RuntimeException) { return VCLXWindow::getProperty( PropertyName ); } } // namespace layoutimpl