~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/widgets/qtabbar.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
 **
 
3
 ** Implementation of QTabBar class.
 
4
 **
 
5
 ** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
6
 **
 
7
 ** This file is part of the widgets module of the Qt Toolkit.
 
8
 **
 
9
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
10
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
11
 **
 
12
 ****************************************************************************/
 
13
 
 
14
#include "qapplication.h"
 
15
#include "qbitmap.h"
 
16
#include "qcursor.h"
 
17
#include "qevent.h"
 
18
#include "qicon.h"
 
19
#include "qpainter.h"
 
20
#include "qstyle.h"
 
21
#include "qstyleoption.h"
 
22
#include "qtabbar.h"
 
23
#include "qtabwidget.h"
 
24
#include "qtoolbutton.h"
 
25
#include "qtooltip.h"
 
26
#include "qstylepainter.h"
 
27
#include <private/qinternal_p.h>
 
28
#ifndef QT_NO_ACCESSIBILITY
 
29
#include "qaccessible.h"
 
30
#endif
 
31
 
 
32
#include "qdebug.h"
 
33
#include "private/qwidget_p.h"
 
34
 
 
35
 
 
36
class QTabBarPrivate  : public QWidgetPrivate
 
37
{
 
38
    Q_DECLARE_PUBLIC(QTabBar)
 
39
public:
 
40
    QTabBarPrivate()
 
41
        :currentIndex(-1), pressedIndex(-1),
 
42
         shape(QTabBar::RoundedNorth),
 
43
         layoutDirty(false), drawBase(true), scrollOffset(0){}
 
44
 
 
45
    int currentIndex;
 
46
    int pressedIndex;
 
47
    QTabBar::Shape shape;
 
48
    bool layoutDirty;
 
49
    bool drawBase;
 
50
    int scrollOffset;
 
51
 
 
52
    struct Tab {
 
53
        inline Tab():enabled(true), shortcutId(0){}
 
54
        inline Tab(const QIcon &ico, const QString &txt):enabled(true), shortcutId(0), text(txt), icon(ico){}
 
55
        bool enabled;
 
56
        int shortcutId;
 
57
        QString text, toolTip;
 
58
        QIcon icon;
 
59
        QRect rect;
 
60
        QVariant data;
 
61
    };
 
62
    QList<Tab> tabList;
 
63
 
 
64
    void init();
 
65
    int extraWidth() const;
 
66
 
 
67
    Tab *at(int index);
 
68
    const Tab *at(int index) const;
 
69
 
 
70
    int indexAtPos(const QPoint &p) const;
 
71
 
 
72
    inline bool validIndex(int index) const { return index >= 0 && index < tabList.count(); }
 
73
 
 
74
    QToolButton* rightB; // right or bottom
 
75
    QToolButton* leftB; // left or top
 
76
    void scrollTabs(); // private slot
 
77
    QRect hoverRect;
 
78
 
 
79
    void refresh();
 
80
    void layoutTabs();
 
81
 
 
82
    void makeVisible(int index);
 
83
    QStyleOptionTab getStyleOption(int tab) const;
 
84
};
 
85
 
 
86
 
 
87
QStyleOptionTab QTabBarPrivate::getStyleOption(int tab) const
 
88
{
 
89
    Q_Q(const QTabBar);
 
90
    QStyleOptionTab opt;
 
91
    const QTabBarPrivate::Tab *ptab = &tabList.at(tab);
 
92
    opt.init(q);
 
93
    opt.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
 
94
    opt.rect = q->tabRect(tab);
 
95
    bool isCurrent = tab == currentIndex;
 
96
    opt.row = 0;
 
97
    if (tab == pressedIndex)
 
98
        opt.state |= QStyle::State_Sunken;
 
99
    if (isCurrent)
 
100
        opt.state |= QStyle::State_Selected;
 
101
    if (isCurrent && q->hasFocus())
 
102
        opt.state |= QStyle::State_HasFocus;
 
103
    if (q->isEnabled() && ptab->enabled)
 
104
        opt.state |= QStyle::State_Enabled;
 
105
    if (q->isActiveWindow())
 
106
        opt.state |= QStyle::State_Active;
 
107
    if (opt.rect == hoverRect)
 
108
        opt.state |= QStyle::State_MouseOver;
 
109
    opt.shape = shape;
 
110
    opt.text = ptab->text;
 
111
    opt.icon = ptab->icon;
 
112
 
 
113
    int totalTabs = tabList.size();
 
114
 
 
115
    if (tab > 0 && tab - 1 == currentIndex)
 
116
        opt.selectedPosition = QStyleOptionTab::PreviousIsSelected;
 
117
    else if (tab < totalTabs - 1 && tab + 1 == currentIndex)
 
118
        opt.selectedPosition = QStyleOptionTab::NextIsSelected;
 
119
    else
 
120
        opt.selectedPosition = QStyleOptionTab::NotAdjacent;
 
121
 
 
122
    if (tab == 0) {
 
123
        if (totalTabs > 1)
 
124
            opt.position = QStyleOptionTab::Beginning;
 
125
        else
 
126
            opt.position = QStyleOptionTab::OnlyOneTab;
 
127
    } else if (tab == totalTabs - 1) {
 
128
        opt.position = QStyleOptionTab::End;
 
129
    } else {
 
130
        opt.position = QStyleOptionTab::Middle;
 
131
    }
 
132
    if (const QTabWidget *tw = qobject_cast<const QTabWidget *>(q->parentWidget())) {
 
133
        if (tw->cornerWidget(Qt::TopLeftCorner) || tw->cornerWidget(Qt::BottomLeftCorner))
 
134
            opt.cornerWidgets |= QStyleOptionTab::LeftCornerWidget;
 
135
        if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner))
 
