ktabwidget.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2003 Stephan Binner <binner@kde.org> 00003 Copyright (C) 2003 Zack Rusin <zack@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include <tqapplication.h> 00022 #include <tqstyle.h> 00023 #include <tqstylesheet.h> 00024 00025 #include <kconfig.h> 00026 #include <kiconloader.h> 00027 #include <kstringhandler.h> 00028 00029 #include "ktabwidget.h" 00030 #include "ktabbar.h" 00031 00032 class KTabWidgetPrivate { 00033 public: 00034 bool m_automaticResizeTabs; 00035 int m_maxLength; 00036 int m_minLength; 00037 unsigned int m_CurrentMaxLength; 00038 00039 //holds the full names of the tab, otherwise all we 00040 //know about is the shortened name 00041 TQStringList m_tabNames; 00042 00043 KTabWidgetPrivate() { 00044 m_automaticResizeTabs = false; 00045 KConfigGroupSaver groupsaver(KGlobal::config(), "General"); 00046 m_maxLength = KGlobal::config()->readNumEntry("MaximumTabLength", 30); 00047 m_minLength = KGlobal::config()->readNumEntry("MinimumTabLength", 3); 00048 m_CurrentMaxLength = m_minLength; 00049 } 00050 }; 00051 00052 KTabWidget::KTabWidget( TQWidget *parent, const char *name, WFlags f ) 00053 : TQTabWidget( parent, name, f ) 00054 { 00055 d = new KTabWidgetPrivate; 00056 setTabBar( new KTabBar(this, "tabbar") ); 00057 setAcceptDrops( true ); 00058 00059 setHoverCloseButtonDelayed(false); 00060 00061 connect(tabBar(), TQT_SIGNAL(contextMenu( int, const TQPoint & )), TQT_SLOT(contextMenu( int, const TQPoint & ))); 00062 connect(tabBar(), TQT_SIGNAL(mouseDoubleClick( int )), TQT_SLOT(mouseDoubleClick( int ))); 00063 connect(tabBar(), TQT_SIGNAL(mouseMiddleClick( int )), TQT_SLOT(mouseMiddleClick( int ))); 00064 connect(tabBar(), TQT_SIGNAL(initiateDrag( int )), TQT_SLOT(initiateDrag( int ))); 00065 connect(tabBar(), TQT_SIGNAL(testCanDecode(const TQDragMoveEvent *, bool & )), TQT_SIGNAL(testCanDecode(const TQDragMoveEvent *, bool & ))); 00066 connect(tabBar(), TQT_SIGNAL(receivedDropEvent( int, TQDropEvent * )), TQT_SLOT(receivedDropEvent( int, TQDropEvent * ))); 00067 connect(tabBar(), TQT_SIGNAL(moveTab( int, int )), TQT_SLOT(moveTab( int, int ))); 00068 connect(tabBar(), TQT_SIGNAL(closeRequest( int )), TQT_SLOT(closeRequest( int ))); 00069 #ifndef QT_NO_WHEELEVENT 00070 connect(tabBar(), TQT_SIGNAL(wheelDelta( int )), TQT_SLOT(wheelDelta( int ))); 00071 #endif 00072 } 00073 00074 KTabWidget::~KTabWidget() 00075 { 00076 delete d; 00077 } 00078 00079 void KTabWidget::insertTab( TQWidget *child, const TQString &label, int index ) 00080 { 00081 TQTabWidget::insertTab( child, label, index ); 00082 } 00083 00084 void KTabWidget::insertTab( TQWidget *child, const TQIconSet& iconset, const TQString &label, int index ) 00085 { 00086 TQTabWidget::insertTab( child, iconset, label, index ); 00087 } 00088 00089 void KTabWidget::insertTab( TQWidget *child, TQTab *tab, int index ) 00090 { 00091 TQTabWidget::insertTab( child, tab, index); 00092 if ( d->m_automaticResizeTabs ) { 00093 if ( index < 0 || index >= count() ) { 00094 d->m_tabNames.append( tab->text() ); 00095 resizeTabs( d->m_tabNames.count()-1 ); 00096 } 00097 else { 00098 d->m_tabNames.insert( d->m_tabNames.at( index ), tab->text() ); 00099 resizeTabs( index ); 00100 } 00101 } 00102 } 00103 00104 void KTabWidget::setTabBarHidden( bool hide ) 00105 { 00106 TQWidget *rightcorner = this->cornerWidget( TopRight ); 00107 TQWidget *leftcorner = this->cornerWidget( TopLeft ); 00108 00109 if ( hide ) { 00110 if ( leftcorner ) leftcorner->hide(); 00111 if ( rightcorner ) rightcorner->hide(); 00112 tabBar()->hide(); 00113 } else { 00114 tabBar()->show(); 00115 if ( leftcorner ) leftcorner->show(); 00116 if ( rightcorner ) rightcorner->show(); 00117 } 00118 } 00119 00120 bool KTabWidget::isTabBarHidden() const 00121 { 00122 return !( tabBar()->isVisible() ); 00123 } 00124 00125 void KTabWidget::setTabColor( TQWidget *w, const TQColor& color ) 00126 { 00127 TQTab *t = tabBar()->tabAt( indexOf( w ) ); 00128 if (t) { 00129 static_cast<KTabBar*>(tabBar())->setTabColor( t->identifier(), color ); 00130 } 00131 } 00132 00133 TQColor KTabWidget::tabColor( TQWidget *w ) const 00134 { 00135 TQTab *t = tabBar()->tabAt( indexOf( w ) ); 00136 if (t) { 00137 return static_cast<KTabBar*>(tabBar())->tabColor( t->identifier() ); 00138 } else { 00139 return TQColor(); 00140 } 00141 } 00142 00143 void KTabWidget::setTabReorderingEnabled( bool on) 00144 { 00145 static_cast<KTabBar*>(tabBar())->setTabReorderingEnabled( on ); 00146 } 00147 00148 bool KTabWidget::isTabReorderingEnabled() const 00149 { 00150 return static_cast<KTabBar*>(tabBar())->isTabReorderingEnabled(); 00151 } 00152 00153 void KTabWidget::setTabCloseActivatePrevious( bool previous) 00154 { 00155 static_cast<KTabBar*>(tabBar())->setTabCloseActivatePrevious( previous ); 00156 } 00157 00158 bool KTabWidget::tabCloseActivatePrevious() const 00159 { 00160 return static_cast<KTabBar*>(tabBar())->tabCloseActivatePrevious(); 00161 } 00162 00163 unsigned int KTabWidget::tabBarWidthForMaxChars( uint maxLength ) 00164 { 00165 int hframe, overlap; 00166 hframe = tabBar()->style().pixelMetric( TQStyle::PM_TabBarTabHSpace, tabBar() ); 00167 overlap = tabBar()->style().pixelMetric( TQStyle::PM_TabBarTabOverlap, tabBar() ); 00168 00169 TQFontMetrics fm = tabBar()->fontMetrics(); 00170 int x = 0; 00171 for( int i=0; i < count(); ++i ) { 00172 TQString newTitle = d->m_tabNames[ i ]; 00173 newTitle = KStringHandler::rsqueeze( newTitle, maxLength ).leftJustify( d->m_minLength, ' ' ); 00174 00175 TQTab* tab = tabBar()->tabAt( i ); 00176 int lw = fm.width( newTitle ); 00177 int iw = 0; 00178 if ( tab->iconSet() ) 00179 iw = tab->iconSet()->pixmap( TQIconSet::Small, TQIconSet::Normal ).width() + 4; 00180 x += ( tabBar()->style().tqsizeFromContents( TQStyle::CT_TabBarTab, this, 00181 TQSize( QMAX( lw + hframe + iw, TQApplication::globalStrut().width() ), 0 ), 00182 TQStyleOption( tab ) ) ).width(); 00183 } 00184 return x; 00185 } 00186 00187 void KTabWidget::changeTab( TQWidget *w, const TQString &label ) 00188 { 00189 TQTabWidget::changeTab( w, label ); 00190 if ( d->m_automaticResizeTabs ) { 00191 int index = indexOf( w ); 00192 if ( index != -1 ) { 00193 d->m_tabNames[ index ] = label; 00194 resizeTabs( index ); 00195 } 00196 } 00197 } 00198 00199 void KTabWidget::changeTab( TQWidget *w, const TQIconSet &iconset, const TQString &label ) 00200 { 00201 TQTabWidget::changeTab( w, iconset, label ); 00202 if ( d->m_automaticResizeTabs ) { 00203 int index = indexOf( w ); 00204 if ( index != -1 ) { 00205 d->m_tabNames[ index ] = label; 00206 resizeTabs( index ); 00207 } 00208 } 00209 } 00210 00211 TQString KTabWidget::label( int index ) const 00212 { 00213 if ( d->m_automaticResizeTabs ) { 00214 if ( index >= 0 && index < count() ) 00215 return d->m_tabNames[ index ]; 00216 else 00217 return TQString::null; 00218 } 00219 else 00220 return TQTabWidget::label( index ); 00221 } 00222 00223 TQString KTabWidget::tabLabel( TQWidget * w ) const 00224 { 00225 if ( d->m_automaticResizeTabs ) { 00226 int index = indexOf( w ); 00227 if ( index == -1 ) 00228 return TQString::null; 00229 else 00230 return d->m_tabNames[ index ]; 00231 } 00232 else 00233 return TQTabWidget::tabLabel( w ); 00234 } 00235 00236 void KTabWidget::setTabLabel( TQWidget *w, const TQString &l ) 00237 { 00238 TQTabWidget::setTabLabel( w, l ); 00239 if ( d->m_automaticResizeTabs ) { 00240 int index = indexOf( w ); 00241 if ( index != -1 ) { 00242 d->m_tabNames[ index ] = l; 00243 resizeTabs( index ); 00244 } 00245 } 00246 } 00247 00248 void KTabWidget::resizeTabs( int changeTabIndex ) 00249 { 00250 uint newMaxLength; 00251 if ( d->m_automaticResizeTabs ) { 00252 // Calculate new max length 00253 newMaxLength=d->m_maxLength; 00254 uint lcw=0, rcw=0; 00255 00256 int tabBarHeight = tabBar()->sizeHint().height(); 00257 if ( cornerWidget( TopLeft ) && cornerWidget( TopLeft )->isVisible() ) 00258 lcw = QMAX( cornerWidget( TopLeft )->width(), tabBarHeight ); 00259 if ( cornerWidget( TopRight ) && cornerWidget( TopRight )->isVisible() ) 00260 rcw = QMAX( cornerWidget( TopRight )->width(), tabBarHeight ); 00261 00262 uint maxTabBarWidth = width() - lcw - rcw; 00263 00264 for ( ; newMaxLength > (uint)d->m_minLength; newMaxLength-- ) { 00265 if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth ) 00266 break; 00267 } 00268 } 00269 else 00270 newMaxLength = 4711; 00271 00272 // Update hinted or all tabs 00273 if ( d->m_CurrentMaxLength != newMaxLength ) { 00274 d->m_CurrentMaxLength = newMaxLength; 00275 for( int i = 0; i < count(); ++i ) 00276 updateTab( i ); 00277 } 00278 else if ( changeTabIndex != -1 ) 00279 updateTab( changeTabIndex ); 00280 } 00281 00282 void KTabWidget::updateTab( int index ) 00283 { 00284 TQString title = d->m_automaticResizeTabs ? d->m_tabNames[ index ] : TQTabWidget::label( index ); 00285 removeTabToolTip( page( index ) ); 00286 if ( title.length() > d->m_CurrentMaxLength ) { 00287 if ( TQStyleSheet::mightBeRichText( title ) ) 00288 setTabToolTip( page( index ), TQStyleSheet::escape(title) ); 00289 else 00290 setTabToolTip( page( index ), title ); 00291 } 00292 00293 title = KStringHandler::rsqueeze( title, d->m_CurrentMaxLength ).leftJustify( d->m_minLength, ' ' ); 00294 title.replace( '&', "&&" ); 00295 00296 if ( TQTabWidget::label( index ) != title ) 00297 TQTabWidget::setTabLabel( page( index ), title ); 00298 } 00299 00300 void KTabWidget::dragMoveEvent( TQDragMoveEvent *e ) 00301 { 00302 if ( isEmptyTabbarSpace( e->pos() ) ) { 00303 bool accept = false; 00304 // The receivers of the testCanDecode() signal has to adjust 00305 // 'accept' accordingly. 00306 emit testCanDecode( e, accept); 00307 e->accept( accept ); 00308 return; 00309 } 00310 e->accept( false ); 00311 TQTabWidget::dragMoveEvent( e ); 00312 } 00313 00314 void KTabWidget::dropEvent( TQDropEvent *e ) 00315 { 00316 if ( isEmptyTabbarSpace( e->pos() ) ) { 00317 emit ( receivedDropEvent( e ) ); 00318 return; 00319 } 00320 TQTabWidget::dropEvent( e ); 00321 } 00322 00323 #ifndef QT_NO_WHEELEVENT 00324 void KTabWidget::wheelEvent( TQWheelEvent *e ) 00325 { 00326 if ( e->orientation() == Qt::Horizontal ) 00327 return; 00328 00329 if ( isEmptyTabbarSpace( e->pos() ) ) 00330 wheelDelta( e->delta() ); 00331 else 00332 e->ignore(); 00333 } 00334 00335 void KTabWidget::wheelDelta( int delta ) 00336 { 00337 if ( count() < 2 ) 00338 return; 00339 00340 int page = currentPageIndex(); 00341 if ( delta < 0 ) 00342 page = (page + 1) % count(); 00343 else { 00344 page--; 00345 if ( page < 0 ) 00346 page = count() - 1; 00347 } 00348 setCurrentPage( page ); 00349 } 00350 #endif 00351 00352 void KTabWidget::mouseDoubleClickEvent( TQMouseEvent *e ) 00353 { 00354 if( e->button() != Qt::LeftButton ) 00355 return; 00356 00357 if ( isEmptyTabbarSpace( e->pos() ) ) { 00358 emit( mouseDoubleClick() ); 00359 return; 00360 } 00361 TQTabWidget::mouseDoubleClickEvent( e ); 00362 } 00363 00364 void KTabWidget::mousePressEvent( TQMouseEvent *e ) 00365 { 00366 if ( e->button() == Qt::RightButton ) { 00367 if ( isEmptyTabbarSpace( e->pos() ) ) { 00368 emit( contextMenu( mapToGlobal( e->pos() ) ) ); 00369 return; 00370 } 00371 } else if ( e->button() == Qt::MidButton ) { 00372 if ( isEmptyTabbarSpace( e->pos() ) ) { 00373 emit( mouseMiddleClick() ); 00374 return; 00375 } 00376 } 00377 TQTabWidget::mousePressEvent( e ); 00378 } 00379 00380 void KTabWidget::receivedDropEvent( int index, TQDropEvent *e ) 00381 { 00382 emit( receivedDropEvent( page( index ), e ) ); 00383 } 00384 00385 void KTabWidget::initiateDrag( int index ) 00386 { 00387 emit( initiateDrag( page( index ) ) ); 00388 } 00389 00390 void KTabWidget::contextMenu( int index, const TQPoint &p ) 00391 { 00392 emit( contextMenu( page( index ), p ) ); 00393 } 00394 00395 void KTabWidget::mouseDoubleClick( int index ) 00396 { 00397 emit( mouseDoubleClick( page( index ) ) ); 00398 } 00399 00400 void KTabWidget::mouseMiddleClick( int index ) 00401 { 00402 emit( mouseMiddleClick( page( index ) ) ); 00403 } 00404 00405 void KTabWidget::moveTab( int from, int to ) 00406 { 00407 TQString tablabel = label( from ); 00408 TQWidget *w = page( from ); 00409 TQColor color = tabColor( w ); 00410 TQIconSet tabiconset = tabIconSet( w ); 00411 TQString tabtooltip = tabToolTip( w ); 00412 bool current = ( w == currentPage() ); 00413 bool enabled = isTabEnabled( w ); 00414 blockSignals(true); 00415 removePage( w ); 00416 00417 // Work-around kmdi brain damage which calls showPage() in insertTab() 00418 TQTab * t = new TQTab(); 00419 t->setText(tablabel); 00420 TQTabWidget::insertTab( w, t, to ); 00421 if ( d->m_automaticResizeTabs ) { 00422 if ( to < 0 || to >= count() ) 00423 d->m_tabNames.append( TQString::null ); 00424 else 00425 d->m_tabNames.insert( d->m_tabNames.at( to ), TQString::null ); 00426 } 00427 00428 w = page( to ); 00429 changeTab( w, tabiconset, tablabel ); 00430 setTabToolTip( w, tabtooltip ); 00431 setTabColor( w, color ); 00432 if ( current ) 00433 showPage( w ); 00434 setTabEnabled( w, enabled ); 00435 blockSignals(false); 00436 00437 emit ( movedTab( from, to ) ); 00438 } 00439 00440 void KTabWidget::removePage( TQWidget * w ) { 00441 if ( d->m_automaticResizeTabs ) { 00442 int index = indexOf( w ); 00443 if ( index != -1 ) 00444 d->m_tabNames.remove( d->m_tabNames.at( index ) ); 00445 } 00446 TQTabWidget::removePage( w ); 00447 if ( d->m_automaticResizeTabs ) 00448 resizeTabs(); 00449 } 00450 00451 00452 bool KTabWidget::isEmptyTabbarSpace( const TQPoint &point ) const 00453 { 00454 TQSize size( tabBar()->sizeHint() ); 00455 if ( ( tabPosition()==Top && point.y()< size.height() ) || ( tabPosition()==Bottom && point.y()>(height()-size.height() ) ) ) { 00456 TQWidget *rightcorner = cornerWidget( TopRight ); 00457 if ( rightcorner ) { 00458 if ( point.x()>=width()-rightcorner->width() ) 00459 return false; 00460 } 00461 TQWidget *leftcorner = cornerWidget( TopLeft ); 00462 if ( leftcorner ) { 00463 if ( point.x()<=leftcorner->width() ) 00464 return false; 00465 } 00466 TQTab *tab = tabBar()->selectTab( tabBar()->mapFromParent( point ) ); 00467 if( !tab ) 00468 return true; 00469 } 00470 return false; 00471 } 00472 00473 void KTabWidget::setHoverCloseButton( bool button ) 00474 { 00475 static_cast<KTabBar*>(tabBar())->setHoverCloseButton( button ); 00476 } 00477 00478 bool KTabWidget::hoverCloseButton() const 00479 { 00480 return static_cast<KTabBar*>(tabBar())->hoverCloseButton(); 00481 } 00482 00483 void KTabWidget::setHoverCloseButtonDelayed( bool delayed ) 00484 { 00485 static_cast<KTabBar*>(tabBar())->setHoverCloseButtonDelayed( delayed ); 00486 } 00487 00488 bool KTabWidget::hoverCloseButtonDelayed() const 00489 { 00490 return static_cast<KTabBar*>(tabBar())->hoverCloseButtonDelayed(); 00491 } 00492 00493 void KTabWidget::setAutomaticResizeTabs( bool enabled ) 00494 { 00495 if ( d->m_automaticResizeTabs==enabled ) 00496 return; 00497 00498 d->m_automaticResizeTabs = enabled; 00499 if ( enabled ) { 00500 d->m_tabNames.clear(); 00501 for( int i = 0; i < count(); ++i ) 00502 d->m_tabNames.append( tabBar()->tabAt( i )->text() ); 00503 } 00504 else 00505 for( int i = 0; i < count(); ++i ) 00506 tabBar()->tabAt( i )->setText( d->m_tabNames[ i ] ); 00507 resizeTabs(); 00508 } 00509 00510 bool KTabWidget::automaticResizeTabs() const 00511 { 00512 return d->m_automaticResizeTabs; 00513 } 00514 00515 void KTabWidget::closeRequest( int index ) 00516 { 00517 emit( closeRequest( page( index ) ) ); 00518 } 00519 00520 void KTabWidget::resizeEvent( TQResizeEvent *e ) 00521 { 00522 TQTabWidget::resizeEvent( e ); 00523 resizeTabs(); 00524 } 00525 00526 #include "ktabwidget.moc"