459 lines
16 KiB
C++
459 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>
|
|
#include <KDE/Plasma/Theme>
|
|
#include <KDE/Plasma/WindowEffects>
|
|
|
|
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());
|
|
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
|
|
// blur background
|
|
Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask());
|
|
Plasma::WindowEffects::overrideShadow(winId(), true);
|
|
} else {
|
|
// do not trim to mask with compositing enabled, otherwise shadows are cropped
|
|
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"
|