136
            opt.cornerWidgets |= QStyleOptionTab::RightCornerWidget;
 
137
    }
 
138
    return opt;
 
139
}
 
140
 
 
141
/*!
 
142
    \class QTabBar
 
143
    \brief The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
 
144
 
 
145
    \ingroup advanced
 
146
    \mainclass
 
147
 
 
148
    QTabBar is straightforward to use; it draws the tabs using one of
 
149
    the predefined \link QTabBar::Shape shapes\endlink, and emits a
 
150
    signal when a tab is selected. It can be subclassed to tailor the
 
151
    look and feel. Qt also provides a ready-made \l{QTabWidget}.
 
152
 
 
153
    Each tab has a tabText(), an optional tabIcon(), an optional
 
154
    tabToolTip(), and optional tabData(). The tabs's attributes can be
 
155
    changed with setTabText(), setTabIcon(), setTabToolTip(), and
 
156
    setTabData(). Each tabs can be enabled or disabled individually
 
157
    with setTabEnabled().
 
158
 
 
159
    Tabs are added using addTab(), or inserted at particular positions
 
160
    using insertTab(). The total number of tabs is given by
 
161
    count(). Tabs can be removed from the tab bar with
 
162
    removeTab(). Combining removeTab() and insertTab() allows you to
 
163
    move tabs to different positions.
 
164
 
 
165
    The \l shape property defines the tabs' appearance. The choice of
 
166
    shape is a matter of taste, although tab dialogs (for preferences
 
167
    and similar) invariably use \c RoundedNorth.
 
168
    Tab controls in windows other than dialogs almost
 
169
    always use either \c RoundedSouth or \c TriangularSouth. Many
 
170
    spreadsheets and other tab controls in which all the pages are
 
171
    essentially similar use \c TriangularSouth, whereas \c
 
172
    RoundedSouth is used mostly when the pages are different (e.g. a
 
173
    multi-page tool palette). The default in QTabBar is \c
 
174
    RoundedNorth.
 
175
 
 
176
    The most important part of QTabBar's API is the currentChanged()
 
177
    signal.  This is emitted whenever the current tab changes (even at
 
178
    startup, when the current tab changes from 'none'). There is also
 
179
    a slot, setCurrentIndex(), which can be used to select a tab
 
180
    programmatically. The function currentIndex() returns the index of
 
181
    the current tab, \l count holds the number of tabs.
 
182
 
 
183
    QTabBar creates automatic mnemonic keys in the manner of QAbstractButton;
 
184
    e.g. if a tab's label is "\&Graphics", Alt+G becomes a shortcut
 
185
    key for switching to that tab.
 
186
 
 
187
    The following virtual functions may need to be reimplemented in
 
188
    order to tailor the look and feel or store extra data with each
 
189
    tab:
 
190
 
 
191
    \list
 
192
    \i tabSizeHint() calcuates the size of a tab.
 
193
    \i tabInserted() notifies that a new tab was added.
 
194
    \i tabRemoved() notifies that a tab was removed.
 
195
    \i tabLayoutChange() notifies that the tabs have been re-laid out.
 
196
    \i paintEvent() paints all tabs.
 
197
    \endlist
 
198
 
 
199
    For subclasses, you might also need the tabRect() functions which
 
200
    returns the visual geometry of a single tab.
 
201
 
 
202
    \inlineimage qtabbar-m.png Screenshot in Motif style
 
203
    \inlineimage qtabbar-w.png Screenshot in Windows style
 
204
*/
 
205
 
 
206
/*!
 
207
    \enum QTabBar::Shape
 
208
 
 
209
    This enum type lists the built-in shapes supported by QTabBar. Treat these
 
210
    as hints as some styles may not render some of the shapes. However,
 
211
    position should be honored.
 
212
 
 
213
    \value RoundedNorth  The normal rounded look above the pages
 
214
 
 
215
    \value RoundedSouth  The normal rounded look below the pages
 
216
 
 
217
    \value RoundedWest  The normal rounded look on the left side of the pages
 
218
 
 
219
    \value RoundedEast  The normal rounded look on the right side the pages
 
220
 
 
221
    \value TriangularNorth  Triangular tabs above the pages.
 
222
 
 
223
    \value TriangularSouth  Triangular tabs similar to those used in
 
224
    the Excel spreadsheet, for example
 
225
 
 
226
    \value TriangularWest  Triangular tabs on the left of the pages.
 
227
 
 
228
    \value TriangularEast  Triangular tabs on the right of the pages.
 
229
    \omitvalue RoundedAbove
 
230
    \omitvalue RoundedBelow
 
231
    \omitvalue TriangularAbove
 
232
    \omitvalue TriangularBelow
 
233
*/
 
234
 
 
235
/*!
 
236
    \fn void QTabBar::currentChanged(int index)
 
237
 
 
238
    This signal is emitted when the tab bar's current tab changes. The
 
239
    new current has the given \a index.
 
240
*/
 
241
 
 
242
int QTabBarPrivate::extraWidth() const
 
243
{
 
244
    Q_Q(const QTabBar);
 
245
    return 2 * qMax(q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, q),
 
246
                    QApplication::globalStrut().width());
 
247
}
 
248
 
 
249
void QTabBarPrivate::init()
 
250
{
 
251
    Q_Q(QTabBar);
 
252
    leftB = new QToolButton(q);
 
253
    QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(scrollTabs()));
 
254
    leftB->hide();
 
255
    rightB = new QToolButton(q);
 
256
    QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(scrollTabs()));
 
257
    rightB->hide();
 
258
    q->setFocusPolicy(Qt::TabFocus);
 
259
    q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
