ktabbar.cpp
/* This file is part of the KDE libraries
Copyright (C) 2003 Stephan Binner <binner@kde.org>
Copyright (C) 2003 Zack Rusin <zack@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <qapplication.h>
#include <qcursor.h>
#include <qpainter.h>
#include <qstyle.h>
#include <qtimer.h>
#include <qpushbutton.h>
#include <qtooltip.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <klocale.h>
#include "ktabbar.h"
#include "ktabwidget.h"
KTabBar::KTabBar( QWidget *parent, const char *name )
: QTabBar( parent, name ), mReorderStartTab( -1 ), mReorderPreviousTab( -1 ),
mHoverCloseButtonTab( 0 ), mDragSwitchTab( 0 ), mHoverCloseButton( 0 ),
mHoverCloseButtonEnabled( false ), mHoverCloseButtonDelayed( true ),
mTabReorderingEnabled( false ), mTabCloseActivatePrevious( false )
{
setAcceptDrops( true );
setMouseTracking( true );
mEnableCloseButtonTimer = new QTimer( this );
connect( mEnableCloseButtonTimer, SIGNAL( timeout() ), SLOT( enableCloseButton() ) );
mActivateDragSwitchTabTimer = new QTimer( this );
connect( mActivateDragSwitchTabTimer, SIGNAL( timeout() ), SLOT( activateDragSwitchTab() ) );
connect(this, SIGNAL(layoutChanged()), SLOT(onLayoutChange()));
}
KTabBar::~KTabBar()
{
//For the future
//delete d;
}
void KTabBar::setTabEnabled( int id, bool enabled )
{
QTab * t = tab( id );
if ( t ) {
if ( t->isEnabled() != enabled ) {
t->setEnabled( enabled );
QRect r( t->rect() );
if ( !enabled && id == currentTab() && count()>1 ) {
QPtrList<QTab> *tablist = tabList();
if ( mTabCloseActivatePrevious )
t = tablist->at( count()-2 );
else {
int index = indexOf( id );
index += ( index+1 == count() ) ? -1 : 1;
t = tabAt( index );
}
if ( t->isEnabled() ) {
r = r.unite( t->rect() );
tablist->append( tablist->take( tablist->findRef( t ) ) );
emit selected( t->identifier() );
}
}
repaint( r );
}
}
}
void KTabBar::mouseDoubleClickEvent( QMouseEvent *e )
{
if( e->button() != LeftButton )
return;
QTab *tab = selectTab( e->pos() );
if( tab ) {
emit( mouseDoubleClick( indexOf( tab->identifier() ) ) );
return;
}
QTabBar::mouseDoubleClickEvent( e );
}
void KTabBar::mousePressEvent( QMouseEvent *e )
{
if( e->button() == LeftButton ) {
mEnableCloseButtonTimer->stop();
mDragStart = e->pos();
}
else if( e->button() == RightButton ) {
QTab *tab = selectTab( e->pos() );
if( tab ) {
emit( contextMenu( indexOf( tab->identifier() ), mapToGlobal( e->pos() ) ) );
return;
}
}
QTabBar::mousePressEvent( e );
}
void KTabBar::mouseMoveEvent( QMouseEvent *e )
{
if ( e->state() == LeftButton ) {
QTab *tab = selectTab( e->pos() );
if ( mDragSwitchTab && tab != mDragSwitchTab ) {
mActivateDragSwitchTabTimer->stop();
mDragSwitchTab = 0;
}
int delay = KGlobalSettings::dndEventDelay();
QPoint newPos = e->pos();
if( newPos.x() > mDragStart.x()+delay || newPos.x() < mDragStart.x()-delay ||
newPos.y() > mDragStart.y()+delay || newPos.y() < mDragStart.y()-delay )
{
if( tab ) {
emit( initiateDrag( indexOf( tab->identifier() ) ) );
return;
}
}
}
else if ( e->state() == MidButton ) {
if (mReorderStartTab==-1) {
int delay = KGlobalSettings::dndEventDelay();
QPoint newPos = e->pos();
if( newPos.x() > mDragStart.x()+delay || newPos.x() < mDragStart.x()-delay ||
newPos.y() > mDragStart.y()+delay || newPos.y() < mDragStart.y()-delay )
{
QTab *tab = selectTab( e->pos() );
if( tab && mTabReorderingEnabled ) {
mReorderStartTab = indexOf( tab->identifier() );
grabMouse( sizeAllCursor );
return;
}
}
}
else {
QTab *tab = selectTab( e->pos() );
if( tab ) {
int reorderStopTab = indexOf( tab->identifier() );
if ( mReorderStartTab!=reorderStopTab && mReorderPreviousTab!=reorderStopTab ) {
emit( moveTab( mReorderStartTab, reorderStopTab ) );
mReorderPreviousTab=mReorderStartTab;
mReorderStartTab=reorderStopTab;
return;
}
}
}
}
if ( mHoverCloseButtonEnabled && mReorderStartTab==-1) {
QTab *t = selectTab( e->pos() );
if( t && t->iconSet() && t->isEnabled() ) {
QPixmap pixmap = t->iconSet()->pixmap( QIconSet::Small, QIconSet::Normal );
QRect rect( 0, 0, pixmap.width() + 4, pixmap.height() +4);
int xoff = 0, yoff = 0;
// The additional offsets were found by try and error, TODO: find the rational behind them
if ( t == tab( currentTab() ) ) {
xoff = style().pixelMetric( QStyle::PM_TabBarTabShiftHorizontal, this ) + 3;
yoff = style().pixelMetric( QStyle::PM_TabBarTabShiftVertical, this ) - 4;
}
else {
xoff = 7;
yoff = 0;
}
rect.moveLeft( t->rect().left() + 2 + xoff );
rect.moveTop( t->rect().center().y()-pixmap.height()/2 + yoff );
if ( rect.contains( e->pos() ) ) {
if ( mHoverCloseButton ) {
if ( mHoverCloseButtonTab == t )
return;
mEnableCloseButtonTimer->stop();
mHoverCloseButton->deleteLater();
mHoverCloseButton = 0;
}
mHoverCloseButton = new QPushButton( this );
mHoverCloseButton->setIconSet( KGlobal::iconLoader()->loadIconSet("fileclose", KIcon::Toolbar, KIcon::SizeSmall) );
mHoverCloseButton->setGeometry( rect );
QToolTip::add(mHoverCloseButton,i18n("Close this tab"));
mHoverCloseButton->setFlat(true);
mHoverCloseButton->show();
if ( mHoverCloseButtonDelayed ) {
mHoverCloseButton->setEnabled(false);
mEnableCloseButtonTimer->start( QApplication::doubleClickInterval(), true );
}
mHoverCloseButtonTab = t;
connect( mHoverCloseButton, SIGNAL( clicked() ), SLOT( closeButtonClicked() ) );
return;
}
}
if ( mHoverCloseButton ) {
mEnableCloseButtonTimer->stop();
mHoverCloseButton->deleteLater();
mHoverCloseButton = 0;
}
}
QTabBar::mouseMoveEvent( e );
}
void KTabBar::enableCloseButton()
{
mHoverCloseButton->setEnabled(true);
}
void KTabBar::activateDragSwitchTab()
{
QTab *tab = selectTab( mapFromGlobal( QCursor::pos() ) );
if ( tab && mDragSwitchTab == tab )
setCurrentTab( mDragSwitchTab );
mDragSwitchTab = 0;
}
void KTabBar::mouseReleaseEvent( QMouseEvent *e )
{
if( e->button() == MidButton ) {
if ( mReorderStartTab==-1 ) {
QTab *tab = selectTab( e->pos() );
if( tab ) {
emit( mouseMiddleClick( indexOf( tab->identifier() ) ) );
return;
}
}
else {
releaseMouse();
setCursor( arrowCursor );
mReorderStartTab=-1;
mReorderPreviousTab=-1;
}
}
QTabBar::mouseReleaseEvent( e );
}
void KTabBar::dragMoveEvent( QDragMoveEvent *e )
{
QTab *tab = selectTab( e->pos() );
if( tab ) {
bool accept = false;
// The receivers of the testCanDecode() signal has to adjust
// 'accept' accordingly.
emit testCanDecode( e, accept);
if ( accept && tab != QTabBar::tab( currentTab() ) ) {
mDragSwitchTab = tab;
mActivateDragSwitchTabTimer->start( QApplication::doubleClickInterval()*2, true );
}
e->accept( accept );
return;
}
e->accept( false );
QTabBar::dragMoveEvent( e );
}
void KTabBar::dropEvent( QDropEvent *e )
{
QTab *tab = selectTab( e->pos() );
if( tab ) {
mActivateDragSwitchTabTimer->stop();
mDragSwitchTab = 0;
emit( receivedDropEvent( indexOf( tab->identifier() ) , e ) );
return;
}
QTabBar::dropEvent( e );
}
#ifndef QT_NO_WHEELEVENT
void KTabBar::wheelEvent( QWheelEvent *e )
{
if ( e->orientation() == Horizontal )
return;
emit( wheelDelta( e->delta() ) );
}
#endif
void KTabBar::setTabColor( int id, const QColor& color )
{
QTab *t = tab( id );
if ( t ) {
mTabColors.insert( id, color );
repaint( t->rect(), false );
}
}
const QColor &KTabBar::tabColor( int id ) const
{
if ( mTabColors.contains( id ) )
return mTabColors[id];
return colorGroup().foreground();
}
int KTabBar::insertTab( QTab *t, int index )
{
int res = QTabBar::insertTab( t, index );
if ( mTabCloseActivatePrevious && count() > 2 ) {
QPtrList<QTab> *tablist = tabList();
tablist->insert( count()-2, tablist->take( tablist->findRef( t ) ) );
}
return res;
}
void KTabBar::removeTab( QTab *t )
{
mTabColors.remove( t->identifier() );
QTabBar::removeTab( t );
}
void KTabBar::paintLabel( QPainter *p, const QRect& br,
QTab *t, bool has_focus ) const
{
QRect r = br;
bool selected = currentTab() == t->identifier();
if ( t->iconSet() ) {
// the tab has an iconset, draw it in the right mode
QIconSet::Mode mode = ( t->isEnabled() && isEnabled() )
? QIconSet::Normal : QIconSet::Disabled;
if ( mode == QIconSet::Normal && has_focus )
mode = QIconSet::Active;
QPixmap pixmap = t->iconSet()->pixmap( QIconSet::Small, mode );
int pixw = pixmap.width();
int pixh = pixmap.height();
r.setLeft( r.left() + pixw + 4 );
r.setRight( r.right() + 2 );
int inactiveXShift = style().pixelMetric( QStyle::PM_TabBarTabShiftHorizontal, this );
int inactiveYShift = style().pixelMetric( QStyle::PM_TabBarTabShiftVertical, this );
int right = t->text().isEmpty() ? br.right() - pixw : br.left() + 2;
p->drawPixmap( right + (selected ? 0 : inactiveXShift),
br.center().y() - pixh / 2 + (selected ? 0 : inactiveYShift),
pixmap );
}
QStyle::SFlags flags = QStyle::Style_Default;
if ( isEnabled() && t->isEnabled() )
flags |= QStyle::Style_Enabled;
if ( has_focus )
flags |= QStyle::Style_HasFocus;
QColorGroup cg( colorGroup() );
if ( mTabColors.contains( t->identifier() ) )
cg.setColor( QColorGroup::Foreground, mTabColors[t->identifier()] );
style().drawControl( QStyle::CE_TabBarLabel, p, this, r,
t->isEnabled() ? cg : palette().disabled(),
flags, QStyleOption(t) );
}
bool KTabBar::isTabReorderingEnabled() const
{
return mTabReorderingEnabled;
}
void KTabBar::setTabReorderingEnabled( bool on )
{
mTabReorderingEnabled = on;
}
bool KTabBar::tabCloseActivatePrevious() const
{
return mTabCloseActivatePrevious;
}
void KTabBar::setTabCloseActivatePrevious( bool on )
{
mTabCloseActivatePrevious = on;
}
void KTabBar::closeButtonClicked()
{
emit closeRequest( indexOf( mHoverCloseButtonTab->identifier() ) );
}
void KTabBar::setHoverCloseButton( bool button )
{
mHoverCloseButtonEnabled = button;
if ( !button )
onLayoutChange();
}
bool KTabBar::hoverCloseButton() const
{
return mHoverCloseButtonEnabled;
}
void KTabBar::setHoverCloseButtonDelayed( bool delayed )
{
mHoverCloseButtonDelayed = delayed;
}
bool KTabBar::hoverCloseButtonDelayed() const
{
return mHoverCloseButtonDelayed;
}
void KTabBar::onLayoutChange()
{
mEnableCloseButtonTimer->stop();
delete mHoverCloseButton;
mHoverCloseButton = 0;
mHoverCloseButtonTab = 0;
mActivateDragSwitchTabTimer->stop();
mDragSwitchTab = 0;
}
#include "ktabbar.moc"
KIcon::Toolbar
KGlobal::iconLoader
static KIconLoader * iconLoader()
klocale.h
KIcon::SizeSmall
KGlobalSettings::dndEventDelay
static int dndEventDelay()

KDE Home | KDE Accessibility Home | Description of Access Keys