File indexing completed on 2024-05-12 16:35:47

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
0003    Copyright (C) 2003 Norbert Andres <nandres@web.de>
0004    Copyright (C) 2002 Laurent Montel <montel@kde.org>
0005    Copyright (C) 1999 David Faure <faure@kde.org>
0006    Copyright (C) 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
0007    Copyright (C) 1998-2000 Torben Weis <weis@kde.org>
0008 
0009    This library is free software; you can redistribute it and/or
0010    modify it under the terms of the GNU Library General Public
0011    License as published by the Free Software Foundation; either
0012    version 2 of the License, or (at your option) any later version.
0013 
0014    This library is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017    Library General Public License for more details.
0018 
0019    You should have received a copy of the GNU Library General Public License
0020    along with this library; see the file COPYING.LIB.  If not, write to
0021    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023 */
0024 
0025 #include "TabBar.h"
0026 
0027 #include <QList>
0028 #include <QMouseEvent>
0029 #include <QPaintEvent>
0030 #include <QPainter>
0031 #include <QPolygon>
0032 #include <QPixmap>
0033 #include <QResizeEvent>
0034 #include <QString>
0035 #include <QStringList>
0036 #include <QStyle>
0037 #include <QTimer>
0038 #include <QToolButton>
0039 #include <QWidget>
0040 #include <QWheelEvent>
0041 #include <QFontDatabase>
0042 
0043 // TODO
0044 // improvement possibilities
0045 // - use offscreen buffer to reduce flicker even more
0046 // - keep track of tabs, only (re)layout when necessary
0047 // - paint all tabs to buffer, show only by shifting
0048 // - customizable button pixmaps
0049 // - use QStyle to paint the tabs & buttons (is it good/possible?)
0050 
0051 namespace Calligra
0052 {
0053 namespace Sheets
0054 {
0055 
0056 class TabBarPrivate
0057 {
0058 public:
0059     TabBar* tabbar;
0060 
0061     // scroll buttons
0062     QToolButton* scrollFirstButton;
0063     QToolButton* scrollLastButton;
0064     QToolButton* scrollBackButton;
0065     QToolButton* scrollForwardButton;
0066 
0067     // read-only: no mouse drag, double-click, right-click
0068     bool readOnly;
0069 
0070     // list of all tabs, in order of appearance
0071     QStringList tabs;
0072 
0073     // array of QRect for each visible tabs
0074     QList<QRect> tabRects;
0075 
0076     // leftmost tab (or rightmost for right-to-left layouts)
0077     int firstTab;
0078 
0079     // rightmost tab (or leftmost for right-to-left layouts)
0080     int lastTab;
0081 
0082     // the active tab in the range form 1..n.
0083     // if this value is 0, that means that no tab is active.
0084     int activeTab;
0085 
0086     // unusable space on the left, taken by the scroll buttons
0087     int offset;
0088 
0089     // when the user drag the tab (in order to move it)
0090     // this is the target position, it's 0 if no tab is dragged
0091     int targetTab;
0092 
0093     // wheel movement since selected tab was last changed by the
0094     // mouse wheel
0095     int wheelDelta;
0096 
0097     // true if autoscroll is active
0098     bool autoScroll;
0099 
0100     // calculate the bounding rectangle for each visible tab
0101     void layoutTabs();
0102 
0103     // reposition scroll buttons
0104     void layoutButtons();
0105 
0106     // find a tab whose bounding rectangle contains the pos
0107     // return -1 if no such tab is found
0108     int tabAt(const QPoint& pos);
0109 
0110     // draw a single tab
0111     void drawTab(QPainter& painter, QRect& rect, const QString& text, bool active);
0112 
0113     // draw a marker to indicate tab moving
0114     void drawMoveMarker(QPainter& painter, int x, int y);
0115 
0116     // update the enable/disable status of scroll buttons
0117     void updateButtons();
0118 
0119     // get the font to use on the tabs
0120     QFont font(bool selected);
0121 };
0122 
0123 // built-in pixmap for scroll-first button
0124 static const char * const arrow_leftmost_xpm[] = {
0125     "10 10 2 1",
0126     "  c None",
0127     ". c #000000",
0128     "          ",
0129     "  .    .  ",
0130     "  .   ..  ",
0131     "  .  ...  ",
0132     "  . ....  ",
0133     "  .  ...  ",
0134     "  .   ..  ",
0135     "  .    .  ",
0136     "          ",
0137     "          "
0138 };
0139 
0140 // built-in pixmap for scroll-last button
0141 static const char * const arrow_rightmost_xpm[] = {
0142     "10 10 2 1",
0143     "  c None",
0144     ". c #000000",
0145     "          ",
0146     "  .    .  ",
0147     "  ..   .  ",
0148     "  ...  .  ",
0149     "  .... .  ",
0150     "  ...  .  ",
0151     "  ..   .  ",
0152     "  .    .  ",
0153     "          ",
0154     "          "
0155 };
0156 
0157 // built-in pixmap for scroll-left button
0158 static const char * const arrow_left_xpm[] = {
0159     "10 10 2 1",
0160     "  c None",
0161     ". c #000000",
0162     "          ",
0163     "      .   ",
0164     "     ..   ",
0165     "    ...   ",
0166     "   ....   ",
0167     "    ...   ",
0168     "     ..   ",
0169     "      .   ",
0170     "          ",
0171     "          "
0172 };
0173 
0174 // built-in pixmap for scroll-right button
0175 static const char * const arrow_right_xpm[] = {
0176     "10 10 2 1",
0177     "  c None",
0178     ". c #000000",
0179     "          ",
0180     "   .      ",
0181     "   ..     ",
0182     "   ...    ",
0183     "   ....   ",
0184     "   ...    ",
0185     "   ..     ",
0186     "   .      ",
0187     "          ",
0188     "          "
0189 };
0190 
0191 
0192 void TabBarPrivate::layoutTabs()
0193 {
0194     tabRects.clear();
0195 
0196     QFont f = font(true);
0197     QFontMetrics fm(f, tabbar);
0198     if (tabbar->isLeftToRight()) {
0199         // left to right
0200         int x = 0;
0201         for (int c = 0; c < tabs.count(); c++) {
0202             QRect rect;
0203             if (c >= firstTab - 1) {
0204                 QString text = tabs[ c ];
0205                 int tw = fm.width(text) + 4;
0206                 rect = QRect(x, 0, tw + 20, tabbar->height());
0207                 x = x + tw + 20;
0208             }
0209             tabRects.append(rect);
0210         }
0211 
0212         lastTab = tabRects.count();
0213         for (int i = 0; i < tabRects.count(); i++)
0214             if (tabRects[i].right() - 10 + offset > tabbar->width()) {
0215                 lastTab = i;
0216                 break;
0217             }
0218     } else {
0219         // right to left
0220         int x = tabbar->width() - offset;
0221         for (int c = 0; c < tabs.count(); c++) {
0222             QRect rect;
0223             if (c >= firstTab - 1) {
0224                 QString text = tabs[ c ];
0225                 int tw = fm.width(text) + 4;
0226                 rect = QRect(x - tw - 20, 0, tw + 20, tabbar->height());
0227                 x = x - tw - 20;
0228             }
0229             tabRects.append(rect);
0230         }
0231 
0232         lastTab = tabRects.count();
0233         for (int i = tabRects.count() - 1; i > 0; i--)
0234             if (tabRects[i].left() > 0) {
0235                 lastTab = i + 1;
0236                 break;
0237             }
0238     }
0239     tabbar->updateGeometry();
0240 }
0241 
0242 int TabBarPrivate::tabAt(const QPoint& pos)
0243 {
0244     for (int i = 0; i < tabRects.count(); i++) {
0245         QRect rect = tabRects[ i ];
0246         if (rect.isNull()) continue;
0247         if (rect.contains(pos)) return i;
0248     }
0249 
0250     return -1; // not found
0251 }
0252 
0253 void TabBarPrivate::drawTab(QPainter& painter, QRect& rect, const QString& text, bool active)
0254 {
0255     QPolygon polygon;
0256 
0257     if (tabbar->isLeftToRight())
0258         polygon << QPoint(rect.x(), rect.y())
0259         << QPoint(rect.x(), rect.bottom() - 3)
0260         << QPoint(rect.x() + 2, rect.bottom())
0261         << QPoint(rect.right() - 4, rect.bottom())
0262         << QPoint(rect.right() - 2, rect.bottom() - 2)
0263         << QPoint(rect.right() + 5, rect.top());
0264     else
0265         polygon << QPoint(rect.right(), rect.top())
0266         << QPoint(rect.right(), rect.bottom() - 3)
0267         << QPoint(rect.right() - 2, rect.bottom())
0268         << QPoint(rect.x() + 4, rect.bottom())
0269         << QPoint(rect.x() + 2, rect.bottom() - 2)
0270         << QPoint(rect.x() - 5, rect.top());
0271 
0272     painter.save();
0273 
0274     // fill it first
0275     QBrush bg = tabbar->palette().background();
0276     if (active)
0277         bg = tabbar->palette().base();
0278     painter.setBrush(bg);
0279     painter.setPen(QPen(Qt::NoPen));
0280     painter.drawPolygon(polygon);
0281 
0282     // draw the lines
0283     painter.setPen(QPen(tabbar->palette().color(QPalette::Dark), 0));
0284     painter.setRenderHint(QPainter::Antialiasing);
0285     if (!active) {
0286         const bool reverseLayout = tabbar->isRightToLeft();
0287         painter.drawLine(rect.x() - (reverseLayout ? 5 : 0), rect.y(),
0288                          rect.right() + (reverseLayout ? 0 : 5), rect.top());
0289     }
0290 
0291     painter.drawPolyline(polygon);
0292 
0293     painter.setPen(tabbar->palette().color(QPalette::ButtonText));
0294     QFont f = font(active);
0295     painter.setFont(f);
0296     QFontMetrics fm = painter.fontMetrics();
0297     int tx =  rect.x() + (rect.width() - fm.width(text)) / 2;
0298     int ty =  rect.y() + (rect.height() - fm.height()) / 2 + fm.ascent();
0299     painter.drawText(tx, ty, text);
0300 
0301     painter.restore();
0302 }
0303 
0304 void TabBarPrivate::drawMoveMarker(QPainter& painter, int x, int y)
0305 {
0306     QPolygon movmark;
0307 
0308     movmark << QPoint(x, y) << QPoint(x + 7, y) << QPoint(x + 4, y + 6);
0309     QBrush oldBrush = painter.brush();
0310     painter.setBrush(Qt::black);
0311     painter.drawPolygon(movmark);
0312     painter.setBrush(oldBrush);
0313 }
0314 
0315 void TabBarPrivate::layoutButtons()
0316 {
0317     int bw = tabbar->height();
0318     int w = tabbar->width();
0319     offset = bw * 4;
0320 
0321     if (tabbar->isLeftToRight()) {
0322         scrollFirstButton->setGeometry(0, 0, bw, bw);
0323         scrollFirstButton->setIcon(QIcon(QPixmap(arrow_leftmost_xpm)));
0324         scrollBackButton->setGeometry(bw, 0, bw, bw);
0325         scrollBackButton->setIcon(QIcon(QPixmap(arrow_left_xpm)));
0326         scrollForwardButton->setGeometry(bw*2, 0, bw, bw);
0327         scrollForwardButton->setIcon(QIcon(QPixmap(arrow_right_xpm)));
0328         scrollLastButton->setGeometry(bw*3, 0, bw, bw);
0329         scrollLastButton->setIcon(QIcon(QPixmap(arrow_rightmost_xpm)));
0330     } else {
0331         scrollFirstButton->setGeometry(w - bw, 0, bw, bw);
0332         scrollFirstButton->setIcon(QIcon(QPixmap(arrow_rightmost_xpm)));
0333         scrollBackButton->setGeometry(w - 2*bw, 0, bw, bw);
0334         scrollBackButton->setIcon(QIcon(QPixmap(arrow_right_xpm)));
0335         scrollForwardButton->setGeometry(w - 3*bw, 0, bw, bw);
0336         scrollForwardButton->setIcon(QIcon(QPixmap(arrow_left_xpm)));
0337         scrollLastButton->setGeometry(w - 4*bw, 0, bw, bw);
0338         scrollLastButton->setIcon(QIcon(QPixmap(arrow_leftmost_xpm)));
0339     }
0340 }
0341 
0342 void TabBarPrivate::updateButtons()
0343 {
0344     scrollFirstButton->setEnabled(tabbar->canScrollBack());
0345     scrollBackButton->setEnabled(tabbar->canScrollBack());
0346     scrollForwardButton->setEnabled(tabbar->canScrollForward());
0347     scrollLastButton->setEnabled(tabbar->canScrollForward());
0348 }
0349 
0350 QFont TabBarPrivate::font(bool selected)
0351 {
0352     QFont f = QFontDatabase::systemFont(QFontDatabase::TitleFont);
0353     if (selected) f.setBold(true);
0354     return f;
0355 }
0356 
0357 // creates a new tabbar
0358 TabBar::TabBar(QWidget* parent, const char* /*name*/)
0359         : QWidget(parent)
0360         , d(new TabBarPrivate)
0361 {
0362     d->tabbar = this;
0363     d->readOnly = false;
0364     d->firstTab = 1;
0365     d->lastTab = 0;
0366     d->activeTab = 0;
0367     d->targetTab = 0;
0368     d->wheelDelta = 0;
0369     d->autoScroll = false;
0370     d->offset = 64;
0371     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0372 
0373     // initialize the scroll buttons
0374     d->scrollFirstButton = new QToolButton(this);
0375     connect(d->scrollFirstButton, SIGNAL(clicked()),
0376             this, SLOT(scrollFirst()));
0377     d->scrollLastButton = new QToolButton(this);
0378     connect(d->scrollLastButton, SIGNAL(clicked()),
0379             this, SLOT(scrollLast()));
0380     d->scrollBackButton = new QToolButton(this);
0381     connect(d->scrollBackButton, SIGNAL(clicked()),
0382             this, SLOT(scrollBack()));
0383     d->scrollForwardButton = new QToolButton(this);
0384     connect(d->scrollForwardButton, SIGNAL(clicked()),
0385             this, SLOT(scrollForward()));
0386     d->layoutButtons();
0387     d->updateButtons();
0388 }
0389 
0390 // destroys the tabbar
0391 TabBar::~TabBar()
0392 {
0393     delete d;
0394 }
0395 
0396 // adds a new visible tab
0397 void TabBar::addTab(const QString& text)
0398 {
0399     d->tabs.append(text);
0400 
0401     update();
0402 }
0403 
0404 // removes a tab
0405 void TabBar::removeTab(const QString& text)
0406 {
0407     int i = d->tabs.indexOf(text);
0408     if (i == -1) return;
0409 
0410     if (d->activeTab == i + 1)
0411         d->activeTab = 0;
0412 
0413     d->tabs.removeAll(text);
0414 
0415     update();
0416 }
0417 
0418 // removes all tabs
0419 void TabBar::clear()
0420 {
0421     d->tabs.clear();
0422     d->activeTab = 0;
0423     d->firstTab = 1;
0424 
0425     update();
0426 }
0427 
0428 bool TabBar::readOnly() const
0429 {
0430     return d->readOnly;
0431 }
0432 
0433 void TabBar::setReadOnly(bool ro)
0434 {
0435     d->readOnly = ro;
0436 }
0437 
0438 void TabBar::setTabs(const QStringList& list)
0439 {
0440     QString left, active;
0441 
0442     if (d->activeTab > 0)
0443         active = d->tabs[ d->activeTab-1 ];
0444     if (d->firstTab > 0 && d->firstTab <= d->tabs.size())
0445         left = d->tabs[ d->firstTab-1 ];
0446 
0447     d->tabs = list;
0448 
0449     if (!left.isNull()) {
0450         d->firstTab = d->tabs.indexOf(left) + 1;
0451         if (d->firstTab > (int)d->tabs.count())
0452             d->firstTab = 1;
0453         if (d->firstTab <= 0)
0454             d->firstTab = 1;
0455     }
0456 
0457     d->activeTab = 0;
0458     if (!active.isNull())
0459         setActiveTab(active);
0460 
0461     update();
0462 }
0463 
0464 QStringList TabBar::tabs() const
0465 {
0466     return d->tabs;
0467 }
0468 
0469 unsigned TabBar::count() const
0470 {
0471     return d->tabs.count();
0472 }
0473 
0474 bool TabBar::canScrollBack() const
0475 {
0476     if (d->tabs.count() == 0)
0477         return false;
0478 
0479     return d->firstTab > 1;
0480 }
0481 
0482 bool TabBar::canScrollForward() const
0483 {
0484     if (d->tabs.count() == 0)
0485         return false;
0486 
0487     return d->lastTab < (int)d->tabs.count();
0488 }
0489 
0490 void TabBar::scrollBack()
0491 {
0492     if (!canScrollBack())
0493         return;
0494 
0495     d->firstTab--;
0496     if (d->firstTab < 1) d->firstTab = 1;
0497 
0498     d->layoutTabs();
0499     d->updateButtons();
0500     update();
0501 }
0502 
0503 void TabBar::scrollForward()
0504 {
0505     if (!canScrollForward())
0506         return;
0507 
0508     d->firstTab ++;
0509     if (d->firstTab > (int)d->tabs.count())
0510         d->firstTab = d->tabs.count();
0511 
0512     d->layoutTabs();
0513     d->updateButtons();
0514     update();
0515 }
0516 
0517 void TabBar::scrollFirst()
0518 {
0519     if (!canScrollBack())
0520         return;
0521 
0522     d->firstTab = 1;
0523     d->layoutTabs();
0524     d->updateButtons();
0525     update();
0526 }
0527 
0528 void TabBar::scrollLast()
0529 {
0530     if (!canScrollForward())
0531         return;
0532 
0533     d->layoutTabs();
0534 
0535     if (!isRightToLeft()) {
0536         int fullWidth = d->tabRects[ d->tabRects.count()-1 ].right();
0537         int delta = fullWidth - width() + d->offset;
0538         for (int i = 0; i < d->tabRects.count(); i++)
0539             if (d->tabRects[i].x() > delta) {
0540                 d->firstTab = i + 1;
0541                 break;
0542             }
0543     } else {
0544         // FIXME optimize this, perhaps without loop
0545         for (; d->firstTab <= (int)d->tabRects.count();) {
0546             int x = d->tabRects[ d->tabRects.count()-1 ].x();
0547             if (x > 0) break;
0548             d->firstTab++;
0549             d->layoutTabs();
0550         }
0551     }
0552 
0553     d->layoutTabs();
0554     d->updateButtons();
0555     update();
0556 }
0557 
0558 void TabBar::ensureVisible(const QString& tab)
0559 {
0560     int i = d->tabs.indexOf(tab);
0561     if (i == -1)
0562         return;
0563     i++;
0564 
0565     // already visible, then do nothing
0566     if ((i >= d->firstTab) && (i <= d->lastTab))
0567         return;
0568 
0569     if (i < d->firstTab)
0570         while (i < d->firstTab)
0571             scrollBack();
0572 
0573     if (i > d->lastTab)
0574         while (i > d->lastTab)
0575             scrollForward();
0576 }
0577 
0578 void TabBar::moveTab(int tab, int target)
0579 {
0580     QString tabName = d->tabs.takeAt(tab);
0581 
0582     if (target > tab)
0583         target--;
0584 
0585     if (target >= d->tabs.count())
0586         d->tabs.append(tabName);
0587     else
0588         d->tabs.insert(target, tabName);
0589 
0590     if (d->activeTab == tab + 1)
0591         d->activeTab = target + 1;
0592 
0593     update();
0594 }
0595 
0596 void TabBar::setActiveTab(const QString& text)
0597 {
0598     int i = d->tabs.indexOf(text);
0599     if (i == -1)
0600         return;
0601 
0602     if (i + 1 == d->activeTab)
0603         return;
0604 
0605     d->activeTab = i + 1;
0606     d->updateButtons();
0607     update();
0608 
0609     emit tabChanged(text);
0610 }
0611 
0612 void TabBar::autoScrollBack()
0613 {
0614     if (!d->autoScroll) return;
0615 
0616     scrollBack();
0617 
0618     if (!canScrollBack())
0619         d->autoScroll = false;
0620     else
0621         QTimer::singleShot(400, this, SLOT(autoScrollBack()));
0622 }
0623 
0624 void TabBar::autoScrollForward()
0625 {
0626     if (!d->autoScroll) return;
0627 
0628     scrollForward();
0629 
0630     if (!canScrollForward())
0631         d->autoScroll = false;
0632     else
0633         QTimer::singleShot(400, this, SLOT(autoScrollForward()));
0634 }
0635 
0636 void TabBar::paintEvent(QPaintEvent*)
0637 {
0638     if (d->tabs.count() == 0) {
0639         update();
0640         return;
0641     }
0642 
0643     d->layoutTabs();
0644     d->updateButtons();
0645 
0646     QPainter painter(this);
0647     if (!isRightToLeft())
0648         painter.translate(d->offset, 0);
0649 
0650     if (!isRightToLeft())
0651         painter.translate(5, 0);
0652 
0653     // draw first all non-active, visible tabs
0654     for (int c = d->tabRects.count() - 1; c >= 0; c--) {
0655         QRect rect = d->tabRects[ c ];
0656         if (rect.isNull()) continue;
0657         QString text = d->tabs[ c ];
0658         d->drawTab(painter, rect, text, false);
0659     }
0660 
0661     // draw the active tab
0662     if (d->activeTab > 0) {
0663         QRect rect = d->tabRects[ d->activeTab-1 ];
0664         if (!rect.isNull()) {
0665             QString text = d->tabs[ d->activeTab-1 ];
0666             d->drawTab(painter, rect, text, true);
0667         }
0668     }
0669 
0670     // draw the move marker
0671     if (d->targetTab > 0) {
0672         int p = qMin(d->targetTab, (int)d->tabRects.count());
0673         QRect rect = d->tabRects[ p-1 ];
0674         if (!rect.isNull()) {
0675             int x = !isRightToLeft() ? rect.x() : rect.right() - 7;
0676             if (d->targetTab > (int)d->tabRects.count())
0677                 x = !isRightToLeft() ? rect.right() - 7 : rect.x() - 3;
0678             d->drawMoveMarker(painter, x, rect.y());
0679         }
0680     }
0681 }
0682 
0683 void TabBar::resizeEvent(QResizeEvent*)
0684 {
0685     d->layoutButtons();
0686     d->updateButtons();
0687     update();
0688 }
0689 
0690 QSize TabBar::sizeHint() const
0691 {
0692     int h = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
0693     int w = 5 * h;  // we have 4 buttons, the 5 is to give some free space too
0694     if (d->tabRects.size()) w += d->tabRects[d->tabRects.size() - 1].right();
0695 
0696     return QSize(w, h);
0697 }
0698 
0699 void TabBar::renameTab(const QString& old_name, const QString& new_name)
0700 {
0701     d->tabs.replace(d->tabs.indexOf(old_name), new_name);
0702 
0703     update();
0704 }
0705 
0706 QString TabBar::activeTab() const
0707 {
0708     if (d->activeTab == 0)
0709         return QString();
0710     else
0711         return d->tabs[ d->activeTab-1 ];
0712 }
0713 
0714 void TabBar::mousePressEvent(QMouseEvent* ev)
0715 {
0716     if (d->tabs.count() == 0) {
0717         update();
0718         return;
0719     }
0720 
0721     d->layoutTabs();
0722 
0723     QPoint pos = ev->pos();
0724     if (!isRightToLeft()) pos = pos - QPoint(d->offset, 0);
0725 
0726     int tab = d->tabAt(pos) + 1;
0727     if ((tab > 0) && (tab != d->activeTab)) {
0728         d->activeTab = tab;
0729         update();
0730 
0731         emit tabChanged(d->tabs[ d->activeTab-1]);
0732 
0733         // scroll if partially visible
0734         if (d->tabRects[ tab-1 ].right() > width() - d->offset)
0735             scrollForward();
0736     }
0737 
0738     if (ev->button() == Qt::RightButton)
0739         if (!d->readOnly)
0740             emit contextMenu(ev->globalPos());
0741 }
0742 
0743 void TabBar::mouseReleaseEvent(QMouseEvent* ev)
0744 {
0745     if (d->readOnly) return;
0746 
0747     d->autoScroll = false;
0748 
0749     if (ev->button() == Qt::LeftButton && d->targetTab != 0) {
0750         emit tabMoved(d->activeTab - 1, d->targetTab - 1);
0751         d->targetTab = 0;
0752     }
0753 }
0754 
0755 void TabBar::mouseMoveEvent(QMouseEvent* ev)
0756 {
0757     if (d->readOnly) return;
0758 
0759     QPoint pos = ev->pos();
0760     if (!isRightToLeft()) pos = pos - QPoint(d->offset, 0);
0761 
0762     // check if user drags a tab to move it
0763     int i = d->tabAt(pos) + 1;
0764     if ((i > 0) && (i != d->targetTab)) {
0765         if (i == d->activeTab) i = 0;
0766         if (i == d->activeTab + 1) i = 0;
0767 
0768         if (i != d->targetTab) {
0769             d->targetTab = i;
0770             d->autoScroll = false;
0771             update();
0772         }
0773     }
0774 
0775     // drag past the very latest visible tab
0776     // e.g move a tab to the last ordering position
0777     QRect r = d->tabRects[ d->tabRects.count()-1 ];
0778     bool moveToLast = false;
0779     if (r.isValid()) {
0780         if (!isRightToLeft())
0781             if (pos.x() > r.right())
0782                 if (pos.x() < width())
0783                     moveToLast = true;
0784         if (isRightToLeft())
0785             if (pos.x() < r.x())
0786                 if (pos.x() > 0)
0787                     moveToLast = true;
0788     }
0789     if (moveToLast)
0790         if (d->targetTab != (int)d->tabRects.count() + 1) {
0791             d->targetTab = d->tabRects.count() + 1;
0792             d->autoScroll = false;
0793             update();
0794         }
0795 
0796     // outside far too left ? activate autoscroll...
0797     if (pos.x() < 0 && !d->autoScroll) {
0798         d->autoScroll = true;
0799         autoScrollBack();
0800     }
0801 
0802     // outside far too right ? activate autoscroll...
0803     int w = width() - d->offset;
0804     if (pos.x() > w && !d->autoScroll) {
0805         d->autoScroll = true;
0806         autoScrollForward();
0807     }
0808 }
0809 
0810 void TabBar::mouseDoubleClickEvent(QMouseEvent* ev)
0811 {
0812     int offset = isRightToLeft() ? 0 : d->offset;
0813     if (ev->pos().x() > offset)
0814         if (!d->readOnly)
0815             emit doubleClicked();
0816 }
0817 
0818 void TabBar::wheelEvent(QWheelEvent * e)
0819 {
0820     if (d->tabs.count() == 0) {
0821         update();
0822         return;
0823     }
0824 
0825     // Currently one wheel movement is a delta of 120.
0826     // The 'unused' delta is stored for devices that allow
0827     // a higher scrolling resolution.
0828     // The delta required to move one tab is one wheel movement:
0829     const int deltaRequired = 120;
0830 
0831     d->wheelDelta += e->delta();
0832     int tabDelta = - (d->wheelDelta / deltaRequired);
0833     d->wheelDelta = d->wheelDelta % deltaRequired;
0834     int numTabs = d->tabs.size();
0835 
0836     if (d->activeTab + tabDelta > numTabs) {
0837         // Would take us past the last tab
0838         d->activeTab = numTabs;
0839     } else if (d->activeTab + tabDelta < 1) {
0840         // Would take us before the first tab
0841         d->activeTab = 1;
0842     } else {
0843         d->activeTab = d->activeTab + tabDelta;
0844     }
0845 
0846     // Find the left and right edge of the new tab.  If we're
0847     // going forward, and the right of the new tab isn't visible
0848     // then scroll forward.  Likewise, if going back, and the
0849     // left of the new tab isn't visible, then scroll back.
0850     int activeTabRight = d->tabRects[ d->activeTab-1 ].right();
0851     int activeTabLeft  = d->tabRects[ d->activeTab-1 ].left();
0852     if (tabDelta > 0 && activeTabRight > width() - d->offset) {
0853         scrollForward();
0854     } else if (tabDelta < 0 && activeTabLeft < width() - d->offset) {
0855         scrollBack();
0856     }
0857 
0858     update();
0859     emit tabChanged(d->tabs[ d->activeTab-1]);
0860 }
0861 
0862 } // namespace Sheets
0863 } // namespace Calligra