/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 Martin Gräßlin 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 . *********************************************************************/ // 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 #include #include #include #include #include #include // KDE #include #include #include #include #include namespace KWin { namespace TabBox { TabBoxView::TabBoxView(ClientModel *clientModel, DesktopModel *desktopModel, QWidget* parent) : QWidget(parent) , m_clientModel(clientModel) , m_desktopModel(desktopModel) , m_previewUpdate(false) { setWindowFlags(Qt::X11BypassWindowManagerHint); setAttribute(Qt::WA_TranslucentBackground); QPalette pal = palette(); pal.setColor(backgroundRole(), Qt::transparent); setPalette(pal); 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"