260
}
 
261
 
 
262
QTabBarPrivate::Tab *QTabBarPrivate::at(int index)
 
263
{
 
264
    return validIndex(index)?&tabList[index]:0;
 
265
}
 
266
 
 
267
const QTabBarPrivate::Tab *QTabBarPrivate::at(int index) const
 
268
{
 
269
    return validIndex(index)?&tabList[index]:0;
 
270
}
 
271
 
 
272
int QTabBarPrivate::indexAtPos(const QPoint &p) const
 
273
{
 
274
    Q_Q(const QTabBar);
 
275
    if (q->tabRect(currentIndex).contains(p))
 
276
        return currentIndex;
 
277
    for (int i = 0; i < tabList.count(); ++i)
 
278
        if (tabList.at(i).enabled && q->tabRect(i).contains(p))
 
279
            return i;
 
280
    return -1;
 
281
}
 
282
 
 
283
inline static bool verticalTabs(QTabBar::Shape shape)
 
284
{
 
285
    return shape == QTabBar::RoundedWest
 
286
           || shape == QTabBar::RoundedEast
 
287
           || shape == QTabBar::TriangularWest
 
288
           || shape == QTabBar::TriangularEast;
 
289
}
 
290
 
 
291
 
 
292
void QTabBarPrivate::layoutTabs()
 
293
{
 
294
    Q_Q(QTabBar);
 
295
    scrollOffset = 0;
 
296
    layoutDirty = false;
 
297
    QSize size = q->size();
 
298
    int last, available;
 
299
    bool vertTabs = verticalTabs(shape);
 
300
    if (!vertTabs) {
 
301
        int x = 0;
 
302
        int maxHeight = 0;
 
303
        int i;
 
304
        for (i = 0; i < tabList.count(); ++i) {
 
305
            QSize sz = q->tabSizeHint(i);
 
306
            tabList[i].rect = QRect(x, 0, sz.width(), sz.height());
 
307
            maxHeight = qMax(maxHeight, sz.height());
 
308
            x += sz.width();
 
309
        }
 
310
 
 
311
        // Go through the list again and make sure we have a consistent height
 
312
        for (i = 0; i < tabList.count(); ++i)
 
313
            tabList[i].rect.setHeight(maxHeight);
 
314
 
 
315
        last = x;
 
316
        available = size.width();
 
317
    } else {
 
318
        int y = 0;
 
319
        int i;
 
320
        int maxWidth = 0;
 
321
        for (i = 0; i < tabList.count(); ++i) {
 
322
            QSize sz = q->tabSizeHint(i);
 
323
            tabList[i].rect = QRect(0, y, sz.width(), sz.height());
 
324
            maxWidth = qMax(0, sz.width());
 
325
            y += sz.height();
 
326
        }
 
327
 
 
328
        // Consistent width
 
329
        for (i = 0; i < tabList.count(); ++i)
 
330
            tabList[i].rect.setWidth(maxWidth);
 
331
 
 
332
        last = y;
 
333
        available = size.height();
 
334
    }
 
335
 
 
336
    if (tabList.count() && last > available) {
 
337
        int extra = extraWidth();
 
338
        if (!vertTabs) {
 
339
            Qt::LayoutDirection ld = q->layoutDirection();
 
340
            QRect arrows = QStyle::visualRect(ld, q->rect(),
 
341
                                              QRect(available - extra, 0, extra, size.height()));
 
342
            if (ld == Qt::LeftToRight) {
 
343
                leftB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
 
344
                rightB->setGeometry(arrows.right() - extra/2 + 1, arrows.top(),
 
345
                                    extra/2, arrows.height());
 
346
                leftB->setArrowType(Qt::LeftArrow);
 
347
                rightB->setArrowType(Qt::RightArrow);
 
348
            } else {
 
349
                rightB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
 
350
                leftB->setGeometry(arrows.right() - extra/2 + 1, arrows.top(),
 
351
                                    extra/2, arrows.height());
 
352
                rightB->setArrowType(Qt::LeftArrow);
 
353
                leftB->setArrowType(Qt::RightArrow);
 
354
            }
 
355
        } else {
 
356
            QRect arrows = QRect(0, available - extra, size.width(), extra );
 
357
            leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra/2);
 
358
            leftB->setArrowType(Qt::UpArrow);
 
359
            rightB->setGeometry(arrows.left(), arrows.bottom() - extra/2 + 1,
 
360
                                arrows.width(), extra/2);
 
361
            rightB->setArrowType(Qt::DownArrow);
 
362
        }
 
363
        leftB->setEnabled(scrollOffset > 0);
 
364
        rightB->setEnabled(last - scrollOffset >= available - extra);
 
365
        leftB->show();
 
366
        rightB->show();
 
367
    } else {
 
368
        rightB->hide();
 
369
        leftB->hide();
 
370
    }
 
371
 
 
372
    q->tabLayoutChange();
 
373
}
 
374
 
 
375
void QTabBarPrivate::makeVisible(int index)
 
376
{
 
377
    Q_Q(QTabBar);
 
378
    if (!validIndex(index) || leftB->isHidden())
 
379
        return;
 
380
    const QRect tabRect = tabList.at(index).rect;
 
381
 
 
382
    const int oldScrollOffset = scrollOffset;
 
383
    const bool horiz = !verticalTabs(shape);
 
384
    const int available = (horiz ? q->width() : q->height()) - extraWidth();
 
385
    const int start = horiz ? tabRect.left() : tabRect.top();
 
386
    const int end = horiz ? tabRect.right() : tabRect.bottom();
 
387
    if (start < scrollOffset) // too far left
 
388
        scrollOffset = start - (index?8:0);
 
389
    else if (end > scrollOffset + available) // too far right
 
390
        scrollOffset = end - available + 1;
 
391
 
 
392
    if (scrollOffset && end < available)  // need scrolling at all?
 
393
        scrollOffset = 0;
 
394
 
 
395
    leftB->setEnabled(scrollOffset > 0);
 
396
    const int last = horiz ? tabList.last().rect.right() : tabList.last().rect.bottom();
 
397
    rightB->setEnabled(last - scrollOffset >= available);
 
398
    if (oldScrollOffset != scrollOffset)
 
399
        q->update();
 
400
 
 
401
}
 
