00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ktabwidget.h"
00023
00024 #include <QtGui/QApplication>
00025 #include <QtGui/QDragMoveEvent>
00026 #include <QtGui/QDropEvent>
00027 #include <QtGui/QMouseEvent>
00028 #include <QtGui/QStyle>
00029 #include <QtGui/QStyleOption>
00030 #include <QtGui/QTextDocument>
00031 #include <QtGui/QWheelEvent>
00032 #include <QtCore/QList>
00033
00034 #include <ksharedconfig.h>
00035 #include <kiconloader.h>
00036 #include <kstringhandler.h>
00037 #include <kdebug.h>
00038
00039 #include <ktabbar.h>
00040
00041 #include <kconfiggroup.h>
00042
00043 class KTabWidget::Private
00044 {
00045 public:
00046 enum {
00047 ResizeEnabled = 0,
00048 ResizeDisabled,
00049 ResizeLater
00050 } m_resizeSuspend;
00051
00052 Private( KTabWidget *parent )
00053 : m_parent( parent ),
00054 m_automaticResizeTabs( false ),
00055 m_resizeSuspend(ResizeEnabled)
00056 {
00057
00058 KConfigGroup cg(KGlobal::config(), "General");
00059 m_maxLength = cg.readEntry("MaximumTabLength", 30);
00060 m_minLength = cg.readEntry("MinimumTabLength", 3);
00061 Q_ASSERT(m_maxLength >= m_minLength);
00062 m_currentTabLength = m_minLength;
00063 }
00064
00065 KTabWidget *m_parent;
00066 bool m_automaticResizeTabs;
00067 int m_maxLength;
00068 int m_minLength;
00069 int m_currentTabLength;
00070
00071
00072
00073 QStringList m_tabNames;
00074
00075
00076 QList<QWidget*> m_previousTabList;
00077
00078 bool isEmptyTabbarSpace( const QPoint & ) const;
00079 void resizeTabs( int changedTabIndex = -1 );
00080 void updateTab( int index );
00081 void removeTab( int index );
00082 };
00083
00084 bool KTabWidget::Private::isEmptyTabbarSpace( const QPoint &point ) const
00085 {
00086 if (m_parent->count() == 0) {
00087 return true;
00088 }
00089 if (m_parent->tabBar()->isHidden()) {
00090 return false;
00091 }
00092 QSize size( m_parent->tabBar()->sizeHint() );
00093 if ( ( m_parent->tabPosition() == QTabWidget::North && point.y() < size.height() ) ||
00094 ( m_parent->tabPosition() == QTabWidget::South && point.y() > (m_parent->height() - size.height() ) ) ) {
00095
00096 QWidget *rightcorner = m_parent->cornerWidget( Qt::TopRightCorner );
00097 if ( rightcorner && rightcorner->isVisible() ) {
00098 if ( point.x() >= m_parent->width()-rightcorner->width() )
00099 return false;
00100 }
00101
00102 QWidget *leftcorner = m_parent->cornerWidget( Qt::TopLeftCorner );
00103 if ( leftcorner && leftcorner->isVisible() ) {
00104 if ( point.x() <= leftcorner->width() )
00105 return false;
00106 }
00107
00108 for ( int i = 0; i < m_parent->count(); ++i )
00109 if ( m_parent->tabBar()->tabRect( i ).contains( m_parent->tabBar()->mapFromParent( point ) ) )
00110 return false;
00111
00112 return true;
00113 }
00114
00115 return false;
00116 }
00117
00118 void KTabWidget::Private::removeTab( int index )
00119 {
00120
00121
00122 m_resizeSuspend = ResizeDisabled;
00123 m_previousTabList.removeOne( m_parent->widget( index ) );
00124
00125
00126
00127
00128
00129
00130 m_tabNames.removeAt( index );
00131
00132
00133
00134
00135
00136
00137 QWidget *widget = 0;
00138 if( !m_previousTabList.isEmpty() && m_parent->tabCloseActivatePrevious() )
00139 widget = m_previousTabList.first();
00140
00141 m_parent->QTabWidget::removeTab( index );
00142
00143 const bool doResize = (m_resizeSuspend == ResizeLater) || m_automaticResizeTabs;
00144 m_resizeSuspend = ResizeEnabled;
00145 if (doResize) {
00146 resizeTabs();
00147 }
00148
00149 if( widget )
00150 m_parent->setCurrentIndex( m_parent->indexOf( widget ) );
00151 }
00152
00153 void KTabWidget::Private::resizeTabs( int changeTabIndex )
00154 {
00155 if (m_resizeSuspend != ResizeEnabled) {
00156 m_resizeSuspend = ResizeLater;
00157 return;
00158 }
00159
00160 int newTabLength = m_maxLength;
00161
00162 if (m_automaticResizeTabs) {
00163
00164 int lcw = 0, rcw = 0;
00165
00166 const int tabBarHeight = m_parent->tabBar()->sizeHint().height();
00167 if (m_parent->cornerWidget(Qt::TopLeftCorner) &&
00168 m_parent->cornerWidget( Qt::TopLeftCorner )->isVisible()) {
00169 lcw = qMax(m_parent->cornerWidget(Qt::TopLeftCorner)->width(), tabBarHeight);
00170 }
00171 if (m_parent->cornerWidget(Qt::TopRightCorner) &&
00172 m_parent->cornerWidget(Qt::TopRightCorner)->isVisible()) {
00173 rcw = qMax( m_parent->cornerWidget(Qt::TopRightCorner)->width(), tabBarHeight);
00174 }
00175
00176 const int maxTabBarWidth = m_parent->width() - lcw - rcw;
00177
00178
00179
00180 int newTabLengthHi = m_maxLength + 1;
00181 int newTabLengthLo = m_minLength;
00182 int prevTabLengthMid = -1;
00183 while (true) {
00184 int newTabLengthMid = (newTabLengthHi + newTabLengthLo) / 2;
00185 if (prevTabLengthMid == newTabLengthMid) {
00186
00187 break;
00188 }
00189 prevTabLengthMid = newTabLengthMid;
00190
00191 if (m_parent->tabBarWidthForMaxChars(newTabLengthMid) > maxTabBarWidth) {
00192 newTabLengthHi = newTabLengthMid;
00193 } else {
00194 newTabLengthLo = newTabLengthMid;
00195 }
00196 }
00197 newTabLength = qMin(newTabLengthLo, m_maxLength);
00198 }
00199
00200
00201 if (m_currentTabLength != newTabLength) {
00202 m_currentTabLength = newTabLength;
00203 for (int i = 0; i < m_parent->count(); i++) {
00204 updateTab(i);
00205 }
00206 } else if (changeTabIndex != -1) {
00207 updateTab(changeTabIndex);
00208 }
00209 }
00210
00211 void KTabWidget::Private::updateTab( int index )
00212 {
00213 QString title = m_automaticResizeTabs ? m_tabNames[ index ] : m_parent->QTabWidget::tabText( index );
00214 m_parent->setTabToolTip( index, QString() );
00215
00216 if ( title.length() > m_currentTabLength ) {
00217 QString toolTipText = title;
00218
00219 for ( int i = toolTipText.indexOf( '&' ); i >= 0 && i < toolTipText.length(); i = toolTipText.indexOf( '&', i + 1 ) )
00220 toolTipText.remove( i, 1 );
00221
00222 if ( Qt::mightBeRichText( toolTipText ) )
00223 m_parent->setTabToolTip( index, Qt::escape( toolTipText ) );
00224 else
00225 m_parent->setTabToolTip( index, toolTipText );
00226 }
00227
00228 title = KStringHandler::rsqueeze( title, m_currentTabLength ).leftJustified( m_minLength, ' ' );
00229
00230 if ( m_parent->QTabWidget::tabText( index ) != title )
00231 m_parent->QTabWidget::setTabText( index, title );
00232 }
00233
00234 KTabWidget::KTabWidget( QWidget *parent, Qt::WFlags flags )
00235 : QTabWidget( parent ),
00236 d( new Private( this ) )
00237 {
00238 setWindowFlags( flags );
00239 setTabBar( new KTabBar( this ) );
00240 setObjectName( "tabbar" );
00241 setAcceptDrops( true );
00242
00243 connect(tabBar(), SIGNAL(contextMenu( int, const QPoint & )), SLOT(contextMenu( int, const QPoint & )));
00244 connect(tabBar(), SIGNAL(tabDoubleClicked( int )), SLOT(mouseDoubleClick( int )));
00245 connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick()));
00246 connect(tabBar(), SIGNAL(mouseMiddleClick( int )), SLOT(mouseMiddleClick( int )));
00247 connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int )));
00248 connect(tabBar(), SIGNAL(testCanDecode(const QDragMoveEvent *, bool & )), SIGNAL(testCanDecode(const QDragMoveEvent *, bool & )));
00249 connect(tabBar(), SIGNAL(receivedDropEvent( int, QDropEvent * )), SLOT(receivedDropEvent( int, QDropEvent * )));
00250 connect(tabBar(), SIGNAL(moveTab( int, int )), SLOT(moveTab( int, int )));
00251 connect(tabBar(), SIGNAL(tabCloseRequested( int )), SLOT(closeRequest( int )));
00252 connect(tabBar(), SIGNAL(currentChanged( int )), SLOT(currentChanged( int )));
00253 #ifndef QT_NO_WHEELEVENT
00254 connect(tabBar(), SIGNAL(wheelDelta( int )), SLOT(wheelDelta( int )));
00255 #endif
00256 }
00257
00258 KTabWidget::~KTabWidget()
00259 {
00260 delete d;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 void KTabWidget::setTabBarHidden( bool hide )
00289 {
00290 QWidget *rightcorner = cornerWidget( Qt::TopRightCorner );
00291 QWidget *leftcorner = cornerWidget( Qt::TopLeftCorner );
00292
00293 if ( hide ) {
00294 if ( leftcorner ) leftcorner->hide();
00295 if ( rightcorner ) rightcorner->hide();
00296 tabBar()->hide();
00297 } else {
00298 tabBar()->show();
00299 if ( leftcorner ) leftcorner->show();
00300 if ( rightcorner ) rightcorner->show();
00301 }
00302 }
00303
00304 bool KTabWidget::isTabBarHidden() const
00305 {
00306 return !( tabBar()->isVisible() );
00307 }
00308
00309 void KTabWidget::setTabTextColor( int index, const QColor& color )
00310 {
00311 tabBar()->setTabTextColor( index, color );
00312 }
00313
00314 QColor KTabWidget::tabTextColor( int index ) const
00315 {
00316 return tabBar()->tabTextColor( index );
00317 }
00318
00319 void KTabWidget::setTabReorderingEnabled( bool on)
00320 {
00321 static_cast<KTabBar*>(tabBar())->setTabReorderingEnabled( on );
00322 }
00323
00324 bool KTabWidget::isTabReorderingEnabled() const
00325 {
00326 return static_cast<KTabBar*>(tabBar())->isTabReorderingEnabled();
00327 }
00328
00329 void KTabWidget::setTabCloseActivatePrevious( bool previous)
00330 {
00331 static_cast<KTabBar*>(tabBar())->setTabCloseActivatePrevious( previous );
00332 }
00333
00334 bool KTabWidget::tabCloseActivatePrevious() const
00335 {
00336 return static_cast<KTabBar*>(tabBar())->tabCloseActivatePrevious();
00337 }
00338
00339 int KTabWidget::tabBarWidthForMaxChars( int maxLength )
00340 {
00341 int hframe, overlap;
00342 hframe = tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabHSpace, 0L, tabBar() );
00343 overlap = tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabOverlap, 0L, tabBar() );
00344
00345 const QFontMetrics fm = tabBar()->fontMetrics();
00346 int x = 0;
00347 for ( int i = 0; i < count(); ++i ) {
00348 QString newTitle = d->m_tabNames.value( i );
00349 newTitle = KStringHandler::rsqueeze( newTitle, maxLength ).leftJustified( d->m_minLength, ' ' );
00350
00351 int lw = fm.width( newTitle );
00352 int iw = 0;
00353 if ( !tabBar()->tabIcon( i ).isNull() ) {
00354 iw = tabBar()->tabIcon( i ).pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), QIcon::Normal ).width() + 4;
00355 }
00356 if ( isCloseButtonEnabled() ) {
00357
00358 iw += KIconLoader::SizeSmall * 3 / 2;
00359 }
00360 x += ( tabBar()->style()->sizeFromContents( QStyle::CT_TabBarTab, 0L,
00361 QSize( qMax( lw + hframe + iw, QApplication::globalStrut().width() ), 0 ),
00362 this ) ).width();
00363 }
00364
00365 return x;
00366 }
00367
00368 QString KTabWidget::tabText( int index ) const
00369 {
00370 if ( d->m_automaticResizeTabs ) {
00371 if (index >= 0 && index < count()) {
00372 if (index >= d->m_tabNames.count()) {
00373
00374
00375
00376
00377 const_cast<KTabWidget*>(this)->tabInserted(index);
00378 }
00379 return d->m_tabNames[ index ];
00380 }
00381 else
00382 return QString();
00383 }
00384 else
00385 return QTabWidget::tabText( index );
00386 }
00387
00388 void KTabWidget::setTabText( int index, const QString &text )
00389 {
00390 if (text == tabText(index))
00391 return;
00392
00393 if ( d->m_automaticResizeTabs ) {
00394
00395 tabBar()->setUpdatesEnabled(false);
00396
00397 QTabWidget::setTabText( index, text );
00398
00399 if ( index != -1 ) {
00400 if (index >= d->m_tabNames.count()) {
00401 kWarning(240) << "setTabText(" << index << ") called but d->m_tabNames has only" << d->m_tabNames.count() << "entries";
00402 while (index >= d->m_tabNames.count()) {
00403 d->m_tabNames.append(QString());
00404 }
00405 }
00406 d->m_tabNames[ index ] = text;
00407 d->resizeTabs( index );
00408 }
00409
00410 tabBar()->setUpdatesEnabled(true);
00411
00412 } else {
00413 QTabWidget::setTabText( index, text );
00414 }
00415 }
00416
00417
00418 void KTabWidget::dragEnterEvent( QDragEnterEvent *event )
00419 {
00420 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00421 bool accept = false;
00422
00423
00424 emit testCanDecode( event, accept);
00425
00426 event->setAccepted( accept );
00427 return;
00428 }
00429
00430 QTabWidget::dragEnterEvent( event );
00431 }
00432
00433 void KTabWidget::dragMoveEvent( QDragMoveEvent *event )
00434 {
00435 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00436 bool accept = false;
00437
00438
00439 emit testCanDecode( event, accept);
00440
00441 event->setAccepted( accept );
00442 return;
00443 }
00444
00445 QTabWidget::dragMoveEvent( event );
00446 }
00447
00448 void KTabWidget::dropEvent( QDropEvent *event )
00449 {
00450 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00451 emit ( receivedDropEvent( event ) );
00452 return;
00453 }
00454
00455 QTabWidget::dropEvent( event );
00456 }
00457
00458 #ifndef QT_NO_WHEELEVENT
00459 void KTabWidget::wheelEvent( QWheelEvent *event )
00460 {
00461 if ( event->orientation() == Qt::Horizontal )
00462 return;
00463
00464 if ( d->isEmptyTabbarSpace( event->pos() ) )
00465 wheelDelta( event->delta() );
00466 else
00467 event->ignore();
00468 }
00469
00470 void KTabWidget::wheelDelta( int delta )
00471 {
00472 if ( count() < 2 )
00473 return;
00474
00475 int page = currentIndex();
00476 if ( delta < 0 )
00477 page = (page + 1) % count();
00478 else {
00479 page--;
00480 if ( page < 0 )
00481 page = count() - 1;
00482 }
00483 setCurrentIndex( page );
00484 }
00485 #endif
00486
00487 void KTabWidget::mouseDoubleClickEvent( QMouseEvent *event )
00488 {
00489 if ( event->button() != Qt::LeftButton )
00490 return;
00491
00492 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00493 emit( mouseDoubleClick() );
00494 return;
00495 }
00496
00497 QTabWidget::mouseDoubleClickEvent( event );
00498 }
00499
00500 void KTabWidget::mousePressEvent( QMouseEvent *event )
00501 {
00502 if ( event->button() == Qt::RightButton ) {
00503 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00504 emit( contextMenu( mapToGlobal( event->pos() ) ) );
00505 return;
00506 }
00507 }
00508
00509 QTabWidget::mousePressEvent( event );
00510 }
00511
00512 void KTabWidget::mouseReleaseEvent( QMouseEvent *event )
00513 {
00514 if ( event->button() == Qt::MidButton ) {
00515 if ( d->isEmptyTabbarSpace( event->pos() ) ) {
00516 emit( mouseMiddleClick() );
00517 return;
00518 }
00519 }
00520
00521 QTabWidget::mouseReleaseEvent( event );
00522 }
00523
00524 void KTabWidget::receivedDropEvent( int index, QDropEvent *event )
00525 {
00526 emit( receivedDropEvent( widget( index ), event ) );
00527 }
00528
00529 void KTabWidget::initiateDrag( int index )
00530 {
00531 emit( initiateDrag( widget( index ) ) );
00532 }
00533
00534 void KTabWidget::contextMenu( int index, const QPoint &point )
00535 {
00536 emit( contextMenu( widget( index ), point ) );
00537 }
00538
00539 void KTabWidget::mouseDoubleClick( int index )
00540 {
00541 emit( mouseDoubleClick( widget( index ) ) );
00542 }
00543
00544 void KTabWidget::mouseMiddleClick( int index )
00545 {
00546 emit( mouseMiddleClick( widget( index ) ) );
00547 }
00548
00549 void KTabWidget::moveTab( int from, int to )
00550 {
00551 setUpdatesEnabled(false);
00552
00553 const QString tablabel = tabText( from );
00554 QWidget *w = widget( from );
00555 const QColor color = tabTextColor( from );
00556 const QIcon tabiconset = tabIcon( from );
00557 const QString tabtooltip = tabToolTip( from );
00558 const bool current = ( from == currentIndex() );
00559 const bool enabled = isTabEnabled( from );
00560
00561 const bool blocked = blockSignals( true );
00562 removeTab( from );
00563 insertTab( to, w, tablabel );
00564
00565 setTabIcon( to, tabiconset );
00566 setTabText( to, tablabel );
00567 setTabToolTip( to, tabtooltip );
00568 setTabTextColor( to, color );
00569 if ( current )
00570 setCurrentIndex( to );
00571 setTabEnabled( to, enabled );
00572 if ( d->m_automaticResizeTabs ) {
00573 d->resizeTabs( to );
00574 }
00575 blockSignals( blocked );
00576
00577 setUpdatesEnabled(true);
00578
00579 emit ( movedTab( from, to ) );
00580 }
00581
00582 void KTabWidget::removePage( QWidget *widget )
00583 {
00584
00585 const int index = indexOf(widget);
00586 if ( d->m_automaticResizeTabs ) {
00587 setUpdatesEnabled(false);
00588 d->removeTab(index);
00589 setUpdatesEnabled(true);
00590 } else {
00591 d->removeTab(index);
00592 }
00593 }
00594
00595 void KTabWidget::removeTab( int index )
00596 {
00597 if ( d->m_automaticResizeTabs ) {
00598 setUpdatesEnabled(false);
00599 d->removeTab( index );
00600 setUpdatesEnabled(true);
00601 } else {
00602 d->removeTab( index );
00603 }
00604 }
00605
00606 void KTabWidget::setHoverCloseButton( bool button )
00607 {
00608
00609 setTabsClosable( button );
00610 }
00611
00612 bool KTabWidget::hoverCloseButton() const
00613 {
00614
00615 return false;
00616 }
00617
00618 void KTabWidget::setHoverCloseButtonDelayed( bool delayed )
00619 {
00620
00621 Q_UNUSED( delayed );
00622 }
00623
00624 bool KTabWidget::hoverCloseButtonDelayed() const
00625 {
00626
00627 return tabsClosable();
00628 }
00629
00630 void KTabWidget::setCloseButtonEnabled( bool enable )
00631 {
00632 static_cast<KTabBar*>( tabBar() )->setTabsClosable( enable );
00633 }
00634
00635 bool KTabWidget::isCloseButtonEnabled() const
00636 {
00637 return static_cast<KTabBar*>( tabBar() )->tabsClosable();
00638 }
00639
00640 void KTabWidget::setAutomaticResizeTabs( bool enabled )
00641 {
00642 if ( d->m_automaticResizeTabs == enabled )
00643 return;
00644
00645 setUpdatesEnabled(false);
00646
00647 d->m_automaticResizeTabs = enabled;
00648 if ( enabled ) {
00649 d->m_tabNames.clear();
00650 for ( int i = 0; i < count(); ++i )
00651 d->m_tabNames.append( tabBar()->tabText( i ) );
00652 } else
00653 for ( int i = 0; i < count(); ++i )
00654 tabBar()->setTabText( i, d->m_tabNames[ i ] );
00655
00656 d->resizeTabs();
00657
00658 setUpdatesEnabled(true);
00659 }
00660
00661 bool KTabWidget::automaticResizeTabs() const
00662 {
00663 return d->m_automaticResizeTabs;
00664 }
00665
00666 void KTabWidget::closeRequest( int index )
00667 {
00668 emit( closeRequest( widget( index ) ) );
00669 }
00670
00671 void KTabWidget::resizeEvent( QResizeEvent *event )
00672 {
00673 QTabWidget::resizeEvent( event );
00674 d->resizeTabs();
00675 }
00676
00677 void KTabWidget::tabInserted( int idx )
00678 {
00679 d->m_tabNames.insert( idx, tabBar()->tabText( idx ) );
00680 }
00681
00682 void KTabWidget::tabRemoved( int idx )
00683 {
00684
00685 }
00686
00687 void KTabWidget::currentChanged( int idx )
00688 {
00689
00690 d->m_previousTabList.removeOne( widget(idx) );
00691
00692 d->m_previousTabList.push_front( widget(idx) );
00693 }
00694
00695 #include "ktabwidget.moc"