ktabbar.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 <tqcursor.h> 00023 #include <tqpainter.h> 00024 #include <tqstyle.h> 00025 #include <tqtimer.h> 00026 #include <tqpushbutton.h> 00027 #include <tqtooltip.h> 00028 00029 #include <kglobalsettings.h> 00030 #include <kiconloader.h> 00031 #include <klocale.h> 00032 00033 #include "ktabbar.h" 00034 #include "ktabwidget.h" 00035 00036 KTabBar::KTabBar( TQWidget *parent, const char *name ) 00037 : TQTabBar( parent, name ), mReorderStartTab( -1 ), mReorderPreviousTab( -1 ), 00038 mHoverCloseButtonTab( 0 ), mDragSwitchTab( 0 ), mHoverCloseButton( 0 ), 00039 mHoverCloseButtonEnabled( false ), mHoverCloseButtonDelayed( true ), 00040 mTabReorderingEnabled( false ), mTabCloseActivatePrevious( false ) 00041 { 00042 setAcceptDrops( true ); 00043 setMouseTracking( true ); 00044 00045 mEnableCloseButtonTimer = new TQTimer( this ); 00046 connect( mEnableCloseButtonTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( enableCloseButton() ) ); 00047 00048 mActivateDragSwitchTabTimer = new TQTimer( this ); 00049 connect( mActivateDragSwitchTabTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( activateDragSwitchTab() ) ); 00050 00051 connect(this, TQT_SIGNAL(layoutChanged()), TQT_SLOT(onLayoutChange())); 00052 } 00053 00054 KTabBar::~KTabBar() 00055 { 00056 //For the future 00057 //delete d; 00058 } 00059 00060 void KTabBar::setTabEnabled( int id, bool enabled ) 00061 { 00062 TQTab * t = tab( id ); 00063 if ( t ) { 00064 if ( t->isEnabled() != enabled ) { 00065 t->setEnabled( enabled ); 00066 TQRect r( t->rect() ); 00067 if ( !enabled && id == currentTab() && count()>1 ) { 00068 TQPtrList<TQTab> *tablist = tabList(); 00069 if ( mTabCloseActivatePrevious ) 00070 t = tablist->at( count()-2 ); 00071 else { 00072 int index = indexOf( id ); 00073 index += ( index+1 == count() ) ? -1 : 1; 00074 t = tabAt( index ); 00075 } 00076 00077 if ( t->isEnabled() ) { 00078 r = r.unite( t->rect() ); 00079 tablist->append( tablist->take( tablist->findRef( t ) ) ); 00080 emit selected( t->identifier() ); 00081 } 00082 } 00083 repaint( r ); 00084 } 00085 } 00086 } 00087 00088 void KTabBar::mouseDoubleClickEvent( TQMouseEvent *e ) 00089 { 00090 if( e->button() != Qt::LeftButton ) 00091 return; 00092 00093 TQTab *tab = selectTab( e->pos() ); 00094 if( tab ) { 00095 emit( mouseDoubleClick( indexOf( tab->identifier() ) ) ); 00096 return; 00097 } 00098 TQTabBar::mouseDoubleClickEvent( e ); 00099 } 00100 00101 void KTabBar::mousePressEvent( TQMouseEvent *e ) 00102 { 00103 if( e->button() == Qt::LeftButton ) { 00104 mEnableCloseButtonTimer->stop(); 00105 mDragStart = e->pos(); 00106 } 00107 else if( e->button() == Qt::RightButton ) { 00108 TQTab *tab = selectTab( e->pos() ); 00109 if( tab ) { 00110 emit( contextMenu( indexOf( tab->identifier() ), mapToGlobal( e->pos() ) ) ); 00111 return; 00112 } 00113 } 00114 TQTabBar::mousePressEvent( e ); 00115 } 00116 00117 void KTabBar::mouseMoveEvent( TQMouseEvent *e ) 00118 { 00119 if ( e->state() == Qt::LeftButton ) { 00120 TQTab *tab = selectTab( e->pos() ); 00121 if ( mDragSwitchTab && tab != mDragSwitchTab ) { 00122 mActivateDragSwitchTabTimer->stop(); 00123 mDragSwitchTab = 0; 00124 } 00125 00126 int delay = KGlobalSettings::dndEventDelay(); 00127 TQPoint newPos = e->pos(); 00128 if( newPos.x() > mDragStart.x()+delay || newPos.x() < mDragStart.x()-delay || 00129 newPos.y() > mDragStart.y()+delay || newPos.y() < mDragStart.y()-delay ) 00130 { 00131 if( tab ) { 00132 emit( initiateDrag( indexOf( tab->identifier() ) ) ); 00133 return; 00134 } 00135 } 00136 } 00137 else if ( e->state() == Qt::MidButton ) { 00138 if (mReorderStartTab==-1) { 00139 int delay = KGlobalSettings::dndEventDelay(); 00140 TQPoint newPos = e->pos(); 00141 if( newPos.x() > mDragStart.x()+delay || newPos.x() < mDragStart.x()-delay || 00142 newPos.y() > mDragStart.y()+delay || newPos.y() < mDragStart.y()-delay ) 00143 { 00144 TQTab *tab = selectTab( e->pos() ); 00145 if( tab && mTabReorderingEnabled ) { 00146 mReorderStartTab = indexOf( tab->identifier() ); 00147 grabMouse( tqsizeAllCursor ); 00148 return; 00149 } 00150 } 00151 } 00152 else { 00153 TQTab *tab = selectTab( e->pos() ); 00154 if( tab ) { 00155 int reorderStopTab = indexOf( tab->identifier() ); 00156 if ( mReorderStartTab!=reorderStopTab && mReorderPreviousTab!=reorderStopTab ) { 00157 emit( moveTab( mReorderStartTab, reorderStopTab ) ); 00158 mReorderPreviousTab=mReorderStartTab; 00159 mReorderStartTab=reorderStopTab; 00160 return; 00161 } 00162 } 00163 } 00164 } 00165 00166 if ( mHoverCloseButtonEnabled && mReorderStartTab==-1) { 00167 TQTab *t = selectTab( e->pos() ); 00168 if( t && t->iconSet() && t->isEnabled() ) { 00169 TQPixmap pixmap = t->iconSet()->pixmap( TQIconSet::Small, TQIconSet::Normal ); 00170 TQRect rect( 0, 0, pixmap.width() + 4, pixmap.height() +4); 00171 00172 int xoff = 0, yoff = 0; 00173 // The additional offsets were found by try and error, TODO: find the rational behind them 00174 if ( t == tab( currentTab() ) ) { 00175 xoff = style().pixelMetric( TQStyle::PM_TabBarTabShiftHorizontal, this ) + 3; 00176 yoff = style().pixelMetric( TQStyle::PM_TabBarTabShiftVertical, this ) - 4; 00177 } 00178 else { 00179 xoff = 7; 00180 yoff = 0; 00181 } 00182 rect.moveLeft( t->rect().left() + 2 + xoff ); 00183 rect.moveTop( t->rect().center().y()-pixmap.height()/2 + yoff ); 00184 if ( rect.contains( e->pos() ) ) { 00185 if ( mHoverCloseButton ) { 00186 if ( mHoverCloseButtonTab == t ) 00187 return; 00188 mEnableCloseButtonTimer->stop(); 00189 mHoverCloseButton->deleteLater(); 00190 mHoverCloseButton = 0; 00191 } 00192 00193 mHoverCloseButton = new TQPushButton( this ); 00194 mHoverCloseButton->setIconSet( KGlobal::iconLoader()->loadIconSet("fileclose", KIcon::Toolbar, KIcon::SizeSmall) ); 00195 mHoverCloseButton->setGeometry( rect ); 00196 TQToolTip::add(mHoverCloseButton,i18n("Close this tab")); 00197 mHoverCloseButton->setFlat(true); 00198 mHoverCloseButton->show(); 00199 if ( mHoverCloseButtonDelayed ) { 00200 mHoverCloseButton->setEnabled(false); 00201 mEnableCloseButtonTimer->start( TQApplication::doubleClickInterval(), true ); 00202 } 00203 mHoverCloseButtonTab = t; 00204 connect( mHoverCloseButton, TQT_SIGNAL( clicked() ), TQT_SLOT( closeButtonClicked() ) ); 00205 return; 00206 } 00207 } 00208 if ( mHoverCloseButton ) { 00209 mEnableCloseButtonTimer->stop(); 00210 mHoverCloseButton->deleteLater(); 00211 mHoverCloseButton = 0; 00212 } 00213 } 00214 00215 TQTabBar::mouseMoveEvent( e ); 00216 } 00217 00218 void KTabBar::enableCloseButton() 00219 { 00220 mHoverCloseButton->setEnabled(true); 00221 } 00222 00223 void KTabBar::activateDragSwitchTab() 00224 { 00225 TQTab *tab = selectTab( mapFromGlobal( TQCursor::pos() ) ); 00226 if ( tab && mDragSwitchTab == tab ) 00227 setCurrentTab( mDragSwitchTab ); 00228 mDragSwitchTab = 0; 00229 } 00230 00231 void KTabBar::mouseReleaseEvent( TQMouseEvent *e ) 00232 { 00233 if( e->button() == Qt::MidButton ) { 00234 if ( mReorderStartTab==-1 ) { 00235 TQTab *tab = selectTab( e->pos() ); 00236 if( tab ) { 00237 emit( mouseMiddleClick( indexOf( tab->identifier() ) ) ); 00238 return; 00239 } 00240 } 00241 else { 00242 releaseMouse(); 00243 setCursor( tqarrowCursor ); 00244 mReorderStartTab=-1; 00245 mReorderPreviousTab=-1; 00246 } 00247 } 00248 TQTabBar::mouseReleaseEvent( e ); 00249 } 00250 00251 void KTabBar::dragMoveEvent( TQDragMoveEvent *e ) 00252 { 00253 TQTab *tab = selectTab( e->pos() ); 00254 if( tab ) { 00255 bool accept = false; 00256 // The receivers of the testCanDecode() signal has to adjust 00257 // 'accept' accordingly. 00258 emit testCanDecode( e, accept); 00259 if ( accept && tab != TQTabBar::tab( currentTab() ) ) { 00260 mDragSwitchTab = tab; 00261 mActivateDragSwitchTabTimer->start( TQApplication::doubleClickInterval()*2, true ); 00262 } 00263 e->accept( accept ); 00264 return; 00265 } 00266 e->accept( false ); 00267 TQTabBar::dragMoveEvent( e ); 00268 } 00269 00270 void KTabBar::dropEvent( TQDropEvent *e ) 00271 { 00272 TQTab *tab = selectTab( e->pos() ); 00273 if( tab ) { 00274 mActivateDragSwitchTabTimer->stop(); 00275 mDragSwitchTab = 0; 00276 emit( receivedDropEvent( indexOf( tab->identifier() ) , e ) ); 00277 return; 00278 } 00279 TQTabBar::dropEvent( e ); 00280 } 00281 00282 #ifndef QT_NO_WHEELEVENT 00283 void KTabBar::wheelEvent( TQWheelEvent *e ) 00284 { 00285 if ( e->orientation() == Qt::Horizontal ) 00286 return; 00287 00288 emit( wheelDelta( e->delta() ) ); 00289 } 00290 #endif 00291 00292 void KTabBar::setTabColor( int id, const TQColor& color ) 00293 { 00294 TQTab *t = tab( id ); 00295 if ( t ) { 00296 mTabColors.insert( id, color ); 00297 repaint( t->rect(), false ); 00298 } 00299 } 00300 00301 const TQColor &KTabBar::tabColor( int id ) const 00302 { 00303 if ( mTabColors.contains( id ) ) 00304 return mTabColors[id]; 00305 00306 return colorGroup().foreground(); 00307 } 00308 00309 int KTabBar::insertTab( TQTab *t, int index ) 00310 { 00311 int res = TQTabBar::insertTab( t, index ); 00312 00313 if ( mTabCloseActivatePrevious && count() > 2 ) { 00314 TQPtrList<TQTab> *tablist = tabList(); 00315 tablist->insert( count()-2, tablist->take( tablist->findRef( t ) ) ); 00316 } 00317 00318 return res; 00319 } 00320 00321 void KTabBar::removeTab( TQTab *t ) 00322 { 00323 mTabColors.remove( t->identifier() ); 00324 TQTabBar::removeTab( t ); 00325 } 00326 00327 void KTabBar::paintLabel( TQPainter *p, const TQRect& br, 00328 TQTab *t, bool has_focus ) const 00329 { 00330 TQRect r = br; 00331 bool selected = currentTab() == t->identifier(); 00332 if ( t->iconSet() ) { 00333 // the tab has an iconset, draw it in the right mode 00334 TQIconSet::Mode mode = ( t->isEnabled() && isEnabled() ) 00335 ? TQIconSet::Normal : TQIconSet::Disabled; 00336 if ( mode == TQIconSet::Normal && has_focus ) 00337 mode = TQIconSet::Active; 00338 TQPixmap pixmap = t->iconSet()->pixmap( TQIconSet::Small, mode ); 00339 int pixw = pixmap.width(); 00340 int pixh = pixmap.height(); 00341 r.setLeft( r.left() + pixw + 4 ); 00342 r.setRight( r.right() + 2 ); 00343 00344 int inactiveXShift = style().pixelMetric( TQStyle::PM_TabBarTabShiftHorizontal, this ); 00345 int inactiveYShift = style().pixelMetric( TQStyle::PM_TabBarTabShiftVertical, this ); 00346 00347 int right = t->text().isEmpty() ? br.right() - pixw : br.left() + 2; 00348 00349 p->drawPixmap( right + (selected ? 0 : inactiveXShift), 00350 br.center().y() - pixh / 2 + (selected ? 0 : inactiveYShift), 00351 pixmap ); 00352 } 00353 00354 TQStyle::SFlags flags = TQStyle::Style_Default; 00355 00356 if ( isEnabled() && t->isEnabled() ) 00357 flags |= TQStyle::Style_Enabled; 00358 if ( has_focus ) 00359 flags |= TQStyle::Style_HasFocus; 00360 00361 TQColorGroup cg( colorGroup() ); 00362 if ( mTabColors.contains( t->identifier() ) ) 00363 cg.setColor( TQColorGroup::Foreground, mTabColors[t->identifier()] ); 00364 00365 style().drawControl( TQStyle::CE_TabBarLabel, p, this, r, 00366 t->isEnabled() ? cg : palette().disabled(), 00367 flags, TQStyleOption(t) ); 00368 } 00369 00370 bool KTabBar::isTabReorderingEnabled() const 00371 { 00372 return mTabReorderingEnabled; 00373 } 00374 00375 void KTabBar::setTabReorderingEnabled( bool on ) 00376 { 00377 mTabReorderingEnabled = on; 00378 } 00379 00380 bool KTabBar::tabCloseActivatePrevious() const 00381 { 00382 return mTabCloseActivatePrevious; 00383 } 00384 00385 void KTabBar::setTabCloseActivatePrevious( bool on ) 00386 { 00387 mTabCloseActivatePrevious = on; 00388 } 00389 00390 void KTabBar::closeButtonClicked() 00391 { 00392 emit closeRequest( indexOf( mHoverCloseButtonTab->identifier() ) ); 00393 } 00394 00395 void KTabBar::setHoverCloseButton( bool button ) 00396 { 00397 mHoverCloseButtonEnabled = button; 00398 if ( !button ) 00399 onLayoutChange(); 00400 } 00401 00402 bool KTabBar::hoverCloseButton() const 00403 { 00404 return mHoverCloseButtonEnabled; 00405 } 00406 00407 void KTabBar::setHoverCloseButtonDelayed( bool delayed ) 00408 { 00409 mHoverCloseButtonDelayed = delayed; 00410 } 00411 00412 bool KTabBar::hoverCloseButtonDelayed() const 00413 { 00414 return mHoverCloseButtonDelayed; 00415 } 00416 00417 void KTabBar::onLayoutChange() 00418 { 00419 mEnableCloseButtonTimer->stop(); 00420 delete mHoverCloseButton; 00421 mHoverCloseButton = 0; 00422 mHoverCloseButtonTab = 0; 00423 mActivateDragSwitchTabTimer->stop(); 00424 mDragSwitchTab = 0; 00425 } 00426 00427 #include "ktabbar.moc"