402
 
 
403
void QTabBarPrivate::scrollTabs()
 
404
{
 
405
    Q_Q(QTabBar);
 
406
    const QObject *sender = q->sender();
 
407
    int i = -1;
 
408
    if (!verticalTabs(shape)) {
 
409
        if (sender == leftB) {
 
410
            for (i = tabList.count() - 1; i >= 0; --i) {
 
411
                if (tabList.at(i).rect.left() - scrollOffset < 0) {
 
412
                    makeVisible(i);
 
413
                    return;
 
414
                }
 
415
            }
 
416
        } else if (sender == rightB) {
 
417
            int availableWidth = q->width() - extraWidth();
 
418
            for (i = 0; i < tabList.count(); ++i) {
 
419
                if (tabList.at(i).rect.right() - scrollOffset > availableWidth) {
 
420
                    makeVisible(i);
 
421
                    return;
 
422
                }
 
423
            }
 
424
        }
 
425
    } else { // vertical
 
426
        if (sender == leftB) {
 
427
            for (i = tabList.count() - 1; i >= 0; --i) {
 
428
                if (tabList.at(i).rect.top() - scrollOffset < 0) {
 
429
                    makeVisible(i);
 
430
                    return;
 
431
                }
 
432
            }
 
433
        } else if (sender == rightB) {
 
434
            int available = q->height() - extraWidth();
 
435
            for (i = 0; i < tabList.count(); ++i) {
 
436
                if (tabList.at(i).rect.bottom() - scrollOffset > available) {
 
437
                    makeVisible(i);
 
438
                    return;
 
439
                }
 
440
            }
 
441
        }
 
442
    }
 
443
}
 
444
 
 
445
void QTabBarPrivate::refresh()
 
446
{
 
447
    Q_Q(QTabBar);
 
448
    if (!q->isVisible()) {
 
449
        layoutDirty = true;
 
450
    } else {
 
451
        layoutTabs();
 
452
        q->update();
 
453
        q->updateGeometry();
 
454
    }
 
455
}
 
456
 
 
457
/*!
 
458
    Creates a new tab bar with the given \a parent.
 
459
*/
 
460
QTabBar::QTabBar(QWidget* parent)
 
461
    :QWidget(*new QTabBarPrivate, parent, 0)
 
462
{
 
463
    Q_D(QTabBar);
 
464
    d->init();
 
465
}
 
466
 
 
467
 
 
468
/*!
 
469
    Destroys the tab bar.
 
470
*/
 
471
QTabBar::~QTabBar()
 
472
{
 
473
}
 
474
 
 
475
/*!
 
476
    \property QTabBar::shape
 
477
    \brief the shape of the tabs in the tab bar
 
478
 
 
479
    The value of this property is one of the following: \c
 
480
    RoundedNorth (default), \c RoundedSouth, \c TriangularNorth or \c
 
481
    TriangularBelow.
 
482
 
 
483
    \sa Shape
 
484
*/
 
485
 
 
486
 
 
487
QTabBar::Shape QTabBar::shape() const
 
488
{
 
489
    Q_D(const QTabBar);
 
490
    return d->shape;
 
491
}
 
492
 
 
493
void QTabBar::setShape(Shape shape)
 
494
{
 
495
    Q_D(QTabBar);
 
496
    if (d->shape == shape)
 
497
        return;
 
498
    d->shape = shape;
 
499
    d->refresh();
 
500
}
 
501
 
 
502
 
 
503
/*!
 
504
    \property QTabBar::drawBase
 
505
    \brief defines whether or not tabbar should draw it's base.
 
506
 
 
507
    If true then QTabBar draws a base in relation to the styles overlab.
 
508
    Otherwise only the tabs are drawn.
 
509
 
 
510
    \sa QStyle::pixelMetric() QStyle::PM_TabBarBaseOverlap
 
511
*/
 
512
 
 
513
void QTabBar::setDrawBase(bool drawBase)
 
514
{
 
515
    Q_D(QTabBar);
 
516
    d->drawBase = drawBase;
 
517
}
 
518
 
 
519
bool QTabBar::drawBase() const
 
520
{
 
521
    Q_D(const QTabBar);
 
522
    return d->drawBase;
 
523
}
 
524
 
 
525
 
 
526
/*!
 
527
    Adds a new tab with text \a text. Returns the new
 
528
    tab's index.
 
529
*/
 
530
int QTabBar::addTab(const QString &text)
 
531
{
 
532
    return insertTab(-1, text);
 
533
}
 
534
 
 
535
/*!
 
536
    \overload
 
537
 
 
538
    Adds a new tab with icon \a icon and text \a
 
539
    text. Returns the new tab's index.
 
540
*/
 
541
int QTabBar::addTab(const QIcon& icon, const QString &text)
 
542
{
 
543
    return insertTab(-1, icon, text);
 
544
}
 
545
 
 
546
/*!
 
547
    Inserts a new tab with text \a text at position \a index. If \a
 
548
    index is out of range, the new tab is appened. Returns the new
 
549
    tab's index.
 
550
*/
 
551
int QTabBar::insertTab(int index, const QString &text)
 
