kwin/tabbox/tabboxview.cpp
Martin Gräßlin 8d2178ad5d Correctly handle mouse clicks in TabBox when there is an additional view.
BUG: 226877

svn path=/trunk/KDE/kdebase/workspace/; revision=1103492
2010-03-15 08:39:40 +00:00

471 lines
16 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// own
#include "tabboxview.h"
// tabbox
#include "clientitemdelegate.h"
#include "clientmodel.h"
#include "desktopitemdelegate.h"
#include "desktopmodel.h"
#include "tabboxconfig.h"
#include "tabboxhandler.h"
// Qt
#include <QTextStream>
#include <QGridLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QSizePolicy>
#include <QPainter>
#include <QPropertyAnimation>
// KDE
#include <kephal/screens.h>
#include <Plasma/FrameSvg>
#include <KDebug>
namespace KWin
{
namespace TabBox
{
TabBoxView::TabBoxView( QWidget* parent )
: QWidget( parent )
, m_previewUpdate( false )
{
setWindowFlags( Qt::X11BypassWindowManagerHint );
setAttribute( Qt::WA_TranslucentBackground );
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
m_clientModel = new ClientModel( this );
m_desktopModel = new DesktopModel( this );
m_delegate = new ClientItemDelegate( this );
m_additionalClientDelegate = new ClientItemDelegate( this );
m_additionalClientDelegate->setShowSelection( false );
m_desktopItemDelegate = new DesktopItemDelegate( this );
m_additionalDesktopDelegate = new DesktopItemDelegate( this );
m_tableView = new TabBoxMainView( this );
m_additionalView = new TabBoxAdditionalView( this );
// FrameSvg
m_frame = new Plasma::FrameSvg( this );
m_frame->setImagePath( "dialogs/background" );
m_frame->setCacheAllRenderedFrames( true );
m_frame->setEnabledBorders( Plasma::FrameSvg::AllBorders );
m_selectionFrame = new Plasma::FrameSvg( this );
m_selectionFrame->setImagePath( "widgets/viewitem" );
m_selectionFrame->setElementPrefix( "hover" );
m_selectionFrame->setCacheAllRenderedFrames( true );
m_selectionFrame->setEnabledBorders( Plasma::FrameSvg::AllBorders );
m_animation = new QPropertyAnimation( this, "selectedItem", this );
m_animation->setDuration(250);
m_animation->setEasingCurve( QEasingCurve::InOutQuad );
connect( tabBox, SIGNAL(configChanged()), this, SLOT(configChanged()));
connect( m_animation, SIGNAL(valueChanged(QVariant)), SLOT(update()));
connect( m_tableView, SIGNAL(activated(QModelIndex)), SLOT(setCurrentIndex(QModelIndex)));
}
TabBoxView::~TabBoxView()
{
}
void TabBoxView::paintEvent(QPaintEvent* e)
{
// paint the background
QPainter painter( this );
painter.setRenderHint(QPainter::Antialiasing);
painter.setClipRect(e->rect());
m_frame->paintFrame( &painter );
// and the selection item
if( m_previewUpdate )
{
m_previewUpdate = false;
setCurrentIndex( m_tableView->currentIndex() );
}
m_selectionFrame->paintFrame( &painter,
m_tableView->geometry().topLeft() + m_selectedItem.topLeft() );
QWidget::paintEvent(e);
}
bool TabBoxView::event( QEvent* event )
{
if( event->type() == QEvent::Paint )
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_Source );
p.fillRect( rect(), Qt::transparent );
}
return QWidget::event( event );
}
void TabBoxView::resizeEvent(QResizeEvent* event)
{
m_frame->resizeFrame( event->size() );
setMask( m_frame->mask() );
QWidget::resizeEvent(event);
}
void TabBoxView::updateGeometry()
{
if( m_tableView->model()->columnCount() == 0 || m_tableView->model()->rowCount() == 0 )
return;
QSize hint = sizeHint();
QRect screenRect = Kephal::ScreenUtils::screenGeometry( tabBox->activeScreen() );
int x = screenRect.x() + screenRect.width() * 0.5 - hint.width() * 0.5;
int y = screenRect.y() + screenRect.height() * 0.5 - hint.height() * 0.5;
setGeometry( x, y, hint.width(), hint.height() );
}
QSize TabBoxView::sizeHint() const
{
if( m_tableView->model()->columnCount() == 0 || m_tableView->model()->rowCount() == 0 )
return QSize( 0, 0 );
// calculate width and height
QSize tabBoxSize = m_tableView->sizeHint();
qreal columnWidth = tabBoxSize.width() / m_tableView->model()->columnCount();
qreal rowHeight = tabBoxSize.height() / m_tableView->model()->rowCount();
for( int i=0; i<m_tableView->model()->rowCount(); i++ )
m_tableView->setRowHeight( i, rowHeight );
// additional view
QSize additionalSize = m_additionalView->sizeHint();
for( int i=0; i<m_additionalView->model()->columnCount(); i++ )
m_additionalView->setColumnWidth( i, additionalSize.width() );
for( int i=0; i<m_additionalView->model()->rowCount(); i++ )
m_additionalView->setRowHeight( i, additionalSize.height() );
// reserve some space for borders
qreal top, bottom, left, right;
m_frame->getMargins( left, top, right, bottom );
int width = columnWidth * m_tableView->model()->columnCount() + left + right;
int height = rowHeight * m_tableView->model()->rowCount() + top + bottom;
qreal addedWidth = left + right;
// depending on layout of additional view we have to add some width or height
switch( tabBox->config().selectedItemViewPosition() )
{
case TabBoxConfig::AbovePosition: // fall through
case TabBoxConfig::BelowPosition:
if( additionalSize.width() + int(left + right) > width )
{
addedWidth += (additionalSize.width() + int(left + right) - width);
width = additionalSize.width() + int(left + right);
}
height = height + additionalSize.height();
break;
case TabBoxConfig::LeftPosition: // fall through
case TabBoxConfig::RightPosition:
width = width + additionalSize.width();
addedWidth += additionalSize.width();
height = qMax( height, additionalSize.height() + int(top + bottom) );
break;
default:
// don't add
break;
}
QRect screenRect = Kephal::ScreenUtils::screenGeometry( tabBox->activeScreen() );
width = qBound( screenRect.width() * tabBox->config().minWidth() / 100, width,
screenRect.width() );
height = qBound( screenRect.height() * tabBox->config().minHeight() / 100, height,
screenRect.height() );
if( width - addedWidth > tabBoxSize.width() )
{
columnWidth = (width - addedWidth) / m_tableView->model()->columnCount();
}
m_tableView->setMinimumWidth( width - addedWidth );
for( int i=0; i<m_tableView->model()->columnCount(); i++ )
m_tableView->setColumnWidth( i, columnWidth );
return QSize( width, height );
}
void TabBoxView::setCurrentIndex( QModelIndex index )
{
if( index.isValid() )
{
m_tableView->setCurrentIndex( index );
const QRect visualRect = m_tableView->visualRect( index );
if( m_selectedItem.isNull() )
m_selectedItem = visualRect;
if( m_animation->state() == QPropertyAnimation::Running )
{
m_animation->stop();
m_selectedItem = visualRect;
update();
}
else
{
m_animation->setStartValue( m_selectedItem );
m_animation->setEndValue( visualRect );
m_animation->start();
}
m_selectionFrame->resizeFrame( visualRect.size() );
m_additionalView->setCurrentIndex( index );
}
}
void TabBoxView::configChanged()
{
switch( tabBox->config().tabBoxMode() )
{
case TabBoxConfig::ClientTabBox:
m_tableView->setModel( m_clientModel );
m_tableView->setItemDelegate( m_delegate );
m_additionalView->setModel( m_clientModel );
m_additionalView->setItemDelegate( m_additionalClientDelegate );
break;
case TabBoxConfig::DesktopTabBox:
m_tableView->setModel( m_desktopModel );
m_tableView->setItemDelegate( m_desktopItemDelegate );
m_additionalView->setModel( m_desktopModel );
m_additionalView->setItemDelegate( m_additionalDesktopDelegate );
break;
}
QLayout* old = layout();
QLayoutItem *child;
while( old && (child = old->takeAt( 0 )) != 0 )
{
delete child;
}
delete old;
QBoxLayout *layout;
switch( tabBox->config().selectedItemViewPosition() )
{
case TabBoxConfig::AbovePosition:
{
layout = new QVBoxLayout();
QHBoxLayout* horizontalLayout1 = new QHBoxLayout();
horizontalLayout1->addStretch();
horizontalLayout1->addWidget( m_additionalView );
horizontalLayout1->addStretch();
layout->addLayout( horizontalLayout1 );
layout->addStretch();
QHBoxLayout* horizontalLayout2 = new QHBoxLayout();
horizontalLayout2->addStretch();
horizontalLayout2->addWidget( m_tableView );
horizontalLayout2->addStretch();
layout->addLayout( horizontalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::BelowPosition:
{
layout = new QVBoxLayout();
QHBoxLayout* horizontalLayout1 = new QHBoxLayout();
horizontalLayout1->addStretch();
horizontalLayout1->addWidget( m_tableView );
horizontalLayout1->addStretch();
layout->addLayout( horizontalLayout1 );
layout->addStretch();
QHBoxLayout* horizontalLayout2 = new QHBoxLayout();
horizontalLayout2->addStretch();
horizontalLayout2->addWidget( m_additionalView );
horizontalLayout2->addStretch();
layout->addLayout( horizontalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::LeftPosition:
{
layout = new QHBoxLayout();
QVBoxLayout* verticalLayout1 = new QVBoxLayout();
verticalLayout1->addStretch();
verticalLayout1->addWidget( m_additionalView );
verticalLayout1->addStretch();
layout->addLayout( verticalLayout1 );
layout->addStretch();
QVBoxLayout* verticalLayout2 = new QVBoxLayout();
verticalLayout2->addStretch();
verticalLayout2->addWidget( m_tableView );
verticalLayout2->addStretch();
layout->addLayout( verticalLayout2 );
m_additionalView->show();
break;
}
case TabBoxConfig::RightPosition:
{
layout = new QHBoxLayout();
QVBoxLayout* verticalLayout1 = new QVBoxLayout();
verticalLayout1->addStretch();
verticalLayout1->addWidget( m_tableView );
verticalLayout1->addStretch();
layout->addLayout( verticalLayout1 );
layout->addStretch();
QVBoxLayout* verticalLayout2 = new QVBoxLayout();
verticalLayout2->addStretch();
verticalLayout2->addWidget( m_additionalView );
verticalLayout2->addStretch();
layout->addLayout( verticalLayout2 );
m_additionalView->show();
break;
}
default:
{
layout = new QVBoxLayout();
layout->addStretch();
layout->addWidget( m_tableView );
layout->addStretch();
m_additionalView->hide();
break;
}
}
setLayout( layout );
if( m_preview )
m_previewUpdate = true;
}
QModelIndex TabBoxView::indexAt( QPoint pos )
{
return m_tableView->indexAt( m_tableView->mapFromParent( pos ) );
}
void TabBoxView::setPreview( bool preview )
{
m_preview = preview;
if( preview )
m_frame->setImagePath( "dialogs/opaque/background" );
}
/********************************************************
* TabBoxMainView
********************************************************/
TabBoxMainView::TabBoxMainView(QWidget* parent)
: QTableView(parent)
{
setFrameStyle( QFrame::NoFrame );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
viewport()->setAutoFillBackground( false );
// adjust table view to needs of tabbox
setShowGrid( false );
horizontalHeader()->hide();
verticalHeader()->hide();
setSelectionMode( QAbstractItemView::SingleSelection );
setSelectionBehavior( QAbstractItemView::SelectItems );
setHorizontalScrollMode( QAbstractItemView::ScrollPerItem );
setVerticalScrollMode( QAbstractItemView::ScrollPerItem );
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
}
TabBoxMainView::~TabBoxMainView()
{
}
QSize TabBoxMainView::sizeHint() const
{
int maxWidth = 0;
int minWidth = sizeHintForColumn( 0 );
int maxHeight = 0;
int minHeight = sizeHintForRow( 0 );
for( int i=0; i<model()->columnCount(); i++ )
{
minWidth = qMin( minWidth, sizeHintForColumn( i ) );
maxWidth = qMax( maxWidth, sizeHintForColumn( i ) );
}
for( int i=0; i<model()->rowCount(); i++ )
{
minHeight = qMin( minHeight, sizeHintForRow( i ) );
maxHeight = qMax( maxHeight, sizeHintForRow( i ) );
}
qreal columnWidth = (minWidth + qreal(maxWidth - minWidth) / 2.0 );
qreal rowHeight = (minHeight + qreal(maxHeight - minHeight) / 2.0 );
return QSize( columnWidth * model()->columnCount(),
rowHeight * model()->rowCount() );
}
QModelIndex TabBoxMainView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED( cursorAction )
Q_UNUSED( modifiers )
return currentIndex();
}
/********************************************************
* TabBoxAdditonalView
********************************************************/
TabBoxAdditionalView::TabBoxAdditionalView(QWidget* parent)
: QTableView(parent)
{
setFrameStyle( QFrame::NoFrame );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
viewport()->setAutoFillBackground( false );
// adjust table view to needs of tabbox
setShowGrid( false );
horizontalHeader()->hide();
verticalHeader()->hide();
setSelectionMode( QAbstractItemView::SingleSelection );
setSelectionBehavior( QAbstractItemView::SelectItems );
setHorizontalScrollMode( QAbstractItemView::ScrollPerItem );
setVerticalScrollMode( QAbstractItemView::ScrollPerItem );
setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
}
TabBoxAdditionalView::~TabBoxAdditionalView()
{
}
QSize TabBoxAdditionalView::sizeHint() const
{
int maxWidth = 0;
int minWidth = sizeHintForColumn( 0 );
int maxHeight = 0;
int minHeight = sizeHintForRow( 0 );
for( int i=0; i<model()->columnCount(); i++ )
{
minWidth = qMin( minWidth, sizeHintForColumn( i ) );
maxWidth = qMax( maxWidth, sizeHintForColumn( i ) );
}
for( int i=0; i<model()->rowCount(); i++ )
{
minHeight = qMin( minHeight, sizeHintForRow( i ) );
maxHeight = qMax( maxHeight, sizeHintForRow( i ) );
}
qreal columnWidth = (minWidth + qreal(maxWidth - minWidth) / 2.0 );
qreal rowHeight = (minHeight + qreal(maxHeight - minHeight) / 2.0 );
return QSize( columnWidth, rowHeight );
}
QModelIndex TabBoxAdditionalView::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
{
Q_UNUSED( cursorAction )
Q_UNUSED( modifiers )
return currentIndex();
}
void TabBoxAdditionalView::wheelEvent( QWheelEvent* event )
{
Q_UNUSED( event )
}
} // namespace Tabbox
} // namespace KWin
#include "tabboxview.moc"