Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / gui / widgets / qtabbar.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qlayoutengine_p.h"
43 #include "qabstractitemdelegate.h"
44 #include "qapplication.h"
45 #include "qbitmap.h"
46 #include "qcursor.h"
47 #include "qevent.h"
48 #include "qpainter.h"
49 #include "qstyle.h"
50 #include "qstyleoption.h"
51 #include "qstylepainter.h"
52 #include "qtabwidget.h"
53 #include "qtooltip.h"
54 #include "qwhatsthis.h"
55 #include "private/qtextengine_p.h"
56 #ifndef QT_NO_ACCESSIBILITY
57 #include "qaccessible.h"
58 #endif
59
60 #include "qdebug.h"
61 #include "private/qtabbar_p.h"
62
63 #ifndef QT_NO_TABBAR
64
65 #ifdef Q_WS_MAC
66 #include <private/qt_mac_p.h>
67 #include <private/qt_cocoa_helpers_mac_p.h>
68 #endif
69
70 #ifndef QT_NO_STYLE_S60
71 #include "qs60style.h"
72 #endif
73
74 QT_BEGIN_NAMESPACE
75
76
77 inline static bool verticalTabs(QTabBar::Shape shape)
78 {
79     return shape == QTabBar::RoundedWest
80            || shape == QTabBar::RoundedEast
81            || shape == QTabBar::TriangularWest
82            || shape == QTabBar::TriangularEast;
83 }
84
85 void QTabBarPrivate::updateMacBorderMetrics()
86 {
87 #if (defined Q_WS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
88     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
89         Q_Q(QTabBar);
90         ::HIContentBorderMetrics metrics;
91
92         // TODO: get metrics to preserve the bottom value
93         // TODO: test tab bar position
94
95         OSWindowRef window = qt_mac_window_for(q);
96
97         // push base line separator down to the client are so we can paint over it (Carbon)
98         metrics.top = (documentMode && q->isVisible()) ? 1 : 0;
99         metrics.bottom = 0;
100         metrics.left = 0;
101         metrics.right = 0;
102         qt_mac_updateContentBorderMetricts(window, metrics);
103 #if QT_MAC_USE_COCOA
104         // In Cocoa we need to keep track of the drawRect method.
105         // If documentMode is enabled we need to change it, unless
106         // a toolbar is present.
107         // Notice that all the information is kept in the window,
108         // that's why we get the private widget for it instead of
109         // the private widget for this widget.
110         QWidgetPrivate *privateWidget = qt_widget_private(q->window());
111         if(privateWidget)
112             privateWidget->changeMethods = documentMode;
113         // Since in Cocoa there is no simple way to remove the baseline, so we just ask the
114         // top level to do the magic for us.
115         privateWidget->syncUnifiedMode();
116 #endif // QT_MAC_USE_COCOA
117     }
118 #endif
119 }
120
121 /*!
122     Initialize \a option with the values from the tab at \a tabIndex. This method
123     is useful for subclasses when they need a QStyleOptionTab, QStyleOptionTabV2,
124     or QStyleOptionTabV3 but don't want to fill in all the information themselves.
125     This function will check the version of the QStyleOptionTab and fill in the
126     additional values for a QStyleOptionTabV2 and QStyleOptionTabV3.
127
128     \sa QStyleOption::initFrom() QTabWidget::initStyleOption()
129 */
130 void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const
131 {
132     Q_D(const QTabBar);
133     int totalTabs = d->tabList.size();
134
135     if (!option || (tabIndex < 0 || tabIndex >= totalTabs))
136         return;
137
138     const QTabBarPrivate::Tab &tab = d->tabList.at(tabIndex);
139     option->initFrom(this);
140     option->state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
141     option->rect = tabRect(tabIndex);
142     bool isCurrent = tabIndex == d->currentIndex;
143     option->row = 0;
144     if (tabIndex == d->pressedIndex)
145         option->state |= QStyle::State_Sunken;
146     if (isCurrent)
147         option->state |= QStyle::State_Selected;
148     if (isCurrent && hasFocus())
149         option->state |= QStyle::State_HasFocus;
150     if (!tab.enabled)
151         option->state &= ~QStyle::State_Enabled;
152     if (isActiveWindow())
153         option->state |= QStyle::State_Active;
154     if (!d->dragInProgress && option->rect == d->hoverRect)
155         option->state |= QStyle::State_MouseOver;
156     option->shape = d->shape;
157     option->text = tab.text;
158
159     if (tab.textColor.isValid())
160         option->palette.setColor(foregroundRole(), tab.textColor);
161
162     option->icon = tab.icon;
163     if (QStyleOptionTabV2 *optionV2 = qstyleoption_cast<QStyleOptionTabV2 *>(option))
164         optionV2->iconSize = iconSize();  // Will get the default value then.
165
166     if (QStyleOptionTabV3 *optionV3 = qstyleoption_cast<QStyleOptionTabV3 *>(option)) {
167         optionV3->leftButtonSize = tab.leftWidget ? tab.leftWidget->size() : QSize();
168         optionV3->rightButtonSize = tab.rightWidget ? tab.rightWidget->size() : QSize();
169         optionV3->documentMode = d->documentMode;
170     }
171
172     if (tabIndex > 0 && tabIndex - 1 == d->currentIndex)
173         option->selectedPosition = QStyleOptionTab::PreviousIsSelected;
174     else if (tabIndex + 1 < totalTabs && tabIndex + 1 == d->currentIndex)
175         option->selectedPosition = QStyleOptionTab::NextIsSelected;
176     else
177         option->selectedPosition = QStyleOptionTab::NotAdjacent;
178
179     bool paintBeginning = (tabIndex == 0) || (d->dragInProgress && tabIndex == d->pressedIndex + 1);
180     bool paintEnd = (tabIndex == totalTabs - 1) || (d->dragInProgress && tabIndex == d->pressedIndex - 1);
181     if (paintBeginning) {
182         if (paintEnd)
183             option->position = QStyleOptionTab::OnlyOneTab;
184         else
185             option->position = QStyleOptionTab::Beginning;
186     } else if (paintEnd) {
187         option->position = QStyleOptionTab::End;
188     } else {
189         option->position = QStyleOptionTab::Middle;
190     }
191
192 #ifndef QT_NO_TABWIDGET
193     if (const QTabWidget *tw = qobject_cast<const QTabWidget *>(parentWidget())) {
194         if (tw->cornerWidget(Qt::TopLeftCorner) || tw->cornerWidget(Qt::BottomLeftCorner))
195             option->cornerWidgets |= QStyleOptionTab::LeftCornerWidget;
196         if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner))
197             option->cornerWidgets |= QStyleOptionTab::RightCornerWidget;
198     }
199 #endif
200
201     QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option, this);
202     option->text = fontMetrics().elidedText(option->text, d->elideMode, textRect.width(),
203                         Qt::TextShowMnemonic);
204 }
205
206 /*!
207     \class QTabBar
208     \brief The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
209
210     \ingroup basicwidgets
211
212
213     QTabBar is straightforward to use; it draws the tabs using one of
214     the predefined \link QTabBar::Shape shapes\endlink, and emits a
215     signal when a tab is selected. It can be subclassed to tailor the
216     look and feel. Qt also provides a ready-made \l{QTabWidget}.
217
218     Each tab has a tabText(), an optional tabIcon(), an optional
219     tabToolTip(), optional tabWhatsThis() and optional tabData().
220     The tabs's attributes can be changed with setTabText(), setTabIcon(),
221     setTabToolTip(), setTabWhatsThis and setTabData(). Each tabs can be
222     enabled or disabled individually with setTabEnabled().
223
224     Each tab can display text in a distinct color. The current text color
225     for a tab can be found with the tabTextColor() function. Set the text
226     color for a particular tab with setTabTextColor().
227
228     Tabs are added using addTab(), or inserted at particular positions
229     using insertTab(). The total number of tabs is given by
230     count(). Tabs can be removed from the tab bar with
231     removeTab(). Combining removeTab() and insertTab() allows you to
232     move tabs to different positions.
233
234     The \l shape property defines the tabs' appearance. The choice of
235     shape is a matter of taste, although tab dialogs (for preferences
236     and similar) invariably use \l RoundedNorth.
237     Tab controls in windows other than dialogs almost
238     always use either \l RoundedSouth or \l TriangularSouth. Many
239     spreadsheets and other tab controls in which all the pages are
240     essentially similar use \l TriangularSouth, whereas \l
241     RoundedSouth is used mostly when the pages are different (e.g. a
242     multi-page tool palette). The default in QTabBar is \l
243     RoundedNorth.
244
245     The most important part of QTabBar's API is the currentChanged()
246     signal.  This is emitted whenever the current tab changes (even at
247     startup, when the current tab changes from 'none'). There is also
248     a slot, setCurrentIndex(), which can be used to select a tab
249     programmatically. The function currentIndex() returns the index of
250     the current tab, \l count holds the number of tabs.
251
252     QTabBar creates automatic mnemonic keys in the manner of QAbstractButton;
253     e.g. if a tab's label is "\&Graphics", Alt+G becomes a shortcut
254     key for switching to that tab.
255
256     The following virtual functions may need to be reimplemented in
257     order to tailor the look and feel or store extra data with each
258     tab:
259
260     \list
261     \i tabSizeHint() calcuates the size of a tab.
262     \i tabInserted() notifies that a new tab was added.
263     \i tabRemoved() notifies that a tab was removed.
264     \i tabLayoutChange() notifies that the tabs have been re-laid out.
265     \i paintEvent() paints all tabs.
266     \endlist
267
268     For subclasses, you might also need the tabRect() functions which
269     returns the visual geometry of a single tab.
270
271     \table 100%
272     \row \o \inlineimage plastique-tabbar.png Screenshot of a Plastique style tab bar
273          \o A tab bar shown in the Plastique widget style.
274     \row \o \inlineimage plastique-tabbar-truncated.png Screenshot of a truncated Plastique tab bar
275          \o A truncated tab bar shown in the Plastique widget style.
276     \endtable
277
278     \sa QTabWidget
279 */
280
281 /*!
282     \enum QTabBar::Shape
283
284     This enum type lists the built-in shapes supported by QTabBar. Treat these
285     as hints as some styles may not render some of the shapes. However,
286     position should be honored.
287
288     \value RoundedNorth  The normal rounded look above the pages
289
290     \value RoundedSouth  The normal rounded look below the pages
291
292     \value RoundedWest  The normal rounded look on the left side of the pages
293
294     \value RoundedEast  The normal rounded look on the right side the pages
295
296     \value TriangularNorth  Triangular tabs above the pages.
297
298     \value TriangularSouth  Triangular tabs similar to those used in
299     the Excel spreadsheet, for example
300
301     \value TriangularWest  Triangular tabs on the left of the pages.
302
303     \value TriangularEast  Triangular tabs on the right of the pages.
304     \omitvalue RoundedAbove
305     \omitvalue RoundedBelow
306     \omitvalue TriangularAbove
307     \omitvalue TriangularBelow
308 */
309
310 /*!
311     \fn void QTabBar::currentChanged(int index)
312
313     This signal is emitted when the tab bar's current tab changes. The
314     new current has the given \a index, or -1 if there isn't a new one
315     (for example, if there are no tab in the QTabBar)
316 */
317
318 /*!
319     \fn void QTabBar::tabCloseRequested(int index)
320     \since 4.5
321
322     This signal is emitted when the close button on a tab is clicked.
323     The \a index is the index that should be removed.
324
325     \sa setTabsClosable()
326 */
327
328 /*!
329     \fn void QTabBar::tabMoved(int from, int to)
330     \since 4.5
331
332     This signal is emitted when the tab has moved the tab
333     at index position \a from to index position \a to.
334
335     note: QTabWidget will automatically move the page when
336     this signal is emitted from its tab bar.
337
338     \sa moveTab()
339 */
340
341 int QTabBarPrivate::extraWidth() const
342 {
343     Q_Q(const QTabBar);
344     return 2 * qMax(q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, q),
345                     QApplication::globalStrut().width());
346 }
347
348 void QTabBarPrivate::init()
349 {
350     Q_Q(QTabBar);
351     leftB = new QToolButton(q);
352     leftB->setAutoRepeat(true);
353     QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
354     leftB->hide();
355     rightB = new QToolButton(q);
356     rightB->setAutoRepeat(true);
357     QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
358     rightB->hide();
359 #ifdef QT_KEYPAD_NAVIGATION
360     if (QApplication::keypadNavigationEnabled()) {
361         leftB->setFocusPolicy(Qt::NoFocus);
362         rightB->setFocusPolicy(Qt::NoFocus);
363         q->setFocusPolicy(Qt::NoFocus);
364     } else
365 #endif
366     q->setFocusPolicy(Qt::TabFocus);
367     q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
368     elideMode = Qt::TextElideMode(q->style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, q));
369     useScrollButtons = !q->style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, q);
370 }
371
372 QTabBarPrivate::Tab *QTabBarPrivate::at(int index)
373 {
374     return validIndex(index)?&tabList[index]:0;
375 }
376
377 const QTabBarPrivate::Tab *QTabBarPrivate::at(int index) const
378 {
379     return validIndex(index)?&tabList[index]:0;
380 }
381
382 int QTabBarPrivate::indexAtPos(const QPoint &p) const
383 {
384     Q_Q(const QTabBar);
385     if (q->tabRect(currentIndex).contains(p))
386         return currentIndex;
387     for (int i = 0; i < tabList.count(); ++i)
388         if (tabList.at(i).enabled && q->tabRect(i).contains(p))
389             return i;
390     return -1;
391 }
392
393 void QTabBarPrivate::layoutTabs()
394 {
395     Q_Q(QTabBar);
396     scrollOffset = 0;
397     layoutDirty = false;
398     QSize size = q->size();
399     int last, available;
400     int maxExtent;
401     int i;
402     bool vertTabs = verticalTabs(shape);
403     int tabChainIndex = 0;
404
405     Qt::Alignment tabAlignment = Qt::Alignment(q->style()->styleHint(QStyle::SH_TabBar_Alignment, 0, q));
406     QVector<QLayoutStruct> tabChain(tabList.count() + 2);
407
408     // We put an empty item at the front and back and set its expansive attribute
409     // depending on tabAlignment.
410     tabChain[tabChainIndex].init();
411     tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignLeft)
412                                         && (tabAlignment != Qt::AlignJustify);
413     tabChain[tabChainIndex].empty = true;
414     ++tabChainIndex;
415
416     // We now go through our list of tabs and set the minimum size and the size hint
417     // This will allow us to elide text if necessary. Since we don't set
418     // a maximum size, tabs will EXPAND to fill up the empty space.
419     // Since tab widget is rather *ahem* strict about keeping the geometry of the
420     // tab bar to its absolute minimum, this won't bleed through, but will show up
421     // if you use tab bar on its own (a.k.a. not a bug, but a feature).
422     // Update: if expanding is false, we DO set a maximum size to prevent the tabs
423     // being wider than necessary.
424     if (!vertTabs) {
425         int minx = 0;
426         int x = 0;
427         int maxHeight = 0;
428         for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) {
429             QSize sz = q->tabSizeHint(i);
430             tabList[i].maxRect = QRect(x, 0, sz.width(), sz.height());
431             x += sz.width();
432             maxHeight = qMax(maxHeight, sz.height());
433             sz = minimumTabSizeHint(i);
434             tabList[i].minRect = QRect(minx, 0, sz.width(), sz.height());
435             minx += sz.width();
436             tabChain[tabChainIndex].init();
437             tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.width();
438             tabChain[tabChainIndex].minimumSize = sz.width();
439             tabChain[tabChainIndex].empty = false;
440             tabChain[tabChainIndex].expansive = true;
441
442             if (!expanding)
443                 tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint;
444         }
445
446         last = minx;
447         available = size.width();
448         maxExtent = maxHeight;
449     } else {
450         int miny = 0;
451         int y = 0;
452         int maxWidth = 0;
453         for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) {
454             QSize sz = q->tabSizeHint(i);
455             tabList[i].maxRect = QRect(0, y, sz.width(), sz.height());
456             y += sz.height();
457             maxWidth = qMax(maxWidth, sz.width());
458             sz = minimumTabSizeHint(i);
459             tabList[i].minRect = QRect(0, miny, sz.width(), sz.height());
460             miny += sz.height();
461             tabChain[tabChainIndex].init();
462             tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.height();
463             tabChain[tabChainIndex].minimumSize = sz.height();
464             tabChain[tabChainIndex].empty = false;
465             tabChain[tabChainIndex].expansive = true;
466
467             if (!expanding)
468                 tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint;
469         }
470
471         last = miny;
472         available = size.height();
473         maxExtent = maxWidth;
474     }
475
476     Q_ASSERT(tabChainIndex == tabChain.count() - 1); // add an assert just to make sure.
477     // Mirror our front item.
478     tabChain[tabChainIndex].init();
479     tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignRight)
480                                         && (tabAlignment != Qt::AlignJustify);
481     tabChain[tabChainIndex].empty = true;
482
483     // Do the calculation
484     qGeomCalc(tabChain, 0, tabChain.count(), 0, qMax(available, last), 0);
485
486     // Use the results
487     for (i = 0; i < tabList.count(); ++i) {
488         const QLayoutStruct &lstruct = tabChain.at(i + 1);
489         if (!vertTabs)
490             tabList[i].rect.setRect(lstruct.pos, 0, lstruct.size, maxExtent);
491         else
492             tabList[i].rect.setRect(0, lstruct.pos, maxExtent, lstruct.size);
493     }
494
495     if (useScrollButtons && tabList.count() && last > available) {
496         int extra = extraWidth();
497 #ifndef QT_NO_STYLE_S60
498         QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style());
499 #endif
500         if (!vertTabs) {
501             Qt::LayoutDirection ld = q->layoutDirection();
502             QRect arrows = QStyle::visualRect(ld, q->rect(),
503                                               QRect(available - extra, 0, extra, size.height()));
504             int buttonOverlap = q->style()->pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, q);
505
506             if (ld == Qt::LeftToRight) {
507 // In S60style, tab scroll buttons are layoutted separately, on the sides of the tabbar.
508 #ifndef QT_NO_STYLE_S60
509                 if (s60Style) {
510                     rightB->setGeometry(arrows.left() + extra / 2, arrows.top(), extra / 2, arrows.height());
511                     leftB->setGeometry(0, arrows.top(), extra / 2, arrows.height());
512                 } else {
513 #endif
514                 leftB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
515                 rightB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(),
516                                     extra/2, arrows.height());
517 #ifndef QT_NO_STYLE_S60
518                 }
519 #endif
520                 leftB->setArrowType(Qt::LeftArrow);
521                 rightB->setArrowType(Qt::RightArrow);
522             } else {
523 #ifndef QT_NO_STYLE_S60
524                 if (s60Style) {
525                     rightB->setGeometry(arrows.left() + extra / 2, arrows.top(), extra / 2, arrows.height());
526                     leftB->setGeometry(0, arrows.top(), extra / 2, arrows.height());
527                 } else {
528 #endif
529                 rightB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
530                 leftB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(),
531                                     extra/2, arrows.height());
532 #ifndef QT_NO_STYLE_S60
533                 }
534 #endif
535                 rightB->setArrowType(Qt::LeftArrow);
536                 leftB->setArrowType(Qt::RightArrow);
537             }
538         } else {
539 #ifndef QT_NO_STYLE_S60
540             if (s60Style) {
541                 QRect arrows = QRect(0, 0, size.width(), available );
542                 leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra / 2);
543                 leftB->setArrowType(Qt::UpArrow);
544                 rightB->setGeometry(arrows.left(), arrows.bottom() - extra / 2 + 1,
545                                     arrows.width(), extra / 2);
546                 rightB->setArrowType(Qt::DownArrow);
547             } else {
548 #endif
549             QRect arrows = QRect(0, available - extra, size.width(), extra );
550             leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra/2);
551             leftB->setArrowType(Qt::UpArrow);
552             rightB->setGeometry(arrows.left(), arrows.bottom() - extra/2 + 1,
553                                 arrows.width(), extra/2);
554             rightB->setArrowType(Qt::DownArrow);
555 #ifndef QT_NO_STYLE_S60
556             }
557 #endif
558         }
559         leftB->setEnabled(scrollOffset > 0);
560         rightB->setEnabled(last - scrollOffset >= available - extra);
561         leftB->show();
562         rightB->show();
563     } else {
564         rightB->hide();
565         leftB->hide();
566     }
567
568     layoutWidgets();
569     q->tabLayoutChange();
570 }
571
572 void QTabBarPrivate::makeVisible(int index)
573 {
574     Q_Q(QTabBar);
575     if (!validIndex(index) || leftB->isHidden())
576         return;
577
578     const QRect tabRect = tabList.at(index).rect;
579     const int oldScrollOffset = scrollOffset;
580     const bool horiz = !verticalTabs(shape);
581     const int available = (horiz ? q->width() : q->height()) - extraWidth();
582     const int start = horiz ? tabRect.left() : tabRect.top();
583     const int end = horiz ? tabRect.right() : tabRect.bottom();
584     if (start < scrollOffset) // too far left
585         scrollOffset = start - (index ? 8 : 0);
586     else if (end > scrollOffset + available) // too far right
587         scrollOffset = end - available + 1;
588
589     leftB->setEnabled(scrollOffset > 0);
590     const int last = horiz ? tabList.last().rect.right() : tabList.last().rect.bottom();
591     rightB->setEnabled(last - scrollOffset >= available);
592     if (oldScrollOffset != scrollOffset) {
593         q->update();
594         layoutWidgets();
595     }
596 }
597
598 void QTabBarPrivate::layoutTab(int index)
599 {
600     Q_Q(QTabBar);
601     Q_ASSERT(index >= 0);
602
603     Tab &tab = tabList[index];
604     bool vertical = verticalTabs(shape);
605     if (!(tab.leftWidget || tab.rightWidget))
606         return;
607
608     QStyleOptionTabV3 opt;
609     q->initStyleOption(&opt, index);
610     if (tab.leftWidget) {
611         QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabLeftButton, &opt, q);
612         QPoint p = rect.topLeft();
613         if ((index == pressedIndex) || paintWithOffsets) {
614             if (vertical)
615                 p.setY(p.y() + tabList[index].dragOffset);
616             else
617                 p.setX(p.x() + tabList[index].dragOffset);
618         }
619         tab.leftWidget->move(p);
620     }
621     if (tab.rightWidget) {
622         QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabRightButton, &opt, q);
623         QPoint p = rect.topLeft();
624         if ((index == pressedIndex) || paintWithOffsets) {
625             if (vertical)
626                 p.setY(p.y() + tab.dragOffset);
627             else
628                 p.setX(p.x() + tab.dragOffset);
629         }
630         tab.rightWidget->move(p);
631     }
632 }
633
634 void QTabBarPrivate::layoutWidgets(int start)
635 {
636     Q_Q(QTabBar);
637     for (int i = start; i < q->count(); ++i) {
638         layoutTab(i);
639     }
640 }
641
642 void QTabBarPrivate::_q_closeTab()
643 {
644     Q_Q(QTabBar);
645     QObject *object = q->sender();
646     int tabToClose = -1;
647     QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)q->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, q);
648     for (int i = 0; i < tabList.count(); ++i) {
649         if (closeSide == QTabBar::LeftSide) {
650             if (tabList.at(i).leftWidget == object) {
651                 tabToClose = i;
652                 break;
653             }
654         } else {
655             if (tabList.at(i).rightWidget == object) {
656                 tabToClose = i;
657                 break;
658             }
659         }
660     }
661     if (tabToClose != -1)
662         emit q->tabCloseRequested(tabToClose);
663 }
664
665 void QTabBarPrivate::_q_scrollTabs()
666 {
667     Q_Q(QTabBar);
668     const QObject *sender = q->sender();
669     int i = -1;
670     if (!verticalTabs(shape)) {
671         if (sender == leftB) {
672             for (i = tabList.count() - 1; i >= 0; --i) {
673                 if (tabList.at(i).rect.left() - scrollOffset < 0) {
674                     makeVisible(i);
675                     return;
676                 }
677             }
678         } else if (sender == rightB) {
679             int availableWidth = q->width() - extraWidth();
680             for (i = 0; i < tabList.count(); ++i) {
681                 if (tabList.at(i).rect.right() - scrollOffset > availableWidth) {
682                     makeVisible(i);
683                     return;
684                 }
685             }
686         }
687     } else { // vertical
688         if (sender == leftB) {
689             for (i = tabList.count() - 1; i >= 0; --i) {
690                 if (tabList.at(i).rect.top() - scrollOffset < 0) {
691                     makeVisible(i);
692                     return;
693                 }
694             }
695         } else if (sender == rightB) {
696             int available = q->height() - extraWidth();
697             for (i = 0; i < tabList.count(); ++i) {
698                 if (tabList.at(i).rect.bottom() - scrollOffset > available) {
699                     makeVisible(i);
700                     return;
701                 }
702             }
703         }
704     }
705 }
706
707 void QTabBarPrivate::refresh()
708 {
709     Q_Q(QTabBar);
710
711     // be safe in case a subclass is also handling move with the tabs
712     if (pressedIndex != -1
713         && movable
714         && QApplication::mouseButtons() == Qt::NoButton) {
715         moveTabFinished(pressedIndex);
716         if (!validIndex(pressedIndex))
717             pressedIndex = -1;
718     }
719
720     if (!q->isVisible()) {
721         layoutDirty = true;
722     } else {
723         layoutTabs();
724         makeVisible(currentIndex);
725         q->update();
726         q->updateGeometry();
727     }
728 }
729
730 /*!
731     Creates a new tab bar with the given \a parent.
732 */
733 QTabBar::QTabBar(QWidget* parent)
734     :QWidget(*new QTabBarPrivate, parent, 0)
735 {
736     Q_D(QTabBar);
737     d->init();
738 }
739
740
741 /*!
742     Destroys the tab bar.
743 */
744 QTabBar::~QTabBar()
745 {
746 }
747
748 /*!
749     \property QTabBar::shape
750     \brief the shape of the tabs in the tab bar
751
752     Possible values for this property are described by the Shape enum.
753 */
754
755
756 QTabBar::Shape QTabBar::shape() const
757 {
758     Q_D(const QTabBar);
759     return d->shape;
760 }
761
762 void QTabBar::setShape(Shape shape)
763 {
764     Q_D(QTabBar);
765     if (d->shape == shape)
766         return;
767     d->shape = shape;
768     d->refresh();
769 }
770
771 /*!
772     \property QTabBar::drawBase
773     \brief defines whether or not tab bar should draw its base.
774
775     If true then QTabBar draws a base in relation to the styles overlab.
776     Otherwise only the tabs are drawn.
777
778     \sa QStyle::pixelMetric() QStyle::PM_TabBarBaseOverlap QStyleOptionTabBarBaseV2
779 */
780
781 void QTabBar::setDrawBase(bool drawBase)
782 {
783     Q_D(QTabBar);
784     if (d->drawBase == drawBase)
785         return;
786     d->drawBase = drawBase;
787     update();
788 }
789
790 bool QTabBar::drawBase() const
791 {
792     Q_D(const QTabBar);
793     return d->drawBase;
794 }
795
796 /*!
797     Adds a new tab with text \a text. Returns the new
798     tab's index.
799 */
800 int QTabBar::addTab(const QString &text)
801 {
802     return insertTab(-1, text);
803 }
804
805 /*!
806     \overload
807
808     Adds a new tab with icon \a icon and text \a
809     text. Returns the new tab's index.
810 */
811 int QTabBar::addTab(const QIcon& icon, const QString &text)
812 {
813     return insertTab(-1, icon, text);
814 }
815
816 /*!
817     Inserts a new tab with text \a text at position \a index. If \a
818     index is out of range, the new tab is appened. Returns the new
819     tab's index.
820 */
821 int QTabBar::insertTab(int index, const QString &text)
822 {
823     return insertTab(index, QIcon(), text);
824 }
825
826 /*!\overload
827
828     Inserts a new tab with icon \a icon and text \a text at position
829     \a index. If \a index is out of range, the new tab is
830     appended. Returns the new tab's index.
831
832     If the QTabBar was empty before this function is called, the inserted tab
833     becomes the current tab.
834
835     Inserting a new tab at an index less than or equal to the current index
836     will increment the current index, but keep the current tab.
837 */
838 int QTabBar::insertTab(int index, const QIcon& icon, const QString &text)
839 {
840     Q_D(QTabBar);
841     if (!d->validIndex(index)) {
842         index = d->tabList.count();
843         d->tabList.append(QTabBarPrivate::Tab(icon, text));
844     } else {
845         d->tabList.insert(index, QTabBarPrivate::Tab(icon, text));
846     }
847 #ifndef QT_NO_SHORTCUT
848     d->tabList[index].shortcutId = grabShortcut(QKeySequence::mnemonic(text));
849 #endif
850     d->refresh();
851     if (d->tabList.count() == 1)
852         setCurrentIndex(index);
853     else if (index <= d->currentIndex)
854         ++d->currentIndex;
855
856     if (d->closeButtonOnTabs) {
857         QStyleOptionTabV3 opt;
858         initStyleOption(&opt, index);
859         ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
860         QAbstractButton *closeButton = new CloseButton(this);
861         connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
862         setTabButton(index, closeSide, closeButton);
863     }
864
865     for (int i = 0; i < d->tabList.count(); ++i) {
866         if (d->tabList[i].lastTab >= index)
867             ++d->tabList[i].lastTab;
868     }
869
870     tabInserted(index);
871     return index;
872 }
873
874
875 /*!
876     Removes the tab at position \a index.
877
878     \sa SelectionBehavior
879  */
880 void QTabBar::removeTab(int index)
881 {
882     Q_D(QTabBar);
883     if (d->validIndex(index)) {
884 #ifndef QT_NO_SHORTCUT
885         releaseShortcut(d->tabList.at(index).shortcutId);
886 #endif
887         if (d->tabList[index].leftWidget) {
888             d->tabList[index].leftWidget->hide();
889             d->tabList[index].leftWidget->deleteLater();
890             d->tabList[index].leftWidget = 0;
891         }
892         if (d->tabList[index].rightWidget) {
893             d->tabList[index].rightWidget->hide();
894             d->tabList[index].rightWidget->deleteLater();
895             d->tabList[index].rightWidget = 0;
896         }
897
898         int newIndex = d->tabList[index].lastTab;
899         d->tabList.removeAt(index);
900         for (int i = 0; i < d->tabList.count(); ++i) {
901             if (d->tabList[i].lastTab == index)
902                 d->tabList[i].lastTab = -1;
903             if (d->tabList[i].lastTab > index)
904                 --d->tabList[i].lastTab;
905         }
906         if (index == d->currentIndex) {
907             // The current tab is going away, in order to make sure
908             // we emit that "current has changed", we need to reset this
909             // around.
910             d->currentIndex = -1;
911             if (d->tabList.size() > 0) {
912                 switch(d->selectionBehaviorOnRemove) {
913                 case SelectPreviousTab:
914                     if (newIndex > index)
915                         newIndex--;
916                     if (d->validIndex(newIndex))
917                         break;
918                     // else fallthrough
919                 case SelectRightTab:
920                     newIndex = index;
921                     if (newIndex >= d->tabList.size())
922                         newIndex = d->tabList.size() - 1;
923                     break;
924                 case SelectLeftTab:
925                     newIndex = index - 1;
926                     if (newIndex < 0)
927                         newIndex = 0;
928                     break;
929                 default:
930                     break;
931                 }
932
933                 if (d->validIndex(newIndex)) {
934                     // don't loose newIndex's old through setCurrentIndex
935                     int bump = d->tabList[newIndex].lastTab;
936                     setCurrentIndex(newIndex);
937                     d->tabList[newIndex].lastTab = bump;
938                 }
939             } else {
940                 emit currentChanged(-1);
941             }
942         } else if (index < d->currentIndex) {
943             setCurrentIndex(d->currentIndex - 1);
944         }
945         d->refresh();
946         tabRemoved(index);
947     }
948 }
949
950
951 /*!
952     Returns true if the tab at position \a index is enabled; otherwise
953     returns false.
954 */
955 bool QTabBar::isTabEnabled(int index) const
956 {
957     Q_D(const QTabBar);
958     if (const QTabBarPrivate::Tab *tab = d->at(index))
959         return tab->enabled;
960     return false;
961 }
962
963 /*!
964     If \a enabled is true then the tab at position \a index is
965     enabled; otherwise the item at position \a index is disabled.
966 */
967 void QTabBar::setTabEnabled(int index, bool enabled)
968 {
969     Q_D(QTabBar);
970     if (QTabBarPrivate::Tab *tab = d->at(index)) {
971         tab->enabled = enabled;
972 #ifndef QT_NO_SHORTCUT
973         setShortcutEnabled(tab->shortcutId, enabled);
974 #endif
975         update();
976         if (!enabled && index == d->currentIndex)
977             setCurrentIndex(d->validIndex(index+1)?index+1:0);
978         else if (enabled && !d->validIndex(d->currentIndex))
979             setCurrentIndex(index);
980     }
981 }
982
983
984 /*!
985     Returns the text of the tab at position \a index, or an empty
986     string if \a index is out of range.
987 */
988 QString QTabBar::tabText(int index) const
989 {
990     Q_D(const QTabBar);
991     if (const QTabBarPrivate::Tab *tab = d->at(index))
992         return tab->text;
993     return QString();
994 }
995
996 /*!
997     Sets the text of the tab at position \a index to \a text.
998 */
999 void QTabBar::setTabText(int index, const QString &text)
1000 {
1001     Q_D(QTabBar);
1002     if (QTabBarPrivate::Tab *tab = d->at(index)) {
1003         tab->text = text;
1004 #ifndef QT_NO_SHORTCUT
1005         releaseShortcut(tab->shortcutId);
1006         tab->shortcutId = grabShortcut(QKeySequence::mnemonic(text));
1007         setShortcutEnabled(tab->shortcutId, tab->enabled);
1008 #endif
1009         d->refresh();
1010     }
1011 }
1012
1013 /*!
1014     Returns the text color of the tab with the given \a index, or a invalid
1015     color if \a index is out of range.
1016
1017     \sa setTabTextColor()
1018 */
1019 QColor QTabBar::tabTextColor(int index) const
1020 {
1021     Q_D(const QTabBar);
1022     if (const QTabBarPrivate::Tab *tab = d->at(index))
1023         return tab->textColor;
1024     return QColor();
1025 }
1026
1027 /*!
1028     Sets the color of the text in the tab with the given \a index to the specified \a color.
1029
1030     If an invalid color is specified, the tab will use the QTabBar foreground role instead.
1031
1032     \sa tabTextColor()
1033 */
1034 void QTabBar::setTabTextColor(int index, const QColor &color)
1035 {
1036     Q_D(QTabBar);
1037     if (QTabBarPrivate::Tab *tab = d->at(index)) {
1038         tab->textColor = color;
1039         update(tabRect(index));
1040     }
1041 }
1042
1043 /*!
1044     Returns the icon of the tab at position \a index, or a null icon
1045     if \a index is out of range.
1046 */
1047 QIcon QTabBar::tabIcon(int index) const
1048 {
1049     Q_D(const QTabBar);
1050     if (const QTabBarPrivate::Tab *tab = d->at(index))
1051         return tab->icon;
1052     return QIcon();
1053 }
1054
1055 /*!
1056     Sets the icon of the tab at position \a index to \a icon.
1057 */
1058 void QTabBar::setTabIcon(int index, const QIcon & icon)
1059 {
1060     Q_D(QTabBar);
1061     if (QTabBarPrivate::Tab *tab = d->at(index)) {
1062         bool simpleIconChange = (!icon.isNull() && !tab->icon.isNull());
1063         tab->icon = icon;
1064         if (simpleIconChange)
1065             update(tabRect(index));
1066         else
1067             d->refresh();
1068     }
1069 }
1070
1071 #ifndef QT_NO_TOOLTIP
1072 /*!
1073     Sets the tool tip of the tab at position \a index to \a tip.
1074 */
1075 void QTabBar::setTabToolTip(int index, const QString & tip)
1076 {
1077     Q_D(QTabBar);
1078     if (QTabBarPrivate::Tab *tab = d->at(index))
1079         tab->toolTip = tip;
1080 }
1081
1082 /*!
1083     Returns the tool tip of the tab at position \a index, or an empty
1084     string if \a index is out of range.
1085 */
1086 QString QTabBar::tabToolTip(int index) const
1087 {
1088     Q_D(const QTabBar);
1089     if (const QTabBarPrivate::Tab *tab = d->at(index))
1090         return tab->toolTip;
1091     return QString();
1092 }
1093 #endif // QT_NO_TOOLTIP
1094
1095 #ifndef QT_NO_WHATSTHIS
1096 /*!
1097     \since 4.1
1098
1099     Sets the What's This help text of the tab at position \a index
1100     to \a text.
1101 */
1102 void QTabBar::setTabWhatsThis(int index, const QString &text)
1103 {
1104     Q_D(QTabBar);
1105     if (QTabBarPrivate::Tab *tab = d->at(index))
1106         tab->whatsThis = text;
1107 }
1108
1109 /*!
1110     \since 4.1
1111
1112     Returns the What's This help text of the tab at position \a index,
1113     or an empty string if \a index is out of range.
1114 */
1115 QString QTabBar::tabWhatsThis(int index) const
1116 {
1117     Q_D(const QTabBar);
1118     if (const QTabBarPrivate::Tab *tab = d->at(index))
1119         return tab->whatsThis;
1120     return QString();
1121 }
1122
1123 #endif // QT_NO_WHATSTHIS
1124
1125 /*!
1126     Sets the data of the tab at position \a index to \a data.
1127 */
1128 void QTabBar::setTabData(int index, const QVariant & data)
1129 {
1130     Q_D(QTabBar);
1131     if (QTabBarPrivate::Tab *tab = d->at(index))
1132         tab->data = data;
1133 }
1134
1135 /*!
1136     Returns the data of the tab at position \a index, or a null
1137     variant if \a index is out of range.
1138 */
1139 QVariant QTabBar::tabData(int index) const
1140 {
1141     Q_D(const QTabBar);
1142     if (const QTabBarPrivate::Tab *tab = d->at(index))
1143         return tab->data;
1144     return QVariant();
1145 }
1146
1147 /*!
1148     Returns the visual rectangle of the tab at position \a
1149     index, or a null rectangle if \a index is out of range.
1150 */
1151 QRect QTabBar::tabRect(int index) const
1152 {
1153     Q_D(const QTabBar);
1154     if (const QTabBarPrivate::Tab *tab = d->at(index)) {
1155         if (d->layoutDirty)
1156             const_cast<QTabBarPrivate*>(d)->layoutTabs();
1157         QRect r = tab->rect;
1158         if (verticalTabs(d->shape))
1159             r.translate(0, -d->scrollOffset);
1160         else
1161             r.translate(-d->scrollOffset, 0);
1162         if (!verticalTabs(d->shape))
1163             r = QStyle::visualRect(layoutDirection(), rect(), r);
1164         return r;
1165     }
1166     return QRect();
1167 }
1168
1169 /*!
1170     \since 4.3
1171     Returns the index of the tab that covers \a position or -1 if no
1172     tab covers \a position;
1173 */
1174
1175 int QTabBar::tabAt(const QPoint &position) const
1176 {
1177     Q_D(const QTabBar);
1178     if (d->validIndex(d->currentIndex)
1179         && tabRect(d->currentIndex).contains(position)) {
1180         return d->currentIndex;
1181     }
1182     const int max = d->tabList.size();
1183     for (int i = 0; i < max; ++i) {
1184         if (tabRect(i).contains(position)) {
1185             return i;
1186         }
1187     }
1188     return -1;
1189 }
1190
1191 /*!
1192     \property QTabBar::currentIndex
1193     \brief the index of the tab bar's visible tab
1194
1195     The current index is -1 if there is no current tab.
1196 */
1197
1198 int QTabBar::currentIndex() const
1199 {
1200     Q_D(const QTabBar);
1201     if (d->validIndex(d->currentIndex))
1202         return d->currentIndex;
1203     return -1;
1204 }
1205
1206
1207 void QTabBar::setCurrentIndex(int index)
1208 {
1209     Q_D(QTabBar);
1210     if (d->dragInProgress && d->pressedIndex != -1)
1211         return;
1212
1213     int oldIndex = d->currentIndex;
1214     if (d->validIndex(index) && d->currentIndex != index) {
1215         d->currentIndex = index;
1216         update();
1217         d->makeVisible(index);
1218         d->tabList[index].lastTab = oldIndex;
1219         if (oldIndex >= 0 && oldIndex < count())
1220             d->layoutTab(oldIndex);
1221         d->layoutTab(index);
1222 #ifndef QT_NO_ACCESSIBILITY
1223         if (QAccessible::isActive()) {
1224             QAccessible::updateAccessibility(this, index + 1, QAccessible::Focus);
1225             QAccessible::updateAccessibility(this, index + 1, QAccessible::Selection);
1226         }
1227 #endif
1228 #ifdef QT3_SUPPORT
1229         emit selected(index);
1230 #endif
1231         emit currentChanged(index);
1232     }
1233 }
1234
1235 /*!
1236     \property QTabBar::iconSize
1237     \brief The size for icons in the tab bar
1238     \since 4.1
1239
1240     The default value is style-dependent. \c iconSize is a maximum
1241     size; icons that are smaller are not scaled up.
1242
1243     \sa QTabWidget::iconSize
1244 */
1245 QSize QTabBar::iconSize() const
1246 {
1247     Q_D(const QTabBar);
1248     if (d->iconSize.isValid())
1249         return d->iconSize;
1250     int iconExtent = style()->pixelMetric(QStyle::PM_TabBarIconSize, 0, this);
1251     return QSize(iconExtent, iconExtent);
1252
1253 }
1254
1255 void QTabBar::setIconSize(const QSize &size)
1256 {
1257     Q_D(QTabBar);
1258     d->iconSize = size;
1259     d->layoutDirty = true;
1260     update();
1261     updateGeometry();
1262 }
1263
1264 /*!
1265     \property QTabBar::count
1266     \brief the number of tabs in the tab bar
1267 */
1268
1269 int QTabBar::count() const
1270 {
1271     Q_D(const QTabBar);
1272     return d->tabList.count();
1273 }
1274
1275
1276 /*!\reimp
1277  */
1278 QSize QTabBar::sizeHint() const
1279 {
1280     Q_D(const QTabBar);
1281     if (d->layoutDirty)
1282         const_cast<QTabBarPrivate*>(d)->layoutTabs();
1283     QRect r;
1284     for (int i = 0; i < d->tabList.count(); ++i)
1285         r = r.united(d->tabList.at(i).maxRect);
1286     QSize sz = QApplication::globalStrut();
1287     return r.size().expandedTo(sz);
1288 }
1289
1290 /*!\reimp
1291  */
1292 QSize QTabBar::minimumSizeHint() const
1293 {
1294     Q_D(const QTabBar);
1295     if (d->layoutDirty)
1296         const_cast<QTabBarPrivate*>(d)->layoutTabs();
1297     if (!d->useScrollButtons) {
1298         QRect r;
1299         for (int i = 0; i < d->tabList.count(); ++i)
1300             r = r.united(d->tabList.at(i).minRect);
1301         return r.size().expandedTo(QApplication::globalStrut());
1302     }
1303     if (verticalTabs(d->shape))
1304         return QSize(sizeHint().width(), d->rightB->sizeHint().height() * 2 + 75);
1305     else
1306         return QSize(d->rightB->sizeHint().width() * 2 + 75, sizeHint().height());
1307 }
1308
1309 // Compute the most-elided possible text, for minimumSizeHint
1310 static QString computeElidedText(Qt::TextElideMode mode, const QString &text)
1311 {
1312     if (text.length() <= 3)
1313         return text;
1314
1315     static const QLatin1String Ellipses("...");
1316     QString ret;
1317     switch (mode) {
1318     case Qt::ElideRight:
1319         ret = text.left(2) + Ellipses;
1320         break;
1321     case Qt::ElideMiddle:
1322         ret = text.left(1) + Ellipses + text.right(1);
1323         break;
1324     case Qt::ElideLeft:
1325         ret = Ellipses + text.right(2);
1326         break;
1327     case Qt::ElideNone:
1328         ret = text;
1329         break;
1330     }
1331     return ret;
1332 }
1333
1334 QSize QTabBarPrivate::minimumTabSizeHint(int index)
1335 {
1336     Q_Q(QTabBar);
1337     // ### Qt 5: make this a protected virtual function in QTabBar
1338     Tab &tab = tabList[index];
1339     QString oldText = tab.text;
1340     tab.text = computeElidedText(elideMode, oldText);
1341     QSize size = q->tabSizeHint(index);
1342     tab.text = oldText;
1343     return size;
1344 }
1345
1346 /*!
1347     Returns the size hint for the tab at position \a index.
1348 */
1349 QSize QTabBar::tabSizeHint(int index) const
1350 {
1351     //Note: this must match with the computations in QCommonStylePrivate::tabLayout
1352     Q_D(const QTabBar);
1353     if (const QTabBarPrivate::Tab *tab = d->at(index)) {
1354         QStyleOptionTabV3 opt;
1355         initStyleOption(&opt, index);
1356         opt.text = d->tabList.at(index).text;
1357         QSize iconSize = tab->icon.isNull() ? QSize(0, 0) : opt.iconSize;
1358         int hframe = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this);
1359         int vframe = style()->pixelMetric(QStyle::PM_TabBarTabVSpace, &opt, this);
1360         const QFontMetrics fm = fontMetrics();
1361
1362         int maxWidgetHeight = qMax(opt.leftButtonSize.height(), opt.rightButtonSize.height());
1363         int maxWidgetWidth = qMax(opt.leftButtonSize.width(), opt.rightButtonSize.width());
1364
1365         int widgetWidth = 0;
1366         int widgetHeight = 0;
1367         int padding = 0;
1368         if (!opt.leftButtonSize.isEmpty()) {
1369             padding += 4;
1370             widgetWidth += opt.leftButtonSize.width();
1371             widgetHeight += opt.leftButtonSize.height();
1372         }
1373         if (!opt.rightButtonSize.isEmpty()) {
1374             padding += 4;
1375             widgetWidth += opt.rightButtonSize.width();
1376             widgetHeight += opt.rightButtonSize.height();
1377         }
1378         if (!opt.icon.isNull())
1379             padding += 4;
1380
1381         QSize csz;
1382         if (verticalTabs(d->shape)) {
1383             csz = QSize( qMax(maxWidgetWidth, qMax(fm.height(), iconSize.height())) + vframe,
1384                     fm.size(Qt::TextShowMnemonic, tab->text).width() + iconSize.width() + hframe + widgetHeight + padding);
1385         } else {
1386             csz = QSize(fm.size(Qt::TextShowMnemonic, tab->text).width() + iconSize.width() + hframe
1387                   + widgetWidth + padding,
1388                   qMax(maxWidgetHeight, qMax(fm.height(), iconSize.height())) + vframe);
1389         }
1390
1391         QSize retSize = style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, csz, this);
1392         return retSize;
1393     }
1394     return QSize();
1395 }
1396
1397 /*!
1398   This virtual handler is called after a new tab was added or
1399   inserted at position \a index.
1400
1401   \sa tabRemoved()
1402  */
1403 void QTabBar::tabInserted(int index)
1404 {
1405     Q_UNUSED(index)
1406 }
1407
1408 /*!
1409   This virtual handler is called after a tab was removed from
1410   position \a index.
1411
1412   \sa tabInserted()
1413  */
1414 void QTabBar::tabRemoved(int index)
1415 {
1416     Q_UNUSED(index)
1417 }
1418
1419 /*!
1420   This virtual handler is called whenever the tab layout changes.
1421
1422   \sa tabRect()
1423  */
1424 void QTabBar::tabLayoutChange()
1425 {
1426 }
1427
1428
1429 /*!\reimp
1430  */
1431 void QTabBar::showEvent(QShowEvent *)
1432 {
1433     Q_D(QTabBar);
1434     if (d->layoutDirty)
1435         d->refresh();
1436     if (!d->validIndex(d->currentIndex))
1437         setCurrentIndex(0);
1438     d->updateMacBorderMetrics();
1439 }
1440
1441 /*!\reimp
1442  */
1443 void QTabBar::hideEvent(QHideEvent *)
1444 {
1445     Q_D(QTabBar);
1446     d->updateMacBorderMetrics();
1447 }
1448
1449 /*!\reimp
1450  */
1451 bool QTabBar::event(QEvent *event)
1452 {
1453     Q_D(QTabBar);
1454     if (event->type() == QEvent::HoverMove
1455         || event->type() == QEvent::HoverEnter) {
1456         QHoverEvent *he = static_cast<QHoverEvent *>(event);
1457         if (!d->hoverRect.contains(he->pos())) {
1458             QRect oldHoverRect = d->hoverRect;
1459             for (int i = 0; i < d->tabList.count(); ++i) {
1460                 QRect area = tabRect(i);
1461                 if (area.contains(he->pos())) {
1462                     d->hoverRect = area;
1463                     break;
1464                 }
1465             }
1466             if (he->oldPos() != QPoint(-1, -1))
1467                 update(oldHoverRect);
1468             update(d->hoverRect);
1469         }
1470         return true;
1471     } else if (event->type() == QEvent::HoverLeave ) {
1472         QRect oldHoverRect = d->hoverRect;
1473         d->hoverRect = QRect();
1474         update(oldHoverRect);
1475         return true;
1476 #ifndef QT_NO_TOOLTIP
1477     } else if (event->type() == QEvent::ToolTip) {
1478         if (const QTabBarPrivate::Tab *tab = d->at(tabAt(static_cast<QHelpEvent*>(event)->pos()))) {
1479             if (!tab->toolTip.isEmpty()) {
1480                 QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(), tab->toolTip, this);
1481                 return true;
1482             }
1483         }
1484 #endif // QT_NO_TOOLTIP
1485 #ifndef QT_NO_WHATSTHIS
1486     } else if (event->type() == QEvent::QueryWhatsThis) {
1487         const QTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast<QHelpEvent*>(event)->pos()));
1488         if (!tab || tab->whatsThis.isEmpty())
1489             event->ignore();
1490         return true;
1491     } else if (event->type() == QEvent::WhatsThis) {
1492         if (const QTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast<QHelpEvent*>(event)->pos()))) {
1493             if (!tab->whatsThis.isEmpty()) {
1494                 QWhatsThis::showText(static_cast<QHelpEvent*>(event)->globalPos(),
1495                                      tab->whatsThis, this);
1496                 return true;
1497             }
1498         }
1499 #endif // QT_NO_WHATSTHIS
1500 #ifndef QT_NO_SHORTCUT
1501     } else if (event->type() == QEvent::Shortcut) {
1502         QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
1503         for (int i = 0; i < d->tabList.count(); ++i) {
1504             const QTabBarPrivate::Tab *tab = &d->tabList.at(i);
1505             if (tab->shortcutId == se->shortcutId()) {
1506                 setCurrentIndex(i);
1507                 return true;
1508             }
1509         }
1510 #endif
1511     }
1512     return QWidget::event(event);
1513 }
1514
1515 /*!\reimp
1516  */
1517 void QTabBar::resizeEvent(QResizeEvent *)
1518 {
1519     Q_D(QTabBar);
1520     if (d->layoutDirty)
1521         updateGeometry();
1522     d->layoutTabs();
1523
1524     d->makeVisible(d->currentIndex);
1525 }
1526
1527 /*!\reimp
1528  */
1529 void QTabBar::paintEvent(QPaintEvent *)
1530 {
1531     Q_D(QTabBar);
1532
1533     QStyleOptionTabBarBaseV2 optTabBase;
1534     QTabBarPrivate::initStyleBaseOption(&optTabBase, this, size());
1535
1536     QStylePainter p(this);
1537     int selected = -1;
1538     int cut = -1;
1539     bool rtl = optTabBase.direction == Qt::RightToLeft;
1540     bool vertical = verticalTabs(d->shape);
1541     QStyleOptionTab cutTab;
1542     selected = d->currentIndex;
1543     if (d->dragInProgress)
1544         selected = d->pressedIndex;
1545
1546     for (int i = 0; i < d->tabList.count(); ++i)
1547          optTabBase.tabBarRect |= tabRect(i);
1548
1549     optTabBase.selectedTabRect = tabRect(selected);
1550
1551     if (d->drawBase)
1552         p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
1553
1554     for (int i = 0; i < d->tabList.count(); ++i) {
1555         QStyleOptionTabV3 tab;
1556         initStyleOption(&tab, i);
1557         if (d->paintWithOffsets && d->tabList[i].dragOffset != 0) {
1558             if (vertical) {
1559                 tab.rect.moveTop(tab.rect.y() + d->tabList[i].dragOffset);
1560             } else {
1561                 tab.rect.moveLeft(tab.rect.x() + d->tabList[i].dragOffset);
1562             }
1563         }
1564         if (!(tab.state & QStyle::State_Enabled)) {
1565             tab.palette.setCurrentColorGroup(QPalette::Disabled);
1566         }
1567         // If this tab is partially obscured, make a note of it so that we can pass the information
1568         // along when we draw the tear.
1569         if (((!vertical && (!rtl && tab.rect.left() < 0)) || (rtl && tab.rect.right() > width()))
1570             || (vertical && tab.rect.top() < 0)) {
1571             cut = i;
1572             cutTab = tab;
1573         }
1574         // Don't bother drawing a tab if the entire tab is outside of the visible tab bar.
1575         if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width()))
1576             || (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height())))
1577             continue;
1578
1579         optTabBase.tabBarRect |= tab.rect;
1580         if (i == selected)
1581             continue;
1582
1583         p.drawControl(QStyle::CE_TabBarTab, tab);
1584     }
1585
1586     // Draw the selected tab last to get it "on top"
1587     if (selected >= 0) {
1588         QStyleOptionTabV3 tab;
1589         initStyleOption(&tab, selected);
1590         if (d->paintWithOffsets && d->tabList[selected].dragOffset != 0) {
1591             if (vertical)
1592                 tab.rect.moveTop(tab.rect.y() + d->tabList[selected].dragOffset);
1593             else
1594                 tab.rect.moveLeft(tab.rect.x() + d->tabList[selected].dragOffset);
1595         }
1596         if (!d->dragInProgress)
1597             p.drawControl(QStyle::CE_TabBarTab, tab);
1598         else {
1599             int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this);
1600             d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
1601         }
1602     }
1603
1604     // Only draw the tear indicator if necessary. Most of the time we don't need too.
1605     if (d->leftB->isVisible() && cut >= 0) {
1606         cutTab.rect = rect();
1607         cutTab.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicator, &cutTab, this);
1608         p.drawPrimitive(QStyle::PE_IndicatorTabTear, cutTab);
1609     }
1610 }
1611
1612 /*
1613     Given that index at position from moved to position to where return where index goes.
1614  */
1615 int QTabBarPrivate::calculateNewPosition(int from, int to, int index) const
1616 {
1617     if (index == from)
1618         return to;
1619
1620     int start = qMin(from, to);
1621     int end = qMax(from, to);
1622     if (index >= start && index <= end)
1623         index += (from < to) ? -1 : 1;
1624     return index;
1625 }
1626
1627 /*!
1628     Moves the item at index position \a from to index position \a to.
1629     \since 4.5
1630
1631     \sa tabMoved(), tabLayoutChange()
1632  */
1633 void QTabBar::moveTab(int from, int to)
1634 {
1635     Q_D(QTabBar);
1636     if (from == to
1637         || !d->validIndex(from)
1638         || !d->validIndex(to))
1639         return;
1640
1641     bool vertical = verticalTabs(d->shape);
1642     int oldPressedPosition = 0;
1643     if (d->pressedIndex != -1) {
1644         // Record the position of the pressed tab before reordering the tabs.
1645         oldPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.y()
1646                              : d->tabList[d->pressedIndex].rect.x();
1647     }
1648
1649     // Update the locations of the tabs first
1650     int start = qMin(from, to);
1651     int end = qMax(from, to);
1652     int width = vertical ? d->tabList[from].rect.height() : d->tabList[from].rect.width();
1653     if (from < to)
1654         width *= -1;
1655     bool rtl = isRightToLeft();
1656     for (int i = start; i <= end; ++i) {
1657         if (i == from)
1658             continue;
1659         if (vertical)
1660             d->tabList[i].rect.moveTop(d->tabList[i].rect.y() + width);
1661         else
1662             d->tabList[i].rect.moveLeft(d->tabList[i].rect.x() + width);
1663         int direction = -1;
1664         if (rtl && !vertical)
1665             direction *= -1;
1666         if (d->tabList[i].dragOffset != 0)
1667             d->tabList[i].dragOffset += (direction * width);
1668     }
1669
1670     if (vertical) {
1671         if (from < to)
1672             d->tabList[from].rect.moveTop(d->tabList[to].rect.bottom() + 1);
1673         else
1674             d->tabList[from].rect.moveTop(d->tabList[to].rect.top() - width);
1675     } else {
1676         if (from < to)
1677             d->tabList[from].rect.moveLeft(d->tabList[to].rect.right() + 1);
1678         else
1679             d->tabList[from].rect.moveLeft(d->tabList[to].rect.left() - width);
1680     }
1681
1682     // Move the actual data structures
1683     d->tabList.move(from, to);
1684
1685     // update lastTab locations
1686     for (int i = 0; i < d->tabList.count(); ++i)
1687         d->tabList[i].lastTab = d->calculateNewPosition(from, to, d->tabList[i].lastTab);
1688
1689     // update external variables
1690     d->currentIndex = d->calculateNewPosition(from, to, d->currentIndex);
1691
1692     // If we are in the middle of a drag update the dragStartPosition
1693     if (d->pressedIndex != -1) {
1694         d->pressedIndex = d->calculateNewPosition(from, to, d->pressedIndex);
1695         int newPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.top() : d->tabList[d->pressedIndex].rect.left();
1696         int diff = oldPressedPosition - newPressedPosition;
1697         if (isRightToLeft() && !vertical)
1698             diff *= -1;
1699         if (vertical)
1700             d->dragStartPosition.setY(d->dragStartPosition.y() - diff);
1701         else
1702             d->dragStartPosition.setX(d->dragStartPosition.x() - diff);
1703     }
1704
1705     d->layoutWidgets(start);
1706     update();
1707     emit tabMoved(from, to);
1708     emit tabLayoutChange();
1709 }
1710
1711 void QTabBarPrivate::slide(int from, int to)
1712 {
1713     Q_Q(QTabBar);
1714     if (from == to
1715             || !validIndex(from)
1716             || !validIndex(to))
1717         return;
1718     bool vertical = verticalTabs(shape);
1719     int preLocation = vertical ? q->tabRect(from).y() : q->tabRect(from).x();
1720     q->setUpdatesEnabled(false);
1721     q->moveTab(from, to);
1722     q->setUpdatesEnabled(true);
1723     int postLocation = vertical ? q->tabRect(to).y() : q->tabRect(to).x();
1724     int length = postLocation - preLocation;
1725     tabList[to].dragOffset -= length;
1726     tabList[to].startAnimation(this, ANIMATION_DURATION);
1727 }
1728
1729 void QTabBarPrivate::moveTab(int index, int offset)
1730 {
1731     if (!validIndex(index))
1732         return;
1733     tabList[index].dragOffset = offset;
1734     layoutTab(index); // Make buttons follow tab
1735     q_func()->update();
1736 }
1737
1738 /*!\reimp
1739 */
1740 void QTabBar::mousePressEvent(QMouseEvent *event)
1741 {
1742     Q_D(QTabBar);
1743     if (event->button() != Qt::LeftButton) {
1744         event->ignore();
1745         return;
1746     }
1747     // Be safe!
1748     if (d->pressedIndex != -1 && d->movable)
1749         d->moveTabFinished(d->pressedIndex);
1750
1751     d->pressedIndex = d->indexAtPos(event->pos());
1752 #ifdef Q_WS_MAC
1753     d->previousPressedIndex = d->pressedIndex;
1754 #endif
1755     if (d->validIndex(d->pressedIndex)) {
1756         QStyleOptionTabBarBaseV2 optTabBase;
1757         optTabBase.init(this);
1758         optTabBase.documentMode = d->documentMode;
1759         if (event->type() == style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this))
1760             setCurrentIndex(d->pressedIndex);
1761         else
1762             repaint(tabRect(d->pressedIndex));
1763         if (d->movable) {
1764             d->dragStartPosition = event->pos();
1765         }
1766     }
1767 }
1768
1769 /*!\reimp
1770  */
1771 void QTabBar::mouseMoveEvent(QMouseEvent *event)
1772 {
1773     Q_D(QTabBar);
1774     if (d->movable) {
1775         // Be safe!
1776         if (d->pressedIndex != -1
1777             && event->buttons() == Qt::NoButton)
1778             d->moveTabFinished(d->pressedIndex);
1779         
1780         // Start drag
1781         if (!d->dragInProgress && d->pressedIndex != -1) {
1782             if ((event->pos() - d->dragStartPosition).manhattanLength() > QApplication::startDragDistance()) {
1783                 d->dragInProgress = true;
1784                 d->setupMovableTab();
1785             }
1786         }
1787
1788         int offset = (event->pos() - d->dragStartPosition).manhattanLength();
1789         if (event->buttons() == Qt::LeftButton
1790             && offset > QApplication::startDragDistance()
1791             && d->validIndex(d->pressedIndex)) {
1792             bool vertical = verticalTabs(d->shape);
1793             int dragDistance;
1794             if (vertical) {
1795                 dragDistance = (event->pos().y() - d->dragStartPosition.y());
1796             } else {
1797                 dragDistance = (event->pos().x() - d->dragStartPosition.x());
1798             }
1799             d->tabList[d->pressedIndex].dragOffset = dragDistance;
1800
1801             QRect startingRect = tabRect(d->pressedIndex);
1802             if (vertical)
1803                 startingRect.moveTop(startingRect.y() + dragDistance);
1804             else
1805                 startingRect.moveLeft(startingRect.x() + dragDistance);
1806
1807             int overIndex;
1808             if (dragDistance < 0)
1809                 overIndex = tabAt(startingRect.topLeft());
1810             else
1811                 overIndex = tabAt(startingRect.topRight());
1812
1813             if (overIndex != d->pressedIndex && overIndex != -1) {
1814                 int offset = 1;
1815                 if (isRightToLeft() && !vertical)
1816                     offset *= -1;
1817                 if (dragDistance < 0) {
1818                     dragDistance *= -1;
1819                     offset *= -1;
1820                 }
1821                 for (int i = d->pressedIndex;
1822                      offset > 0 ? i < overIndex : i > overIndex;
1823                      i += offset) {
1824                     QRect overIndexRect = tabRect(overIndex);
1825                     int needsToBeOver = (vertical ? overIndexRect.height() : overIndexRect.width()) / 2;
1826                     if (dragDistance > needsToBeOver)
1827                         d->slide(i + offset, d->pressedIndex);
1828                 }
1829             }
1830             // Buttons needs to follow the dragged tab
1831             d->layoutTab(d->pressedIndex);
1832
1833             update();
1834         }
1835 #ifdef Q_WS_MAC
1836     } else if (!d->documentMode && event->buttons() == Qt::LeftButton && d->previousPressedIndex != -1) {
1837         int newPressedIndex = d->indexAtPos(event->pos());
1838         if (d->pressedIndex == -1 && d->previousPressedIndex == newPressedIndex) {
1839             d->pressedIndex = d->previousPressedIndex;
1840             update(tabRect(d->pressedIndex));
1841         } else if(d->pressedIndex != newPressedIndex) {
1842             d->pressedIndex = -1;
1843             update(tabRect(d->previousPressedIndex));
1844         }
1845 #endif
1846     }
1847
1848     if (event->buttons() != Qt::LeftButton) {
1849         event->ignore();
1850         return;
1851     }
1852     QStyleOptionTabBarBaseV2 optTabBase;
1853     optTabBase.init(this);
1854     optTabBase.documentMode = d->documentMode;
1855 }
1856
1857 void QTabBarPrivate::setupMovableTab()
1858 {
1859     Q_Q(QTabBar);
1860     if (!movingTab)
1861         movingTab = new QWidget(q);
1862
1863     int taboverlap = q->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ,q);
1864     QRect grabRect = q->tabRect(pressedIndex);
1865     grabRect.adjust(-taboverlap, 0, taboverlap, 0);
1866
1867     QPixmap grabImage(grabRect.size());
1868     grabImage.fill(Qt::transparent);
1869     QStylePainter p(&grabImage, q);
1870     p.initFrom(q);
1871
1872     QStyleOptionTabV3 tab;
1873     q->initStyleOption(&tab, pressedIndex);
1874     tab.rect.moveTopLeft(QPoint(taboverlap, 0));
1875     p.drawControl(QStyle::CE_TabBarTab, tab);
1876     p.end();
1877
1878     QPalette pal;
1879     pal.setBrush(QPalette::All, QPalette::Window, grabImage);
1880     movingTab->setPalette(pal);
1881     movingTab->setGeometry(grabRect);
1882     movingTab->setAutoFillBackground(true);
1883     movingTab->raise();
1884
1885     // Re-arrange widget order to avoid overlaps
1886     if (tabList[pressedIndex].leftWidget)
1887         tabList[pressedIndex].leftWidget->raise();
1888     if (tabList[pressedIndex].rightWidget)
1889         tabList[pressedIndex].rightWidget->raise();
1890     if (leftB)
1891         leftB->raise();
1892     if (rightB)
1893         rightB->raise();
1894     movingTab->setVisible(true);
1895 }
1896
1897 void QTabBarPrivate::moveTabFinished(int index)
1898 {
1899     Q_Q(QTabBar);
1900     bool cleanup = (pressedIndex == index) || (pressedIndex == -1) || !validIndex(index);
1901     bool allAnimationsFinished = true;
1902 #ifndef QT_NO_ANIMATION
1903     for(int i = 0; allAnimationsFinished && i < tabList.count(); ++i) {
1904         const Tab &t = tabList.at(i);
1905         if (t.animation && t.animation->state() == QAbstractAnimation::Running)
1906             allAnimationsFinished = false;
1907     }
1908 #endif //QT_NO_ANIMATION
1909     if (allAnimationsFinished && cleanup) {
1910         if(movingTab)
1911             movingTab->setVisible(false); // We might not get a mouse release
1912         for (int i = 0; i < tabList.count(); ++i) {
1913             tabList[i].dragOffset = 0;
1914         }
1915         if (pressedIndex != -1 && movable) {
1916             pressedIndex = -1;
1917             dragInProgress = false;
1918             dragStartPosition = QPoint();
1919         }
1920         layoutWidgets();
1921     } else {
1922         if (!validIndex(index))
1923             return;
1924         tabList[index].dragOffset = 0;
1925     }
1926     q->update();
1927 }
1928
1929 /*!\reimp
1930 */
1931 void QTabBar::mouseReleaseEvent(QMouseEvent *event)
1932 {
1933     Q_D(QTabBar);
1934     if (event->button() != Qt::LeftButton) {
1935         event->ignore();
1936         return;
1937     }
1938 #ifdef Q_WS_MAC
1939     d->previousPressedIndex = -1;
1940 #endif
1941     if (d->movable && d->dragInProgress && d->validIndex(d->pressedIndex)) {
1942         int length = d->tabList[d->pressedIndex].dragOffset;
1943         int width = verticalTabs(d->shape)
1944             ? tabRect(d->pressedIndex).height()
1945             : tabRect(d->pressedIndex).width();
1946         int duration = qMin(ANIMATION_DURATION,
1947                 (qAbs(length) * ANIMATION_DURATION) / width);
1948         d->tabList[d->pressedIndex].startAnimation(d, duration);
1949         d->dragInProgress = false;
1950         d->movingTab->setVisible(false);
1951         d->dragStartPosition = QPoint();
1952     }
1953
1954     int i = d->indexAtPos(event->pos()) == d->pressedIndex ? d->pressedIndex : -1;
1955     d->pressedIndex = -1;
1956     QStyleOptionTabBarBaseV2 optTabBase;
1957     optTabBase.initFrom(this);
1958     optTabBase.documentMode = d->documentMode;
1959     if (style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this) == QEvent::MouseButtonRelease)
1960         setCurrentIndex(i);
1961 }
1962
1963 /*!\reimp
1964  */
1965 void QTabBar::keyPressEvent(QKeyEvent *event)
1966 {
1967     Q_D(QTabBar);
1968     if (event->key() != Qt::Key_Left && event->key() != Qt::Key_Right) {
1969         event->ignore();
1970         return;
1971     }
1972     int offset = event->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1;
1973     d->setCurrentNextEnabledIndex(offset);
1974 }
1975
1976 /*!\reimp
1977  */
1978 #ifndef QT_NO_WHEELEVENT
1979 void QTabBar::wheelEvent(QWheelEvent *event)
1980 {
1981     Q_D(QTabBar);
1982     int offset = event->delta() > 0 ? -1 : 1;
1983     d->setCurrentNextEnabledIndex(offset);
1984     QWidget::wheelEvent(event);
1985 }
1986 #endif //QT_NO_WHEELEVENT
1987
1988 void QTabBarPrivate::setCurrentNextEnabledIndex(int offset)
1989 {
1990     Q_Q(QTabBar);
1991     for (int index = currentIndex + offset; validIndex(index); index += offset) {
1992         if (tabList.at(index).enabled) {
1993             q->setCurrentIndex(index);
1994             break;
1995         }
1996     }
1997 }
1998
1999 /*!\reimp
2000  */
2001 void QTabBar::changeEvent(QEvent *event)
2002 {
2003     Q_D(QTabBar);
2004     if (event->type() == QEvent::StyleChange) {
2005         if (!d->elideModeSetByUser)
2006             d->elideMode = Qt::TextElideMode(style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, this));
2007         if (!d->useScrollButtonsSetByUser)
2008             d->useScrollButtons = !style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, this);
2009         d->refresh();
2010     } else if (event->type() == QEvent::FontChange) {
2011         d->refresh();
2012     }
2013     QWidget::changeEvent(event);
2014 }
2015
2016 /*!
2017     \property QTabBar::elideMode
2018     \brief how to elide text in the tab bar
2019     \since 4.2
2020
2021     This property controls how items are elided when there is not
2022     enough space to show them for a given tab bar size.
2023
2024     By default the value is style dependent.
2025
2026     \sa QTabWidget::elideMode usesScrollButtons QStyle::SH_TabBar_ElideMode
2027 */
2028
2029 Qt::TextElideMode QTabBar::elideMode() const
2030 {
2031     Q_D(const QTabBar);
2032     return d->elideMode;
2033 }
2034
2035 void QTabBar::setElideMode(Qt::TextElideMode mode)
2036 {
2037     Q_D(QTabBar);
2038     d->elideMode = mode;
2039     d->elideModeSetByUser = true;
2040     d->refresh();
2041 }
2042
2043 /*!
2044     \property QTabBar::usesScrollButtons
2045     \brief Whether or not a tab bar should use buttons to scroll tabs when it
2046     has many tabs.
2047     \since 4.2
2048
2049     When there are too many tabs in a tab bar for its size, the tab bar can either choose
2050     to expand its size or to add buttons that allow you to scroll through the tabs.
2051
2052     By default the value is style dependant.
2053
2054     \sa elideMode QTabWidget::usesScrollButtons QStyle::SH_TabBar_PreferNoArrows
2055 */
2056 bool QTabBar::usesScrollButtons() const
2057 {
2058     return d_func()->useScrollButtons;
2059 }
2060
2061 void QTabBar::setUsesScrollButtons(bool useButtons)
2062 {
2063     Q_D(QTabBar);
2064     d->useScrollButtonsSetByUser = true;
2065     if (d->useScrollButtons == useButtons)
2066         return;
2067     d->useScrollButtons = useButtons;
2068     d->refresh();
2069 }
2070
2071 /*!
2072     \fn void QTabBar::setCurrentTab(int index)
2073
2074     Use setCurrentIndex() instead.
2075 */
2076
2077 /*!
2078     \fn void QTabBar::selected(int index);
2079
2080     Use currentChanged() instead.
2081 */
2082
2083
2084 /*!
2085     \property QTabBar::tabsClosable
2086     \brief Whether or not a tab bar should place close buttons on each tab
2087     \since 4.5
2088
2089     When tabsClosable is set to true a close button will appear on the tab on
2090     either the left or right hand side depending upon the style.  When the button
2091     is clicked the tab the signal tabCloseRequested will be emitted.
2092
2093     By default the value is false.
2094
2095     \sa setTabButton(), tabRemoved()
2096 */
2097
2098 bool QTabBar::tabsClosable() const
2099 {
2100     Q_D(const QTabBar);
2101     return d->closeButtonOnTabs;
2102 }
2103
2104 void QTabBar::setTabsClosable(bool closable)
2105 {
2106     Q_D(QTabBar);
2107     if (d->closeButtonOnTabs == closable)
2108         return;
2109     d->closeButtonOnTabs = closable;
2110     ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
2111     if (!closable) {
2112         for (int i = 0; i < d->tabList.count(); ++i) {
2113             if (closeSide == LeftSide && d->tabList[i].leftWidget) {
2114                 d->tabList[i].leftWidget->deleteLater();
2115                 d->tabList[i].leftWidget = 0;
2116             }
2117             if (closeSide == RightSide && d->tabList[i].rightWidget) {
2118                 d->tabList[i].rightWidget->deleteLater();
2119                 d->tabList[i].rightWidget = 0;
2120             }
2121         }
2122     } else {
2123         bool newButtons = false;
2124         for (int i = 0; i < d->tabList.count(); ++i) {
2125             if (tabButton(i, closeSide))
2126                 continue;
2127             newButtons = true;
2128             QAbstractButton *closeButton = new CloseButton(this);
2129             connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
2130             setTabButton(i, closeSide, closeButton);
2131         }
2132         if (newButtons)
2133             d->layoutTabs();
2134     }
2135     update();
2136 }
2137
2138 /*!
2139     \enum QTabBar::ButtonPosition
2140     \since 4.5
2141
2142     This enum type lists the location of the widget on a tab.
2143
2144     \value LeftSide Left side of the tab.
2145
2146     \value RightSide Right side of the tab.
2147
2148 */
2149
2150 /*!
2151     \enum QTabBar::SelectionBehavior
2152     \since 4.5
2153
2154     This enum type lists the behavior of QTabBar when a tab is removed
2155     and the tab being removed is also the current tab.
2156
2157     \value SelectLeftTab  Select the tab to the left of the one being removed.
2158
2159     \value SelectRightTab  Select the tab to the right of the one being removed.
2160
2161     \value SelectPreviousTab  Select the previously selected tab.
2162
2163 */
2164
2165 /*!
2166     \property QTabBar::selectionBehaviorOnRemove
2167     \brief What tab should be set as current when removeTab is called if
2168     the removed tab is also the current tab.
2169     \since 4.5
2170
2171     By default the value is SelectRightTab.
2172
2173     \sa removeTab()
2174 */
2175
2176
2177 QTabBar::SelectionBehavior QTabBar::selectionBehaviorOnRemove() const
2178 {
2179     Q_D(const QTabBar);
2180     return d->selectionBehaviorOnRemove;
2181 }
2182
2183 void QTabBar::setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior behavior)
2184 {
2185     Q_D(QTabBar);
2186     d->selectionBehaviorOnRemove = behavior;
2187 }
2188
2189 /*!
2190     \property QTabBar::expanding
2191     \brief When expanding is true QTabBar will expand the tabs to use the empty space.
2192     \since 4.5
2193
2194     By default the value is true.
2195
2196     \sa QTabWidget::documentMode
2197 */
2198
2199 bool QTabBar::expanding() const
2200 {
2201     Q_D(const QTabBar);
2202     return d->expanding;
2203 }
2204
2205 void QTabBar::setExpanding(bool enabled)
2206 {
2207     Q_D(QTabBar);
2208     if (d->expanding == enabled)
2209         return;
2210     d->expanding = enabled;
2211     d->layoutTabs();
2212 }
2213
2214 /*!
2215     \property QTabBar::movable
2216     \brief This property holds whether the user can move the tabs
2217     within the tabbar area.
2218
2219     \since 4.5
2220
2221     By default, this property is false;
2222 */
2223
2224 bool QTabBar::isMovable() const
2225 {
2226     Q_D(const QTabBar);
2227     return d->movable;
2228 }
2229
2230 void QTabBar::setMovable(bool movable)
2231 {
2232     Q_D(QTabBar);
2233     d->movable = movable;
2234 }
2235
2236
2237 /*!
2238     \property QTabBar::documentMode
2239     \brief Whether or not the tab bar is rendered in a mode suitable for the main window.
2240     \since 4.5
2241
2242     This property is used as a hint for styles to draw the tabs in a different
2243     way then they would normally look in a tab widget.  On Mac OS X this will
2244     look similar to the tabs in Safari or Leopard's Terminal.app.
2245
2246     \sa QTabWidget::documentMode
2247 */
2248 bool QTabBar::documentMode() const
2249 {
2250     return d_func()->documentMode;
2251 }
2252
2253 void QTabBar::setDocumentMode(bool enabled)
2254 {
2255     Q_D(QTabBar);
2256
2257     d->documentMode = enabled;
2258     d->updateMacBorderMetrics();
2259 }
2260
2261 /*!
2262     Sets \a widget on the tab \a index.  The widget is placed
2263     on the left or right hand side depending upon the \a position.
2264     \since 4.5
2265
2266     Any previously set widget in \a position is hidden.
2267
2268     The tab bar will take ownership of the widget and so all widgets set here
2269     will be deleted by the tab bar when it is destroyed unless you separately
2270     reparent the widget after setting some other widget (or 0).
2271
2272     \sa tabsClosable()
2273   */
2274 void QTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget)
2275 {
2276     Q_D(QTabBar);
2277     if (index < 0 || index >= d->tabList.count())
2278         return;
2279     if (widget) {
2280         widget->setParent(this);
2281         // make sure our left and right widgets stay on top
2282         widget->lower();
2283         widget->show();
2284     }
2285     if (position == LeftSide) {
2286         if (d->tabList[index].leftWidget)
2287             d->tabList[index].leftWidget->hide();
2288         d->tabList[index].leftWidget = widget;
2289     } else {
2290         if (d->tabList[index].rightWidget)
2291             d->tabList[index].rightWidget->hide();
2292         d->tabList[index].rightWidget = widget;
2293     }
2294     d->layoutTabs();
2295     d->refresh();
2296     update();
2297 }
2298
2299 /*!
2300     Returns the widget set a tab \a index and \a position or 0 if
2301     one is not set.
2302   */
2303 QWidget *QTabBar::tabButton(int index, ButtonPosition position) const
2304 {
2305     Q_D(const QTabBar);
2306     if (index < 0 || index >= d->tabList.count())
2307         return 0;
2308     if (position == LeftSide)
2309         return d->tabList.at(index).leftWidget;
2310     else
2311         return d->tabList.at(index).rightWidget;
2312 }
2313
2314 CloseButton::CloseButton(QWidget *parent)
2315     : QAbstractButton(parent)
2316 {
2317     setFocusPolicy(Qt::NoFocus);
2318 #ifndef QT_NO_CURSOR
2319     setCursor(Qt::ArrowCursor);
2320 #endif
2321 #ifndef QT_NO_TOOLTIP
2322     setToolTip(tr("Close Tab"));
2323 #endif
2324     resize(sizeHint());
2325 }
2326
2327 QSize CloseButton::sizeHint() const
2328 {
2329     ensurePolished();
2330     int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
2331     int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
2332     return QSize(width, height);
2333 }
2334
2335 void CloseButton::enterEvent(QEvent *event)
2336 {
2337     if (isEnabled())
2338         update();
2339     QAbstractButton::enterEvent(event);
2340 }
2341
2342 void CloseButton::leaveEvent(QEvent *event)
2343 {
2344     if (isEnabled())
2345         update();
2346     QAbstractButton::leaveEvent(event);
2347 }
2348
2349 void CloseButton::paintEvent(QPaintEvent *)
2350 {
2351     QPainter p(this);
2352     QStyleOption opt;
2353     opt.init(this);
2354     opt.state |= QStyle::State_AutoRaise;
2355     if (isEnabled() && underMouse() && !isChecked() && !isDown())
2356         opt.state |= QStyle::State_Raised;
2357     if (isChecked())
2358         opt.state |= QStyle::State_On;
2359     if (isDown())
2360         opt.state |= QStyle::State_Sunken;
2361
2362     if (const QTabBar *tb = qobject_cast<const QTabBar *>(parent())) {
2363         int index = tb->currentIndex();
2364         QTabBar::ButtonPosition position = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb);
2365         if (tb->tabButton(index, position) == this)
2366             opt.state |= QStyle::State_Selected;
2367     }
2368
2369     style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
2370 }
2371
2372 QT_END_NAMESPACE
2373
2374 #include "moc_qtabbar.cpp"
2375
2376 #endif // QT_NO_TABBAR