552
{
 
553
    return insertTab(index, QIcon(), text);
 
554
}
 
555
 
 
556
/*!\overload
 
557
 
 
558
    Inserts a new tab with icon \a icon and text \a text at position
 
559
    \a index. If \a index is out of range, the new tab is
 
560
    appended. Returns the new tab's index.
 
561
*/
 
562
int QTabBar::insertTab(int index, const QIcon& icon, const QString &text)
 
563
{
 
564
    Q_D(QTabBar);
 
565
    if (!d->validIndex(index)) {
 
566
        index = d->tabList.count();
 
567
        d->tabList.append(QTabBarPrivate::Tab(icon, text));
 
568
    } else {
 
569
        d->tabList.insert(index, QTabBarPrivate::Tab(icon, text));
 
570
    }
 
571
    d->tabList[index].shortcutId = grabShortcut(QKeySequence::mnemonic(text));
 
572
    d->refresh();
 
573
    tabInserted(index);
 
574
    return index;
 
575
}
 
576
 
 
577
 
 
578
/*!
 
579
    Removes the tab at position \a index.
 
580
 */
 
581
void QTabBar::removeTab(int index)
 
582
{
 
583
    Q_D(QTabBar);
 
584
    if (d->validIndex(index)) {
 
585
        releaseShortcut(d->tabList.at(index).shortcutId);
 
586
        d->tabList.removeAt(index);
 
587
        if (index == d->currentIndex)
 
588
            setCurrentIndex(d->validIndex(index+1)?index+1:0);
 
589
        d->refresh();
 
590
        tabRemoved(index);
 
591
    }
 
592
}
 
593
 
 
594
 
 
595
/*!
 
596
    Returns true if the tab at position \a index is enabled; otherwise
 
597
    returns false.
 
598
*/
 
599
bool QTabBar::isTabEnabled(int index) const
 
600
{
 
601
    Q_D(const QTabBar);
 
602
    if (const QTabBarPrivate::Tab *tab = d->at(index))
 
603
        return tab->enabled;
 
604
    return false;
 
605
}
 
606
 
 
607
/*!
 
608
    If \a enabled is true then the tab at position \a index is
 
609
    enabled; otherwise the item at position \a index is disabled.
 
610
*/
 
611
void QTabBar::setTabEnabled(int index, bool enabled)
 
612
{
 
613
    Q_D(QTabBar);
 
614
    if (QTabBarPrivate::Tab *tab = d->at(index)) {
 
615
        tab->enabled = enabled;
 
616
        update();
 
617
        if (!enabled && index == d->currentIndex)
 
618
            setCurrentIndex(d->validIndex(index+1)?index+1:0);
 
619
        else if (enabled && !d->validIndex(d->currentIndex))
 
620
            setCurrentIndex(index);
 
621
    }
 
622
}
 
623
 
 
624
 
 
625
/*!
 
626
    Returns the text of the tab at position \a index, or an empty
 
627
    string if \a index is out of range.
 
628
*/
 
629
QString QTabBar::tabText(int index) const
 
630
{
 
631
    Q_D(const QTabBar);
 
632
    if (const QTabBarPrivate::Tab *tab = d->at(index))
 
633
        return tab->text;
 
634
    return QString();
 
635
}
 
636
 
 
637
/*!
 
638
    Sets the text of the tab at position \a index to \a text.
 
639
*/
 
640
void QTabBar::setTabText(int index, const QString &text)
 
641
{
 
642
    Q_D(QTabBar);
 
643
    if (QTabBarPrivate::Tab *tab = d->at(index)) {
 
644
        tab->text = text;
 
645
        releaseShortcut(tab->shortcutId);
 
646
        tab->shortcutId = grabShortcut(QKeySequence::mnemonic(text));
 
647
        d->refresh();
 
648
    }
 
649
}
 
650
 
 
651
 
 
652
/*!
 
653
    Returns the icon of the tab at position \a index, or a null icon
 
654
    if \a index is out of range.
 
655
*/
 
656
QIcon QTabBar::tabIcon(int index) const
 
657
{
 
658
    Q_D(const QTabBar);
 
659
    if (const QTabBarPrivate::Tab *tab = d->at(index))
 
660
        return tab->icon;
 
661
    return QIcon();
 
662
}
 
663
 
 
664
/*!
 
665
    Sets the icon of the tab at position \a index to \a icon.
 
666
*/
 
667
void QTabBar::setTabIcon(int index, const QIcon & icon)
 
668
{
 
669
    Q_D(QTabBar);
 
670
    if (QTabBarPrivate::Tab *tab = d->at(index)) {
 
671
        tab->icon = icon;
 
672
        d->refresh();
 
673
    }
 
674
}
 
675
 
 
676
 
 
677
/*!
 
678
    Sets the tool tip of the tab at position \a index to \a tip.
 
679
*/
 
680
void QTabBar::setTabToolTip(int index, const QString & tip)
 
681
{
 
682
    Q_D(QTabBar);
 
683
    if (QTabBarPrivate::Tab *tab = d->at(index))
 
684
        tab->toolTip = tip;
 
685
}
 
686
 
 
687
/*!
 
688
    Returns the tool tip of the tab at position \a index, or an empty
 
689
    string if \a index is out of range.
 
690
*/
 
691
QString QTabBar::tabToolTip(int index) const
 
692
{
 
693
    Q_D(const QTabBar);
 
694
    if (const QTabBarPrivate::Tab *tab = d->at(index))
 
695
        return tab->toolTip;
 
696
    return QString();
 
697
}
 
698
 
 
699
/*!
 
700
    Sets the data of the tab at position \a index to \a data.
 
701
*/
 
