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 #include "vclxtabcontrol.hxx" 29 30 #include <com/sun/star/awt/PosSize.hpp> 31 #include <sal/macros.h> 32 #include <toolkit/helper/property.hxx> 33 #include <toolkit/helper/vclunohelper.hxx> 34 #include <vcl/tabctrl.hxx> 35 #include <vcl/tabpage.hxx> 36 37 #include "forward.hxx" 38 39 namespace layoutimpl 40 { 41 42 using namespace ::com::sun::star::lang; 43 using namespace ::com::sun::star::beans; 44 using namespace ::com::sun::star; 45 46 VCLXTabControl::ChildProps::ChildProps( VCLXTabControl::ChildData *pData ) 47 { 48 addProp( RTL_CONSTASCII_USTRINGPARAM( "Title" ), 49 ::getCppuType( static_cast< const rtl::OUString* >( NULL ) ), 50 &(pData->maTitle) ); 51 } 52 53 VCLXTabControl::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild ) 54 : Box_Base::ChildData( xChild ) 55 , maTitle() 56 { 57 } 58 59 VCLXTabControl::ChildData* 60 VCLXTabControl::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild ) 61 { 62 return new ChildData( xChild ); 63 } 64 65 VCLXTabControl::ChildProps* 66 VCLXTabControl::createChildProps( Box_Base::ChildData *pData ) 67 { 68 return new ChildProps( static_cast<VCLXTabControl::ChildData*> ( pData ) ); 69 } 70 71 DBG_NAME( VCLXTabControl ); 72 73 #if !defined (__GNUC__) 74 #define __PRETTY_FUNCTION__ __FUNCTION__ 75 #endif /* !__GNUC__ */ 76 77 VCLXTabControl::VCLXTabControl() 78 : VCLXWindow() 79 , VCLXTabControl_Base() 80 , Box_Base() 81 , mTabId (1) 82 , bRealized (false) 83 { 84 #ifndef __SUNPRO_CC 85 OSL_TRACE ("\n********%s:%x", __PRETTY_FUNCTION__, this); 86 #endif 87 DBG_CTOR( VCLXTabControl, NULL ); 88 } 89 90 VCLXTabControl::~VCLXTabControl() 91 { 92 DBG_DTOR( VCLXTabControl, NULL ); 93 } 94 95 IMPLEMENT_2_FORWARD_XINTERFACE2( VCLXTabControl, VCLXWindow, Container, VCLXTabControl_Base ); 96 97 IMPLEMENT_FORWARD_XTYPEPROVIDER2( VCLXTabControl, VCLXWindow, VCLXTabControl_Base ); 98 99 void SAL_CALL VCLXTabControl::dispose( ) throw(uno::RuntimeException) 100 { 101 { 102 ::vos::OGuard aGuard( GetMutex() ); 103 104 EventObject aDisposeEvent; 105 aDisposeEvent.Source = W3K_EXPLICIT_CAST (*this); 106 // maTabListeners.disposeAndClear( aDisposeEvent ); 107 } 108 109 VCLXWindow::dispose(); 110 } 111 112 #if 0 113 void SAL_CALL VCLXTabControl::addTabListener( const Reference< XTabListener >& listener ) throw (uno::RuntimeException) 114 { 115 if ( listener.is() ) 116 maTabListeners.addInterface( listener ); 117 } 118 119 void SAL_CALL VCLXTabControl::removeTabListener( const Reference< XTabListener >& listener ) throw (uno::RuntimeException) 120 { 121 if ( listener.is() ) 122 maTabListeners.removeInterface( listener ); 123 } 124 #endif 125 126 TabControl *VCLXTabControl::getTabControl() const throw (uno::RuntimeException) 127 { 128 TabControl *pTabControl = static_cast< TabControl* >( GetWindow() ); 129 if ( pTabControl ) 130 return pTabControl; 131 throw uno::RuntimeException(); 132 } 133 134 sal_Int32 SAL_CALL VCLXTabControl::insertTab() throw (uno::RuntimeException) 135 { 136 TabControl *pTabControl = getTabControl(); 137 sal_uInt16 id = sal::static_int_cast< sal_uInt16 >( mTabId++ ); 138 rtl::OUString title (RTL_CONSTASCII_USTRINGPARAM( "" ) ); 139 pTabControl->InsertPage( id, title.getStr(), TAB_APPEND ); 140 pTabControl->SetTabPage( id, new TabPage( pTabControl ) ); 141 return id; 142 } 143 144 void SAL_CALL VCLXTabControl::removeTab( sal_Int32 ID ) throw (uno::RuntimeException, IndexOutOfBoundsException) 145 { 146 TabControl *pTabControl = getTabControl(); 147 if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL ) 148 throw IndexOutOfBoundsException(); 149 pTabControl->RemovePage( sal::static_int_cast< sal_uInt16 >( ID ) ); 150 } 151 152 void SAL_CALL VCLXTabControl::activateTab( sal_Int32 ID ) throw (uno::RuntimeException, IndexOutOfBoundsException) 153 { 154 TabControl *pTabControl = getTabControl(); 155 if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL ) 156 throw IndexOutOfBoundsException(); 157 pTabControl->SelectTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ); 158 } 159 160 sal_Int32 SAL_CALL VCLXTabControl::getActiveTabID() throw (uno::RuntimeException) 161 { 162 return getTabControl()->GetCurPageId( ); 163 } 164 165 void SAL_CALL VCLXTabControl::addTabListener( const uno::Reference< awt::XTabListener >& xListener ) throw (uno::RuntimeException) 166 { 167 for ( std::list< uno::Reference 168 < awt::XTabListener > >::const_iterator it 169 = mxTabListeners.begin(); it != mxTabListeners.end(); it++ ) 170 { 171 if ( *it == xListener ) 172 // already added 173 return; 174 } 175 mxTabListeners.push_back( xListener ); 176 } 177 178 void SAL_CALL VCLXTabControl::removeTabListener( const uno::Reference< awt::XTabListener >& xListener ) throw (uno::RuntimeException) 179 { 180 for ( std::list< uno::Reference 181 < awt::XTabListener > >::iterator it 182 = mxTabListeners.begin(); it != mxTabListeners.end(); it++ ) 183 { 184 if ( *it == xListener ) 185 { 186 mxTabListeners.erase( it ); 187 break; 188 } 189 } 190 } 191 192 void SAL_CALL VCLXTabControl::setTabProps( sal_Int32 ID, const uno::Sequence< NamedValue >& Properties ) throw (uno::RuntimeException, IndexOutOfBoundsException) 193 { 194 TabControl *pTabControl = getTabControl(); 195 if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL ) 196 throw IndexOutOfBoundsException(); 197 198 for ( int i = 0; i < Properties.getLength(); i++ ) 199 { 200 const rtl::OUString &name = Properties[i].Name; 201 const uno::Any &value = Properties[i].Value; 202 203 if ( name == rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ) ) 204 { 205 rtl::OUString title = value.get<rtl::OUString>(); 206 pTabControl->SetPageText( sal::static_int_cast< sal_uInt16 >( ID ), title.getStr() ); 207 } 208 } 209 } 210 211 uno::Sequence< NamedValue > SAL_CALL VCLXTabControl::getTabProps( sal_Int32 ID ) 212 throw (IndexOutOfBoundsException, uno::RuntimeException) 213 { 214 TabControl *pTabControl = getTabControl(); 215 if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL ) 216 throw IndexOutOfBoundsException(); 217 218 #define ADD_PROP( seq, i, name, val ) { \ 219 NamedValue value; \ 220 value.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( name ) ); \ 221 value.Value = uno::makeAny( val ); \ 222 seq[i] = value; \ 223 } 224 225 uno::Sequence< NamedValue > props( 2 ); 226 ADD_PROP( props, 0, "Title", rtl::OUString( pTabControl->GetPageText( sal::static_int_cast< sal_uInt16 >( ID ) ) ) ); 227 ADD_PROP( props, 1, "Position", pTabControl->GetPagePos( sal::static_int_cast< sal_uInt16 >( ID ) ) ); 228 #undef ADD_PROP 229 return props; 230 } 231 232 // TODO: draw tab border here 233 void SAL_CALL VCLXTabControl::draw( sal_Int32 nX, sal_Int32 nY ) throw(uno::RuntimeException) 234 { 235 ::vos::OGuard aGuard( GetMutex() ); 236 237 TabControl *pTabControl = getTabControl(); 238 TabPage *pTabPage = pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( getActiveTabID() ) ); 239 if ( pTabPage ) 240 { 241 ::Point aPos( nX, nY ); 242 ::Size aSize = pTabPage->GetSizePixel(); 243 244 OutputDevice* pDev = VCLUnoHelper::GetOutputDevice( getGraphics() ); 245 aPos = pDev->PixelToLogic( aPos ); 246 aSize = pDev->PixelToLogic( aSize ); 247 248 pTabPage->Draw( pDev, aPos, aSize, 0 ); 249 } 250 251 VCLXWindow::draw( nX, nY ); 252 } 253 254 void VCLXTabControl::AddChild (uno::Reference< awt::XLayoutConstrains > const& xChild) 255 256 { 257 #ifndef __SUNPRO_CC 258 OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ()); 259 #endif 260 mIdMap[ xChild ] = mTabId++; 261 Box_Base::AddChild( xChild ); 262 #ifndef __SUNPRO_CC 263 OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ()); 264 #endif 265 } 266 267 void SAL_CALL VCLXTabControl::addChild( 268 const uno::Reference< awt::XLayoutConstrains > &xChild ) 269 throw (uno::RuntimeException, awt::MaxChildrenException) 270 { 271 mIdMap[ xChild ] = insertTab(); 272 Box_Base::addChild( xChild ); 273 } 274 275 void SAL_CALL VCLXTabControl::removeChild( const uno::Reference< awt::XLayoutConstrains > &xChild ) 276 throw (uno::RuntimeException) 277 { 278 removeTab( mIdMap[xChild] ); 279 mIdMap[ xChild ] = -1; 280 Box_Base::removeChild( xChild ); 281 } 282 283 static void setChildrenVisible( uno::Reference < awt::XLayoutConstrains > xChild, bool visible ) 284 { 285 uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY); 286 if ( xWin.is() ) 287 { 288 xWin->setVisible( visible ); 289 } 290 291 uno::Reference < awt::XLayoutContainer > xCont( xChild, uno::UNO_QUERY ); 292 if ( xCont.is()) 293 { 294 uno::Sequence< uno::Reference < awt::XLayoutConstrains > > children = xCont->getChildren(); 295 for ( int i = 0; i < children.getLength(); i++ ) 296 { 297 setChildrenVisible( children[i], visible ); 298 } 299 } 300 } 301 302 void SAL_CALL VCLXTabControl::allocateArea (awt::Rectangle const &area) 303 throw (uno::RuntimeException) 304 { 305 #ifndef __SUNPRO_CC 306 OSL_TRACE ("\n%s", __PRETTY_FUNCTION__); 307 #endif 308 maAllocation = area; 309 310 TabControl *pTabControl = getTabControl(); 311 312 // FIXME: this is wrong. We just want to set tab controls pos/size for 313 // the tabs menu, otherwise, it gets events that should go to children 314 // (I guess we could solve this by making the tabcontrol as the actual 315 // XWindow parent of its children, when importing...) Not sure about 316 // TabPage drawing... That doesn't work on gtk+; just ignoring that. 317 // LATER: Nah, the proper fix is to get the XWindow hierarchy 318 // straight. 319 320 #if 0 321 setPosSize( area.X, area.Y, area.Width, area.Height, awt::PosSize::POSSIZE ); 322 #else 323 awt::Size currentSize = getSize(); 324 awt::Size requestedSize (area.Width, area.Height); 325 // requestedSize.Height = getHeightForWidth( area.Width ); 326 327 awt::Size minimumSize = getMinimumSize(); 328 if (requestedSize.Width < minimumSize.Width) 329 requestedSize.Width = minimumSize.Width; 330 if (requestedSize.Height < minimumSize.Height) 331 requestedSize.Height = minimumSize.Height; 332 333 Size pageSize = static_cast<TabControl*> (GetWindow ())->GetTabPageSizePixel (); 334 awt::Size pageBasedSize (0, 0); 335 pageBasedSize.Width = pageSize.Width (); 336 pageBasedSize.Height = pageSize.Height (); 337 338 const int wc = 0; 339 const int hc = 20; 340 static int pwc = 0; 341 static int phc = 40; 342 343 if (requestedSize.Width < pageBasedSize.Width) 344 requestedSize.Width = pageBasedSize.Width + wc; 345 if (requestedSize.Height < pageBasedSize.Height) 346 requestedSize.Height = pageBasedSize.Height + hc; 347 348 Size windowSize = GetWindow()->GetSizePixel(); 349 Window *parent = GetWindow()->GetParent(); 350 Size parentSize = parent->GetSizePixel(); 351 352 #ifndef __SUNPRO_CC 353 #ifdef GCC_MAJOR 354 OSL_TRACE ("\n%s", __PRETTY_FUNCTION__); 355 #endif /* GCC_MAJOR */ 356 OSL_TRACE ("%s: cursize: %d ,%d", __FUNCTION__, currentSize.Width, currentSize.Height ); 357 OSL_TRACE ("%s: area: %d, %d", __FUNCTION__, area.Width, area.Height ); 358 OSL_TRACE ("%s: minimum: %d, %d", __FUNCTION__, minimumSize.Width, minimumSize.Height ); 359 OSL_TRACE ("%s: requestedSize: %d, %d", __FUNCTION__, requestedSize.Width, requestedSize.Height ); 360 OSL_TRACE ("%s: pageBasedSize: %d, %d", __FUNCTION__, pageBasedSize.Width, pageBasedSize.Height ); 361 362 //OSL_TRACE ("%s: parent: %d, %d", __FUNCTION__, parentSize.Width(), parentSize.Height() ); 363 //OSL_TRACE ("%s: window: %d, %d", __FUNCTION__, windowSize.Width(), windowSize.Height() ); 364 #endif 365 366 //bRealized = false; 367 if (!bRealized) 368 { 369 setPosSize( area.X, area.Y, requestedSize.Width, requestedSize.Height, awt::PosSize::POSSIZE ); 370 bRealized = true; 371 } 372 else 373 { 374 if ( requestedSize.Width > currentSize.Width + 10) 375 setPosSize( 0, 0, requestedSize.Width, 0, awt::PosSize::WIDTH ); 376 if ( requestedSize.Height > currentSize.Height + 10) 377 setPosSize( 0, 0, 0, requestedSize.Height, awt::PosSize::HEIGHT ); 378 } 379 #endif 380 381 if (pageBasedSize.Width > parentSize.Width () 382 || pageBasedSize.Height > parentSize.Height ()) 383 //parent->SetSizePixel ( Size (pageBasedSize.Width, pageBasedSize.Height)); 384 //parent->SetSizePixel ( Size (pageBasedSize.Width + pwc, pageBasedSize.Height + phc)); 385 parent->SetSizePixel ( Size (requestedSize.Width + pwc, requestedSize.Height + phc)); 386 387 // FIXME: we can save cycles by setting visibility more sensibly. Having 388 // it here does makes it easier when changing tabs (just needs a recalc()) 389 unsigned i = 0; 390 for ( std::list<Box_Base::ChildData *>::const_iterator it 391 = maChildren.begin(); it != maChildren.end(); it++, i++ ) 392 { 393 ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it ); 394 uno::Reference 395 < awt::XLayoutConstrains > xChild( child->mxChild ); 396 if ( xChild.is() ) 397 { 398 uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY ); 399 bool active = (i+1 == (unsigned) getActiveTabID()); 400 401 // HACK: since our layout:: container don't implement XWindow, we have no easy 402 // way to set them invisible; lets just set all their children as such :P 403 #if 0 404 if ( xWin.is() ) 405 xWin->setVisible( active ); 406 #else 407 setChildrenVisible( xChild, active ); 408 #endif 409 410 if ( active ) 411 { 412 ::Rectangle label_rect = pTabControl->GetTabBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) ); 413 ::Rectangle page_rect = pTabControl->GetTabPageBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) ); 414 415 awt::Rectangle childRect; 416 childRect.X = page_rect.Left(); 417 childRect.Y = SAL_MAX( label_rect.Bottom(), page_rect.Top() ); 418 childRect.Width = page_rect.Right() - page_rect.Left(); 419 childRect.Height = page_rect.Bottom() - childRect.Y; 420 421 allocateChildAt( xChild, childRect ); 422 } 423 } 424 } 425 } 426 427 awt::Size SAL_CALL VCLXTabControl::getMinimumSize() 428 throw(uno::RuntimeException) 429 { 430 awt::Size requestedSize = VCLXWindow::getMinimumSize(); 431 awt::Size childrenSize( 0, 0 ); 432 433 TabControl* pTabControl = static_cast< TabControl* >( GetWindow() ); 434 if ( !pTabControl ) 435 return requestedSize; 436 437 // calculate size to accomodate all children 438 unsigned i = 0; 439 for ( std::list<Box_Base::ChildData *>::const_iterator it 440 = maChildren.begin(); it != maChildren.end(); it++, i++ ) 441 { 442 ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it ); 443 if ( child->mxChild.is() ) 444 { 445 // set the title prop here... 446 pTabControl->SetPageText( sal::static_int_cast< sal_uInt16 >( i+1 ), child->maTitle.getStr() ); 447 448 awt::Size childSize( child->mxChild->getMinimumSize() ); 449 childrenSize.Width = SAL_MAX( childSize.Width, childrenSize.Width ); 450 childrenSize.Height = SAL_MAX( childSize.Height, childrenSize.Height ); 451 } 452 } 453 454 #ifndef __SUNPRO_CC 455 #ifdef GCC_MAJOR 456 OSL_TRACE ("\n%s", __PRETTY_FUNCTION__); 457 #endif /* GCC_MAJOR */ 458 OSL_TRACE ("%s: children: %d", __FUNCTION__, i); 459 OSL_TRACE ("%s: childrenSize: %d, %d", __FUNCTION__, childrenSize.Width, childrenSize.Height ); 460 #endif 461 462 requestedSize.Width += childrenSize.Width; 463 requestedSize.Height += childrenSize.Height + 20; 464 465 maRequisition = requestedSize; 466 return requestedSize; 467 } 468 469 void VCLXTabControl::ProcessWindowEvent( const VclWindowEvent& _rVclWindowEvent ) 470 { 471 ::vos::OClearableGuard aGuard( GetMutex() ); 472 TabControl* pTabControl = static_cast< TabControl* >( GetWindow() ); 473 if ( !pTabControl ) 474 return; 475 476 switch ( _rVclWindowEvent.GetId() ) 477 { 478 case VCLEVENT_TABPAGE_ACTIVATE: 479 forceRecalc(); 480 case VCLEVENT_TABPAGE_DEACTIVATE: 481 case VCLEVENT_TABPAGE_INSERTED: 482 case VCLEVENT_TABPAGE_REMOVED: 483 case VCLEVENT_TABPAGE_REMOVEDALL: 484 case VCLEVENT_TABPAGE_PAGETEXTCHANGED: 485 { 486 sal_uLong page = (sal_uLong) _rVclWindowEvent.GetData(); 487 for ( std::list< uno::Reference 488 < awt::XTabListener > >::iterator it 489 = mxTabListeners.begin(); it != mxTabListeners.end(); it++) 490 { 491 uno::Reference 492 < awt::XTabListener > listener = *it; 493 494 switch ( _rVclWindowEvent.GetId() ) 495 { 496 497 case VCLEVENT_TABPAGE_ACTIVATE: 498 listener->activated( page ); 499 break; 500 case VCLEVENT_TABPAGE_DEACTIVATE: 501 listener->deactivated( page ); 502 break; 503 case VCLEVENT_TABPAGE_INSERTED: 504 listener->inserted( page ); 505 break; 506 case VCLEVENT_TABPAGE_REMOVED: 507 listener->removed( page ); 508 break; 509 case VCLEVENT_TABPAGE_REMOVEDALL: 510 for ( int i = 1; i < mTabId; i++) 511 { 512 if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( i ) ) ) 513 listener->removed( i ); 514 } 515 break; 516 case VCLEVENT_TABPAGE_PAGETEXTCHANGED: 517 listener->changed( page, getTabProps( page ) ); 518 break; 519 } 520 } 521 break; 522 } 523 default: 524 aGuard.clear(); 525 VCLXWindow::ProcessWindowEvent( _rVclWindowEvent ); 526 break; 527 } 528 } 529 530 void SAL_CALL VCLXTabControl::setProperty( const ::rtl::OUString& PropertyName, const uno::Any &Value ) throw(uno::RuntimeException) 531 { 532 VCLXWindow::setProperty( PropertyName, Value ); 533 } 534 535 uno::Any SAL_CALL VCLXTabControl::getProperty( const ::rtl::OUString& PropertyName ) throw(uno::RuntimeException) 536 { 537 return VCLXWindow::getProperty( PropertyName ); 538 } 539 540 } // namespace layoutimpl 541