plasma-framework/widgets/tabbar.cpp

407 lines
12 KiB
C++
Raw Normal View History

/*
* Copyright 2008 Marco Martin <notmart@gmail.com>
*
* This program 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, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "tabbar.h"
#include <QGraphicsLinearLayout>
#include <QGraphicsLayoutItem>
#include <QString>
#include <QGraphicsScene>
#include <QGraphicsProxyWidget>
#include <QGraphicsSceneWheelEvent>
#include <QIcon>
#include <KDebug>
#include <plasma/animator.h>
#include "private/nativetabbar_p.h"
namespace Plasma
{
class TabBarPrivate
{
public:
TabBarPrivate(TabBar *parent)
: q(parent),
tabBar(0),
currentIndex(0),
oldPage(0),
newPage(0),
oldPageAnimId(-1),
newPageAnimId(-1)
{
}
~TabBarPrivate()
{
}
void updateTabWidgetMode();
void slidingCompleted(QGraphicsItem *item);
void shapeChanged(const QTabBar::Shape shape);
TabBar *q;
NativeTabBar *tabBar;
QGraphicsProxyWidget *tabProxy;
QGraphicsWidget *leftSpacer;
QGraphicsWidget *rightSpacer;
QList<QGraphicsWidget *> pages;
QGraphicsLinearLayout *mainLayout;
QGraphicsLinearLayout *tabBarLayout;
int currentIndex;
QGraphicsWidget *oldPage;
QGraphicsWidget *newPage;
int oldPageAnimId;
int newPageAnimId;
};
void TabBarPrivate::updateTabWidgetMode()
{
bool tabWidget = false;
foreach (QGraphicsWidget *page, pages) {
if (page->preferredSize() != QSize(0, 0)) {
tabWidget = true;
break;
}
}
if (tabWidget && tabBarLayout->count() < 3) {
tabBarLayout->insertItem(0, leftSpacer);
tabBarLayout->insertItem(2, rightSpacer);
leftSpacer->show();
rightSpacer->show();
} else if (!tabWidget && tabBarLayout->count() >= 3) {
tabBarLayout->removeItem(leftSpacer);
tabBarLayout->removeItem(rightSpacer);
leftSpacer->hide();
rightSpacer->hide();
}
}
void TabBarPrivate::slidingCompleted(QGraphicsItem *item)
{
if (item == oldPage || item == newPage) {
if (item == newPage) {
mainLayout->addItem(newPage);
newPageAnimId = -1;
} else {
oldPageAnimId = -1;
item->hide();
}
q->setFlags(0);
}
}
void TabBarPrivate::shapeChanged(const QTabBar::Shape shape)
{
//FIXME: QGraphicsLinearLayout doesn't have setDirection, so for now
// North is equal to south and East is equal to West
switch (shape) {
case QTabBar::RoundedWest:
case QTabBar::TriangularWest:
case QTabBar::RoundedEast:
case QTabBar::TriangularEast:
tabBarLayout->setOrientation(Qt::Vertical);
mainLayout->setOrientation(Qt::Horizontal);
mainLayout->itemAt(0)->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
mainLayout->itemAt(1)->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
tabProxy->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
break;
case QTabBar::RoundedSouth:
case QTabBar::TriangularSouth:
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
default:
tabBarLayout->setOrientation(Qt::Horizontal);
mainLayout->setOrientation(Qt::Vertical);
mainLayout->itemAt(0)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
mainLayout->itemAt(1)->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
tabProxy->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
tabProxy->setPreferredSize(tabBar->sizeHint());
}
TabBar::TabBar(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new TabBarPrivate(this))
{
d->tabBar = new NativeTabBar();
d->tabBar->setAttribute(Qt::WA_NoSystemBackground);
d->mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
d->tabBarLayout = new QGraphicsLinearLayout(Qt::Horizontal);
setLayout(d->mainLayout);
d->mainLayout->addItem(d->tabBarLayout);
d->tabProxy = new QGraphicsProxyWidget(this);
d->tabProxy->setWidget(d->tabBar);
d->tabProxy->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
//tabBar is centered, so a stretch at begin one at the end
//FIXME: doesn't seem to be possible to remove stretches from a layout
d->leftSpacer = new QGraphicsWidget(this);
d->rightSpacer = new QGraphicsWidget(this);
d->leftSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
d->rightSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
d->tabBarLayout->addItem(d->leftSpacer);
d->tabBarLayout->addItem(d->tabProxy);
d->tabBarLayout->addItem(d->rightSpacer);
//d->tabBarLayout->setStretchFactor(d->tabProxy, 2);
connect(d->tabBar, SIGNAL(currentChanged(int)), this, SLOT(setCurrentIndex(int)));
connect(d->tabBar, SIGNAL(shapeChanged(QTabBar::Shape)), this, SLOT(shapeChanged(QTabBar::Shape)));
connect(Plasma::Animator::self(), SIGNAL(movementFinished(QGraphicsItem*)), this, SLOT(slidingCompleted(QGraphicsItem*)));
}
TabBar::~TabBar()
{
delete d;
}
int TabBar::insertTab(int index, const QIcon &icon, const QString &label, QGraphicsLayoutItem *content)
{
QGraphicsWidget *page = new QGraphicsWidget(this);
page->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
if (content) {
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, page);
layout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
page->setLayout(layout);
layout->addItem(content);
} else {
page->setPreferredSize(0, 0);
}
d->pages.insert(qBound(0, index, d->pages.count()), page);
if (d->pages.count() == 1) {
d->mainLayout->addItem(page);
page->setVisible(true);
page->setEnabled(true);
} else {
page->setVisible(false);
page->setEnabled(false);
}
d->tabProxy->setPreferredSize(d->tabBar->sizeHint());
d->updateTabWidgetMode();
int actualIndex = d->tabBar->insertTab(index, icon, label);
d->tabProxy->setPreferredSize(d->tabBar->sizeHint());
d->updateTabWidgetMode();
return actualIndex;
}
int TabBar::insertTab(int index, const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(index, QIcon(), label, content);
}
int TabBar::addTab(const QIcon &icon, const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(d->pages.count(), icon, label, content);
}
int TabBar::addTab(const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(d->pages.count(), QIcon(), label, content);
}
int TabBar::currentIndex() const
{
return d->tabBar->currentIndex();
}
void TabBar::setCurrentIndex(int index)
{
if (index > d->tabBar->count() || d->tabBar->count() <= 1) {
return;
}
if (d->currentIndex != index) {
d->tabBar->setCurrentIndex(index);
}
d->mainLayout->removeAt(1);
d->oldPage = d->pages[d->currentIndex];
d->newPage = d->pages[index];
//FIXME: this part should be enabled again once
//http://trolltech.com/developer/task-tracker/index_html?id=220488
//get fixed
#ifdef USE_SLIDING_ANIMATION
d->newPage->resize(d->oldPage->size());
setFlags(QGraphicsItem::ItemClipsChildrenToShape);
//if an animation was in rogress hide everything to avoid an inconsistent state
if (d->newPageAnimId != -1 || d->oldPageAnimId != -1) {
foreach (QGraphicsWidget *page, d->pages) {
page->hide();
}
if (d->newPageAnimId != -1) {
Animator::self()->stopItemMovement(d->newPageAnimId);
}
if (d->oldPageAnimId != -1) {
Animator::self()->stopItemMovement(d->oldPageAnimId);
}
}
d->oldPage->show();
d->newPage->show();
d->newPage->setEnabled(true);
d->oldPage->setEnabled(false);
QRect beforeCurrentGeom(d->oldPage->geometry().toRect());
beforeCurrentGeom.moveTopRight(beforeCurrentGeom.topLeft());
d->newPageAnimId = Animator::self()->moveItem(d->newPage, Plasma::Animator::SlideOutMovement, d->oldPage->pos().toPoint());
if (index > d->currentIndex) {
d->newPage->setPos(d->oldPage->geometry().topRight());
d->oldPageAnimId = Animator::self()->moveItem(d->oldPage, Plasma::Animator::SlideOutMovement, beforeCurrentGeom.topLeft());
} else {
d->newPage->setPos(beforeCurrentGeom.topLeft());
d->oldPageAnimId = Animator::self()->moveItem(d->oldPage, Plasma::Animator::SlideOutMovement, d->oldPage->geometry().topRight().toPoint());
}
#else
d->mainLayout->addItem(d->pages[index]);
d->oldPage->hide();
d->newPage->show();
d->newPage->setEnabled(true);
d->oldPage->setEnabled(false);
#endif
d->currentIndex = index;
emit currentChanged(index);
}
int TabBar::count() const
{
return d->pages.count();
}
void TabBar::removeTab(int index)
{
if (index > d->pages.count()) {
return;
}
int currentIndex = d->tabBar->currentIndex();
d->tabBar->removeTab(index);
QGraphicsWidget *page = d->pages.takeAt(index);
if (index == currentIndex) {
setCurrentIndex(currentIndex);
}
scene()->removeItem(page);
page->deleteLater();
d->updateTabWidgetMode();
d->tabProxy->setPreferredSize(d->tabBar->sizeHint());
}
void TabBar::setTabText(int index, const QString &label)
{
if (index > d->pages.count()) {
return;
}
d->tabBar->setTabText(index, label);
}
QString TabBar::tabText(int index) const
{
return d->tabBar->tabText(index);
}
void TabBar::setTabIcon(int index, const QIcon &icon)
{
d->tabBar->setTabIcon(index, icon);
}
QIcon TabBar::tabIcon(int index) const
{
return d->tabBar->tabIcon(index);
}
void TabBar::setStyleSheet(const QString &stylesheet)
{
d->tabBar->setStyleSheet(stylesheet);
}
QString TabBar::styleSheet() const
{
return d->tabBar->styleSheet();
}
QTabBar *TabBar::nativeWidget() const
{
return d->tabBar;
}
void TabBar::wheelEvent(QGraphicsSceneWheelEvent * event)
{
//FIXME: probably this would make more sense in NativeTabBar, but it works only here
if (d->tabBar->underMouse()) {
//Cycle tabs with the circular array tecnique
if (event->delta() < 0) {
int index = d->tabBar->currentIndex();
//search for an enabled tab
for (int i = 0; i < d->tabBar->count()-1; ++i) {
index = (index + 1) % d->tabBar->count();
if (d->tabBar->isTabEnabled(index)) {
break;
}
}
d->tabBar->setCurrentIndex(index);
} else {
int index = d->tabBar->currentIndex();
for (int i = 0; i < d->tabBar->count()-1; ++i) {
index = (d->tabBar->count() + index -1) % d->tabBar->count();
if (d->tabBar->isTabEnabled(index)) {
break;
}
}
d->tabBar->setCurrentIndex(index);
}
} else {
QGraphicsWidget::wheelEvent(event);
}
}
} // namespace Plasma
#include <tabbar.moc>