702
void QTabBar::setTabData(int index, const QVariant & data)
 
703
{
 
704
    Q_D(QTabBar);
 
705
    if (QTabBarPrivate::Tab *tab = d->at(index))
 
706
        tab->data = data;
 
707
}
 
708
 
 
709
/*!
 
710
    Returns the datad of the tab at position \a index, or a null
 
711
    variant if \a index is out of range.
 
712
*/
 
713
QVariant QTabBar::tabData(int index) const
 
714
{
 
715
    Q_D(const QTabBar);
 
716
    if (const QTabBarPrivate::Tab *tab = d->at(index))
 
717
        return tab->data;
 
718
    return QVariant();
 
719
}
 
720
 
 
721
/*!
 
722
    Returns the visual rectangle of the of the tab at position \a
 
723
    index, or a null rectangle if \a index is out of range.
 
724
*/
 
725
QRect QTabBar::tabRect(int index) const
 
726
{
 
727
    Q_D(const QTabBar);
 
728
    if (const QTabBarPrivate::Tab *tab = d->at(index)) {
 
729
        if (d->layoutDirty)
 
730
            const_cast<QTabBarPrivate*>(d)->layoutTabs();
 
731
        QRect r = tab->rect;
 
732
        if (verticalTabs(d->shape))
 
733
            r.translate(0, -d->scrollOffset);
 
734
        else
 
735
            r.translate(-d->scrollOffset, 0);
 
736
        return QStyle::visualRect(layoutDirection(), rect(), r);
 
737
    }
 
738
    return QRect();
 
739
}
 
740
 
 
741
/*!
 
742
    \property QTabBar::currentIndex
 
743
    \brief the index of the tab bar's visible tab
 
744
*/
 
745
 
 
746
int QTabBar::currentIndex() const
 
747
{
 
748
    Q_D(const QTabBar);
 
749
    if (d->validIndex(d->currentIndex))
 
750
        return d->currentIndex;
 
751
    return -1;
 
752
}
 
753
 
 
754
 
 
755
void QTabBar::setCurrentIndex(int index)
 
756
{
 
757
    Q_D(QTabBar);
 
758
    if (d->validIndex(index)) {
 
759
        d->currentIndex = index;
 
760
        update();
 
761
        d->makeVisible(index);
 
762
#ifdef QT3_SUPPORT
 
763
        emit selected(index);
 
764
#endif
 
765
        emit currentChanged(index);
 
766
    }
 
767
}
 
768
 
 
769
 
 
770
/*!
 
771
    \property QTabBar::count
 
772
    \brief the number of tabs in the tab bar
 
773
*/
 
774
 
 
775
int QTabBar::count() const
 
776
{
 
777
    Q_D(const QTabBar);
 
778
    return d->tabList.count();
 
779
}
 
780
 
 
781
 
 
782
/*!\reimp
 
783
 */
 
784
QSize QTabBar::sizeHint() const
 
785
{
 
786
    Q_D(const QTabBar);
 
787
    if (d->layoutDirty)
 
788
        const_cast<QTabBarPrivate*>(d)->layoutTabs();
 
789
    QRect r;
 
790
    for (int i = 0; i < d->tabList.count(); ++i)
 
791
        r = r.unite(d->tabList.at(i).rect);
 
792
    QSize sz = QApplication::globalStrut();
 
793
    return r.size().expandedTo(sz);
 
794
}
 
795
 
 
796
/*!\reimp
 
797
 */
 
798
QSize QTabBar::minimumSizeHint() const
 
799
{
 
800
    Q_D(const QTabBar);
 
801
    if (style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, this))
 
802
        return sizeHint();
 
803
    if (verticalTabs(d->shape))
 
804
        return QSize(sizeHint().width(), d->rightB->sizeHint().height() * 2 + 75);
 
805
    else
 
806
        return QSize(d->rightB->sizeHint().width() * 2 + 75, sizeHint().height());
 
807
}
 
808
 
 
809
/*!
 
810
    Returns the size hint for the tab at position \a index.
 
811
*/
 
812
QSize QTabBar::tabSizeHint(int index) const
 
813
{
 
814
    Q_D(const QTabBar);
 
815
    if (const QTabBarPrivate::Tab *tab = d->at(index)) {
 
816
        QStyleOptionTab opt = d->getStyleOption(index);
 
817
        int iconExtent = style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, this);
 
818
        QSize iconSize = tab->icon.isNull() ? QSize() : QSize(iconExtent, iconExtent);
 
819
        int hframe  = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this);
 
820
        int vframe  = style()->pixelMetric(QStyle::PM_TabBarTabVSpace, &opt, this);
 
821
        const QFontMetrics fm = fontMetrics();
 
822
        QSize csz(fm.size(Qt::TextShowMnemonic, tab->text).width() + iconSize.width() + hframe,
 
823
                  qMax(fm.height(), iconSize.height()) + vframe);
 
824
        if (verticalTabs(d->shape))
 
825
            csz.transpose();
 
826
 
 
827
        return style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, csz, this);
 
828
    }
 
829
    return QSize();
 
830
}
 
831
 
 
832
/*!
 
833
  This virtual handler is called after a new tab was added or
 
834
  inserted at position \a index.
 
835
 
 
836
  \sa tabRemoved()
 
837
 */
 
838
void QTabBar::tabInserted(int index)
 
839
{
 
840
    Q_UNUSED(index)
 
841
}
 
842
 
 
843
/*!
 
844
  This virtual handler is called after a tab was removed from
 
845
  position \a index.
 
846
 
 
847
  \sa tabInserted()
 
848
 */
 
849
void QTabBar::tabRemoved(int index)
 
850
{
 
851
    Q_UNUSED(index)
 
852
}
 
