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 <tdeconfig.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 bool m_mouseWheelScroll; 00039 00040 // Holds the full names of the tab, otherwise all we know about is the shortened name 00041 TQStringList m_tabNames; 00042 00043 KTabWidgetPrivate() : m_automaticResizeTabs(false), m_mouseWheelScroll(true) 00044 { 00045 TDEConfigGroupSaver groupsaver(TDEGlobal::config(), "General"); 00046 m_maxLength = TDEGlobal::config()->readNumEntry("MaximumTabLength", 30); 00047 m_minLength = TDEGlobal::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::setMouseWheelScroll(bool mouseWheelScroll) 00126 { 00127 d->m_mouseWheelScroll = mouseWheelScroll; 00128 } 00129 00130 void KTabWidget::setTabColor( TQWidget *w, const TQColor& color ) 00131 { 00132 TQTab *t = tabBar()->tabAt( indexOf( w ) ); 00133 if (t) { 00134 static_cast<KTabBar*>(tabBar())->setTabColor( t->identifier(), color ); 00135 } 00136 } 00137 00138 TQColor KTabWidget::tabColor( TQWidget *w ) const 00139 { 00140 TQTab *t = tabBar()->tabAt( indexOf( w ) ); 00141 if (t) { 00142 return static_cast<KTabBar*>(tabBar())->tabColor( t->identifier() ); 00143 } else { 00144 return TQColor(); 00145 } 00146 } 00147 00148 void KTabWidget::setTabReorderingEnabled( bool on) 00149 { 00150 static_cast<KTabBar*>(tabBar())->setTabReorderingEnabled( on ); 00151 } 00152 00153 bool KTabWidget::isTabReorderingEnabled() const 00154 { 00155 return static_cast<KTabBar*>(tabBar())->isTabReorderingEnabled(); 00156 } 00157 00158 void KTabWidget::setTabCloseActivatePrevious( bool previous) 00159 { 00160 static_cast<KTabBar*>(tabBar())->setTabCloseActivatePrevious( previous ); 00161 } 00162 00163 bool KTabWidget::tabCloseActivatePrevious() const 00164 { 00165 return static_cast<KTabBar*>(tabBar())->tabCloseActivatePrevious(); 00166 } 00167 00168 unsigned int KTabWidget::tabBarWidthForMaxChars( uint maxLength ) 00169 { 00170 int hframe, overlap; 00171 hframe = tabBar()->style().pixelMetric( TQStyle::PM_TabBarTabHSpace, tabBar() ); 00172 overlap = tabBar()->style().pixelMetric( TQStyle::PM_TabBarTabOverlap, tabBar() ); 00173 00174 TQFontMetrics fm = tabBar()->fontMetrics(); 00175 int x = 0; 00176 for( int i=0; i < count(); ++i ) { 00177 TQString newTitle = d->m_tabNames[ i ]; 00178 newTitle = KStringHandler::rsqueeze( newTitle, maxLength ).leftJustify( d->m_minLength, ' ' ); 00179 00180 TQTab* tab = tabBar()->tabAt( i ); 00181 int lw = fm.width( newTitle ); 00182 int iw = 0; 00183 if ( tab->iconSet() ) 00184 iw = tab->iconSet()->pixmap( TQIconSet::Small, TQIconSet::Normal ).width() + 4; 00185 x += ( tabBar()->style().tqsizeFromContents( TQStyle::CT_TabBarTab, this, 00186 TQSize( TQMAX( lw + hframe + iw, TQApplication::globalStrut().width() ), 0 ), 00187 TQStyleOption( tab ) ) ).width(); 00188 } 00189 return x; 00190 } 00191 00192 void KTabWidget::changeTab( TQWidget *w, const TQString &label ) 00193 { 00194 TQTabWidget::changeTab( w, label ); 00195 if ( d->m_automaticResizeTabs ) { 00196 int index = indexOf( w ); 00197 if ( index != -1 ) { 00198 d->m_tabNames[ index ] = label; 00199 resizeTabs( index ); 00200 } 00201 } 00202 } 00203 00204 void KTabWidget::changeTab( TQWidget *w, const TQIconSet &iconset, const TQString &label ) 00205 { 00206 TQTabWidget::changeTab( w, iconset, label ); 00207 if ( d->m_automaticResizeTabs ) { 00208 int index = indexOf( w ); 00209 if ( index != -1 ) { 00210 d->m_tabNames[ index ] = label; 00211 resizeTabs( index ); 00212 } 00213 } 00214 } 00215 00216 TQString KTabWidget::label( int index ) const 00217 { 00218 if ( d->m_automaticResizeTabs ) { 00219 if ( index >= 0 && index < count() ) 00220 return d->m_tabNames[ index ]; 00221 else 00222 return TQString::null; 00223 } 00224 else 00225 return TQTabWidget::label( index ); 00226 } 00227 00228 TQString KTabWidget::tabLabel( TQWidget * w ) const 00229 { 00230 if ( d->m_automaticResizeTabs ) { 00231 int index = indexOf( w ); 00232 if ( index == -1 ) 00233 return TQString::null; 00234 else 00235 return d->m_tabNames[ index ]; 00236 } 00237 else 00238 return TQTabWidget::tabLabel( w ); 00239 } 00240 00241 void KTabWidget::setTabLabel( TQWidget *w, const TQString &l ) 00242 { 00243 TQTabWidget::setTabLabel( w, l ); 00244 if ( d->m_automaticResizeTabs ) { 00245 int index = indexOf( w ); 00246 if ( index != -1 ) { 00247 d->m_tabNames[ index ] = l; 00248 resizeTabs( index ); 00249 } 00250 } 00251 } 00252 00253 void KTabWidget::resizeTabs( int changeTabIndex ) 00254 { 00255 uint newMaxLength; 00256 if ( d->m_automaticResizeTabs ) { 00257 // Calculate new max length 00258 newMaxLength=d->m_maxLength; 00259 uint lcw=0, rcw=0; 00260 00261 int tabBarHeight = tabBar()->sizeHint().height(); 00262 if ( cornerWidget( TopLeft ) && cornerWidget( TopLeft )->isVisible() ) 00263 lcw = TQMAX( cornerWidget( TopLeft )->width(), tabBarHeight ); 00264 if ( cornerWidget( TopRight ) && cornerWidget( TopRight )->isVisible() ) 00265 rcw = TQMAX( cornerWidget( TopRight )->width(), tabBarHeight ); 00266 00267 uint maxTabBarWidth = width() - lcw - rcw; 00268 00269 for ( ; newMaxLength > (uint)d->m_minLength; newMaxLength-- ) { 00270 if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth ) 00271 break; 00272 } 00273 } 00274 else 00275 newMaxLength = 4711; 00276 00277 // Update hinted or all tabs 00278 if ( d->m_CurrentMaxLength != newMaxLength ) { 00279 d->m_CurrentMaxLength = newMaxLength; 00280 for( int i = 0; i < count(); ++i ) 00281 updateTab( i ); 00282 } 00283 else if ( changeTabIndex != -1 ) 00284 updateTab( changeTabIndex ); 00285 } 00286 00287 void KTabWidget::updateTab( int index ) 00288 { 00289 TQString title = d->m_automaticResizeTabs ? d->m_tabNames[ index ] : TQTabWidget::label( index ); 00290 removeTabToolTip( page( index ) ); 00291 if ( title.length() > d->m_CurrentMaxLength ) { 00292 if ( TQStyleSheet::mightBeRichText( title ) ) 00293 setTabToolTip( page( index ), TQStyleSheet::escape(title) ); 00294 else 00295 setTabToolTip( page( index ), title ); 00296 } 00297 00298 title = KStringHandler::rsqueeze( title, d->m_CurrentMaxLength ).leftJustify( d->m_minLength, ' ' ); 00299 title.replace( '&', "&&" ); 00300 00301 if ( TQTabWidget::label( index ) != title ) 00302 TQTabWidget::setTabLabel( page( index ), title ); 00303 } 00304 00305 void KTabWidget::dragMoveEvent( TQDragMoveEvent *e ) 00306 { 00307 if ( isEmptyTabbarSpace( e->pos() ) ) { 00308 bool accept = false; 00309 // The receivers of the testCanDecode() signal has to adjust 00310 // 'accept' accordingly. 00311 emit testCanDecode( e, accept); 00312 e->accept( accept ); 00313 return; 00314 } 00315 e->accept( false ); 00316 TQTabWidget::dragMoveEvent( e ); 00317 } 00318 00319 void KTabWidget::dropEvent( TQDropEvent *e ) 00320 { 00321 if ( isEmptyTabbarSpace( e->pos() ) ) { 00322 emit ( receivedDropEvent( e ) ); 00323 return; 00324 } 00325 TQTabWidget::dropEvent( e ); 00326 } 00327 00328 #ifndef QT_NO_WHEELEVENT 00329 void KTabWidget::wheelEvent( TQWheelEvent *e ) 00330 { 00331 if ( e->orientation() == Qt::Horizontal ) 00332 return; 00333 00334 if ( isEmptyTabbarSpace( e->pos() ) ) 00335 wheelDelta( e->delta() ); 00336 else 00337 e->ignore(); 00338 } 00339 00340 void KTabWidget::wheelDelta(int delta) 00341 { 00342 if (count()<2 || !d->m_mouseWheelScroll) 00343 return; 00344 00345 int page = currentPageIndex(); 00346 if (delta<0) 00347 page = (page + 1) % count(); 00348 else 00349 { 00350 page--; 00351 if (page<0) 00352 page = count() - 1; 00353 } 00354 setCurrentPage(page); 00355 } 00356 #endif 00357 00358 void KTabWidget::mouseDoubleClickEvent( TQMouseEvent *e ) 00359 { 00360 if( e->button() != Qt::LeftButton ) 00361 return; 00362 00363 if ( isEmptyTabbarSpace( e->pos() ) ) { 00364 emit( mouseDoubleClick() ); 00365 return; 00366 } 00367 TQTabWidget::mouseDoubleClickEvent( e ); 00368 } 00369 00370 void KTabWidget::mousePressEvent( TQMouseEvent *e ) 00371 { 00372 if ( e->button() == Qt::RightButton ) { 00373 if ( isEmptyTabbarSpace( e->pos() ) ) { 00374 emit( contextMenu( mapToGlobal( e->pos() ) ) ); 00375 return; 00376 } 00377 } else if ( e->button() == Qt::MidButton ) { 00378 if ( isEmptyTabbarSpace( e->pos() ) ) { 00379 emit( mouseMiddleClick() ); 00380 return; 00381 } 00382 } 00383 TQTabWidget::mousePressEvent( e ); 00384 } 00385 00386 void KTabWidget::receivedDropEvent( int index, TQDropEvent *e ) 00387 { 00388 emit( receivedDropEvent( page( index ), e ) ); 00389 } 00390 00391 void KTabWidget::initiateDrag( int index ) 00392 { 00393 emit( initiateDrag( page( index ) ) ); 00394 } 00395 00396 void KTabWidget::contextMenu( int index, const TQPoint &p ) 00397 { 00398 emit( contextMenu( page( index ), p ) ); 00399 } 00400 00401 void KTabWidget::mouseDoubleClick( int index ) 00402 { 00403 emit( mouseDoubleClick( page( index ) ) ); 00404 } 00405 00406 void KTabWidget::mouseMiddleClick( int index ) 00407 { 00408 emit( mouseMiddleClick( page( index ) ) ); 00409 } 00410 00411 void KTabWidget::moveTab( int from, int to ) 00412 { 00413 TQString tablabel = label( from ); 00414 TQWidget *w = page( from ); 00415 TQColor color = tabColor( w ); 00416 TQIconSet tabiconset = tabIconSet( w ); 00417 TQString tabtooltip = tabToolTip( w ); 00418 bool current = ( w == currentPage() ); 00419 bool enabled = isTabEnabled( w ); 00420 blockSignals(true); 00421 removePage( w ); 00422 00423 // Work-around tdemdi brain damage which calls showPage() in insertTab() 00424 TQTab * t = new TQTab(); 00425 t->setText(tablabel); 00426 TQTabWidget::insertTab( w, t, to ); 00427 if ( d->m_automaticResizeTabs ) { 00428 if ( to < 0 || to >= count() ) 00429 d->m_tabNames.append( TQString::null ); 00430 else 00431 d->m_tabNames.insert( d->m_tabNames.at( to ), TQString::null ); 00432 } 00433 00434 w = page( to ); 00435 changeTab( w, tabiconset, tablabel ); 00436 setTabToolTip( w, tabtooltip ); 00437 setTabColor( w, color ); 00438 if ( current ) 00439 showPage( w ); 00440 setTabEnabled( w, enabled ); 00441 blockSignals(false); 00442 00443 emit ( movedTab( from, to ) ); 00444 } 00445 00446 void KTabWidget::removePage( TQWidget * w ) { 00447 if ( d->m_automaticResizeTabs ) { 00448 int index = indexOf( w ); 00449 if ( index != -1 ) 00450 d->m_tabNames.remove( d->m_tabNames.at( index ) ); 00451 } 00452 TQTabWidget::removePage( w ); 00453 if ( d->m_automaticResizeTabs ) 00454 resizeTabs(); 00455 } 00456 00457 00458 bool KTabWidget::isEmptyTabbarSpace( const TQPoint &point ) const 00459 { 00460 TQSize size( tabBar()->sizeHint() ); 00461 if ( ( tabPosition()==Top && point.y()< size.height() ) || ( tabPosition()==Bottom && point.y()>(height()-size.height() ) ) ) { 00462 TQWidget *rightcorner = cornerWidget( TopRight ); 00463 if ( rightcorner ) { 00464 if ( point.x()>=width()-rightcorner->width() ) 00465 return false; 00466 } 00467 TQWidget *leftcorner = cornerWidget( TopLeft ); 00468 if ( leftcorner ) { 00469 if ( point.x()<=leftcorner->width() ) 00470 return false; 00471 } 00472 TQTab *tab = tabBar()->selectTab( tabBar()->mapFromParent( point ) ); 00473 if( !tab ) 00474 return true; 00475 } 00476 return false; 00477 } 00478 00479 void KTabWidget::setHoverCloseButton( bool button ) 00480 { 00481 static_cast<KTabBar*>(tabBar())->setHoverCloseButton( button ); 00482 } 00483 00484 bool KTabWidget::hoverCloseButton() const 00485 { 00486 return static_cast<KTabBar*>(tabBar())->hoverCloseButton(); 00487 } 00488 00489 void KTabWidget::setHoverCloseButtonDelayed( bool delayed ) 00490 { 00491 static_cast<KTabBar*>(tabBar())->setHoverCloseButtonDelayed( delayed ); 00492 } 00493 00494 bool KTabWidget::hoverCloseButtonDelayed() const 00495 { 00496 return static_cast<KTabBar*>(tabBar())->hoverCloseButtonDelayed(); 00497 } 00498 00499 void KTabWidget::setAutomaticResizeTabs( bool enabled ) 00500 { 00501 if ( d->m_automaticResizeTabs==enabled ) 00502 return; 00503 00504 d->m_automaticResizeTabs = enabled; 00505 if ( enabled ) { 00506 d->m_tabNames.clear(); 00507 for( int i = 0; i < count(); ++i ) 00508 d->m_tabNames.append( tabBar()->tabAt( i )->text() ); 00509 } 00510 else 00511 for( int i = 0; i < count(); ++i ) 00512 tabBar()->tabAt( i )->setText( d->m_tabNames[ i ] ); 00513 resizeTabs(); 00514 } 00515 00516 bool KTabWidget::automaticResizeTabs() const 00517 { 00518 return d->m_automaticResizeTabs; 00519 } 00520 00521 void KTabWidget::closeRequest( int index ) 00522 { 00523 emit( closeRequest( page( index ) ) ); 00524 } 00525 00526 void KTabWidget::resizeEvent( TQResizeEvent *e ) 00527 { 00528 TQTabWidget::resizeEvent( e ); 00529 resizeTabs(); 00530 } 00531 00532 #include "ktabwidget.moc"