853
 
 
854
/*!
 
855
  This virtual handler is called whenever the tab layout changes.
 
856
 
 
857
  \sa tabRect()
 
858
 */
 
859
void QTabBar::tabLayoutChange()
 
860
{
 
861
}
 
862
 
 
863
 
 
864
/*!\reimp
 
865
 */
 
866
void QTabBar::showEvent(QShowEvent *)
 
867
{
 
868
    Q_D(QTabBar);
 
869
    if (d->layoutDirty)
 
870
        d->layoutTabs();
 
871
    if (!d->validIndex(d->currentIndex))
 
872
        setCurrentIndex(0);
 
873
 
 
874
}
 
875
 
 
876
 
 
877
/*!\reimp
 
878
 */
 
879
bool QTabBar::event(QEvent *e)
 
880
{
 
881
    Q_D(QTabBar);
 
882
    if (e->type() == QEvent::HoverMove
 
883
        || e->type() == QEvent::HoverEnter) {
 
884
        QHoverEvent *he = static_cast<QHoverEvent *>(e);
 
885
        if (!d->hoverRect.contains(he->pos())) {
 
886
            QRect oldHoverRect = d->hoverRect;
 
887
            for (int i = 0; i < d->tabList.count(); ++i) {
 
888
                QRect area = tabRect(i);
 
889
                if (area.contains(he->pos())) {
 
890
                    d->hoverRect = area;
 
891
                    break;
 
892
                }
 
893
            }
 
894
            if (he->oldPos() != QPoint(-1, -1))
 
895
                update(oldHoverRect);
 
896
            update(d->hoverRect);
 
897
        }
 
898
    } else if (e->type() == QEvent::HoverLeave ) {
 
899
        QRect oldHoverRect = d->hoverRect;
 
900
        d->hoverRect = QRect();
 
901
        update(oldHoverRect);
 
902
    } else if (e->type() == QEvent::ToolTip) {
 
903
        if (const QTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast<QHelpEvent*>(e)->pos()))) {
 
904
            if (!tab->toolTip.isEmpty()) {
 
905
                QToolTip::showText(static_cast<QHelpEvent*>(e)->globalPos(), tab->toolTip, this);
 
906
                return true;
 
907
            }
 
908
        }
 
909
    } else if (e->type() == QEvent::Shortcut) {
 
910
        QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
 
911
        for (int i = 0; i < d->tabList.count(); ++i) {
 
912
            const QTabBarPrivate::Tab *tab = &d->tabList.at(i);
 
913
            if (tab->shortcutId == se->shortcutId()) {
 
914
                setCurrentIndex(i);
 
915
                return true;
 
916
            }
 
917
        }
 
918
    }
 
919
    return QWidget::event(e);
 
920
}
 
921
 
 
922
/*!\reimp
 
923
 */
 
924
void QTabBar::resizeEvent(QResizeEvent *)
 
925
{
 
926
    Q_D(QTabBar);
 
927
    d->layoutTabs();
 
928
    d->makeVisible(d->currentIndex);
 
929
}
 
930
 
 
931
/*!\reimp
 
932
 */
 
933
void QTabBar::paintEvent(QPaintEvent *)
 
934
{
 
935
    Q_D(QTabBar);
 
936
    QStyleOptionTab tabOverlap;
 
937
    tabOverlap.shape = d->shape;
 
938
    int overlap = style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, this);
 
939
    QWidget *theParent = parentWidget();
 
940
    QStyleOptionTabBarBase optTabBase;
 
941
    optTabBase.init(this);
 
942
    optTabBase.shape = d->shape;
 
943
    if (theParent && overlap > 0) {
 
944
        QPainter::setRedirected(theParent, this, pos());
 
945
        QRect rect;
 
946
        switch (tabOverlap.shape) {
 
947
        case QTabBar::RoundedNorth:
 
948
        case QTabBar::TriangularNorth:
 
949
            rect.setRect(0, height()-overlap, width(), overlap);
 
950
            break;
 
951
        case QTabBar::RoundedSouth:
 
952
        case QTabBar::TriangularSouth:
 
953
            rect.setRect(0, 0, width(), overlap);
 
954
            break;
 
955
        case QTabBar::RoundedEast:
 
956
        case QTabBar::TriangularEast:
 
957
            rect.setRect(0, 0, overlap, height());
 
958
            break;
 
959
        case QTabBar::RoundedWest:
 
960
        case QTabBar::TriangularWest:
 
961
            rect.setRect(width()-overlap, 0, overlap, height());
 
962
            break;
 
963
        }
 
964
        optTabBase.rect = rect;
 
965
        QPaintEvent e(rect);
 
966
        QApplication::sendEvent(theParent, &e);
 
967
        QPainter::restoreRedirected(theParent);
 
968
    }
 
969
    QStylePainter p(this);
 
970
    int selected = -1;
 
971
    int cut = -1;
 
972
    bool rtl = optTabBase.direction == Qt::RightToLeft;
 
973
    bool verticalTabs = (d->shape == QTabBar::RoundedWest || d->shape == QTabBar::RoundedEast
 
974
                         || d->shape == QTabBar::TriangularWest
 
975
                         || d->shape == QTabBar::TriangularEast);
 
976
    QStyleOptionTab cutTab;
 
977
    QStyleOptionTab selectedTab;
 
978
    for (int i = 0; i < d->tabList.count(); ++i) {
 
979
        QStyleOptionTab tab = d->getStyleOption(i);
 
980
        // If this tab is partially obscured, make a note of it so that we can pass the information
 
981
        // along when we draw the tear.
 
982
        if ((!verticalTabs && (!rtl && tab.rect.left() < 0) || (rtl && tab.rect.right() > width()))
 
983
            || (verticalTabs && tab.rect.top() < 0)) {
 
984
            cut = i;
 
985
            cutTab = tab;
 
986
        }
 
987
        // Don't bother drawing a tab if the entire tab is outside of the visible tab bar.
 
988
        if ((!verticalTabs && (tab.rect.right() < 0 || tab.rect.left() > width()))
 
989
            || (verticalTabs && (tab.rect.bottom() < 0 || tab.rect.top() > height())))
 
990
            continue;
 
991
 
 
992
        optTabBase.tabBarRect |= tab.rect;
 
993
        if (i == d->currentIndex) {
 
994
            selected = i;
 
995
            selectedTab = tab;
 
996
            optTabBase.selectedTabRect = tab.rect;
 
997
            continue;
 
998
        }
 
999
        p.drawControl(QStyle::CE_TabBarTab, tab);
 
1000
    }
 
1001
 
 
1002
    // Draw the selected tab last to get it "on top"
 
1003
    if (selected >= 0) {
 
1004
        QStyleOptionTab tab = d->getStyleOption(selected);
 
1005
        p.drawControl(QStyle::CE_TabBarTab, tab);
 
1006
    }
 
1007
    if (d->drawBase)
 
1008
        p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
 
1009
 
 
1010
    // Only draw the tear indicator if necessary. Most of the time we don't need too.
 
1011
    if (d->leftB->isVisible() && cut >= 0) {
 
1012
        cutTab.rect = rect();
 
1013
        cutTab.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicator, &cutTab, this);
 
1014
        p.drawPrimitive(QStyle::PE_IndicatorTabTear, cutTab);
 
1015
    }
 
1016
}
 
1017
 
 
1018
/*!\reimp
 
1019
 */
 
1020
void QTabBar::mousePressEvent (QMouseEvent *e)
 
1021
{
 
1022
    Q_D(QTabBar);
 
1023
    if (e->button() != Qt::LeftButton) {
 
1024
        e->ignore();
 
1025
        return;
 
1026
    }
 
1027
    d->pressedIndex = d->indexAtPos(e->pos());
 
1028
    if (d->pressedIndex >= 0) {
 
1029
        if (e->type() == style()->styleHint(QStyle::SH_TabBar_SelectMouseType, 0, this))
 
1030
            setCurrentIndex(d->pressedIndex);
 
1031
        else
 
1032
            repaint(tabRect(d->pressedIndex));
 
1033
    }
 
1034
}
 
1035
 
 
1036
/*!\reimp
 
1037
 */
 
1038
void QTabBar::mouseMoveEvent (QMouseEvent *e)
 
1039
{
 
1040
    Q_D(QTabBar);
 
1041
    if (e->buttons() != Qt::LeftButton) {
 
1042
        e->ignore();
 
1043
        return;
 
1044
    }
 
1045
    if (style()->styleHint(QStyle::SH_TabBar_SelectMouseType, 0, this)
 
1046
            == QEvent::MouseButtonRelease) {
 
1047
        int i = d->indexAtPos(e->pos());
 
1048
        if (i != d->pressedIndex) {
 
1049
            int oldIndex = d->pressedIndex;
 
1050
            d->pressedIndex = -1;
 
1051
            if (oldIndex >= 0)
 
1052
                repaint(tabRect(oldIndex));
 
1053
            if ((d->pressedIndex = i) >= 0)
 
1054
                repaint(tabRect(i));
 
1055
        }
 
1056
    }
 
1057
}
 
1058
 
 
1059
/*!\reimp
 
1060
 */
 
1061
void QTabBar::mouseReleaseEvent (QMouseEvent *e)
 
1062
{
 
1063
    Q_D(QTabBar);
 
1064
    if (e->button() != Qt::LeftButton)
 
1065
        e->ignore();
 
1066
 
 
1067
    int i = d->indexAtPos(e->pos()) == d->pressedIndex ? d->pressedIndex : -1;
 
1068
    d->pressedIndex = -1;
 
1069
    if (e->type() == style()->styleHint(QStyle::SH_TabBar_SelectMouseType, 0, this))
 
1070
        setCurrentIndex(i);
 
1071
}
 
1072
 
 
1073
/*!\reimp
 
1074
 */
 
1075
void QTabBar::keyPressEvent(QKeyEvent *e)
 
1076
{
 
1077
    Q_D(QTabBar);
 
1078
    if (e->key() != Qt::Key_Left && e->key() != Qt::Key_Right) {
 
1079
        e->ignore();
 
1080
        return;
 
1081
    }
 
1082
    int dx = e->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1;
 
1083
    for (int index = d->currentIndex + dx; d->validIndex(index); index += dx) {
 
1084
        if (d->tabList.at(index).enabled) {
 
1085
            setCurrentIndex(index);
 
1086
            break;
 
1087
        }
 
1088
    }
 
1089
}
 
1090
 
 
1091
/*!\reimp
 
1092
 */
 
1093
void QTabBar::changeEvent(QEvent *e)
 
1094
{
 
1095
    Q_D(QTabBar);
 
1096
    d->refresh();
 
1097
    QWidget::changeEvent(e);
 
1098
}
 
1099
 
 
1100
 
 
1101
/*!
 
1102
    \fn void QTabBar::setCurrentTab(int index)
 
1103
 
 
1104
    Use setCurrentIndex() instead.
 
1105
*/
 
1106
 
 
1107
/*!
 
1108
    \fn void QTabBar::selected(int index);
 
1109
 
 
1110
    Use currentChanged() instead.
 
1111
*/
 
1112
 
 
1113
 
 
1114
#include "moc_qtabbar.cpp"
 
1115