source: trunk/src/gui/widgets/qtabwidget.cpp@ 1117

Last change on this file since 1117 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 39.7 KB
Line 
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtabwidget.h"
43
44#ifndef QT_NO_TABWIDGET
45#include "private/qwidget_p.h"
46#include "private/qtabbar_p.h"
47#include "qapplication.h"
48#include "qbitmap.h"
49#include "qdesktopwidget.h"
50#include "qevent.h"
51#include "qlayout.h"
52#include "qstackedwidget.h"
53#include "qstyle.h"
54#include "qstyleoption.h"
55#include "qstylepainter.h"
56#include "qtabbar.h"
57#include "qtoolbutton.h"
58
59QT_BEGIN_NAMESPACE
60
61/*!
62 \class QTabWidget
63 \brief The QTabWidget class provides a stack of tabbed widgets.
64
65 \ingroup organizers
66 \ingroup basicwidgets
67
68
69 A tab widget provides a tab bar (see QTabBar) and a "page area"
70 that is used to display pages related to each tab. By default, the
71 tab bar is shown above the page area, but different configurations
72 are available (see \l{TabPosition}). Each tab is associated with a
73 different widget (called a page). Only the current page is shown in
74 the page area; all the other pages are hidden. The user can show a
75 different page by clicking on its tab or by pressing its
76 Alt+\e{letter} shortcut if it has one.
77
78 The normal way to use QTabWidget is to do the following:
79 \list 1
80 \i Create a QTabWidget.
81 \i Create a QWidget for each of the pages in the tab dialog, but
82 do not specify parent widgets for them.
83 \i Insert child widgets into the page widget, using layouts to
84 position them as normal.
85 \i Call addTab() or insertTab() to put the page widgets into the
86 tab widget, giving each tab a suitable label with an optional
87 keyboard shortcut.
88 \endlist
89
90 The position of the tabs is defined by \l tabPosition, their shape
91 by \l tabShape.
92
93 The signal currentChanged() is emitted when the user selects a
94 page.
95
96 The current page index is available as currentIndex(), the current
97 page widget with currentWidget(). You can retrieve a pointer to a
98 page widget with a given index using widget(), and can find the
99 index position of a widget with indexOf(). Use setCurrentWidget()
100 or setCurrentIndex() to show a particular page.
101
102 You can change a tab's text and icon using setTabText() or
103 setTabIcon(). A tab and its associated page can be removed with
104 removeTab().
105
106 Each tab is either enabled or disabled at any given time (see
107 setTabEnabled()). If a tab is enabled, the tab text is drawn
108 normally and the user can select that tab. If it is disabled, the
109 tab is drawn in a different way and the user cannot select that
110 tab. Note that even if a tab is disabled, the page can still be
111 visible, for example if all of the tabs happen to be disabled.
112
113 Tab widgets can be a very good way to split up a complex dialog.
114 An alternative is to use a QStackedWidget for which you provide some
115 means of navigating between pages, for example, a QToolBar or a
116 QListWidget.
117
118 Most of the functionality in QTabWidget is provided by a QTabBar
119 (at the top, providing the tabs) and a QStackedWidget (most of the
120 area, organizing the individual pages).
121
122 \table 100%
123 \row \o \inlineimage windowsxp-tabwidget.png Screenshot of a Windows XP style tab widget
124 \o \inlineimage macintosh-tabwidget.png Screenshot of a Macintosh style tab widget
125 \o \inlineimage plastique-tabwidget.png Screenshot of a Plastique style tab widget
126 \row \o A Windows XP style tab widget.
127 \o A Macintosh style tab widget.
128 \o A Plastique style tab widget.
129 \endtable
130
131 \sa QTabBar, QStackedWidget, QToolBox, {Tab Dialog Example}
132*/
133
134/*!
135 \enum QTabWidget::TabPosition
136
137 This enum type defines where QTabWidget draws the tab row:
138
139 \value North The tabs are drawn above the pages.
140 \value South The tabs are drawn below the pages.
141 \value West The tabs are drawn to the left of the pages.
142 \value East The tabs are drawn to the right of the pages.
143 \omitvalue Bottom
144 \omitvalue Top
145*/
146
147/*!
148 \enum QTabWidget::TabShape
149
150 This enum type defines the shape of the tabs:
151 \value Rounded The tabs are drawn with a rounded look. This is the default
152 shape.
153 \value Triangular The tabs are drawn with a triangular look.
154*/
155
156/*!
157 \fn void QTabWidget::selected(const QString &tabLabel)
158
159 This signal is emitted whenever a tab is selected (raised),
160 including during the first show().
161
162 You can normally use currentChanged() instead.
163*/
164
165/*!
166 \fn void QTabWidget::currentChanged(int index)
167
168 This signal is emitted whenever the current page index changes.
169 The parameter is the new current page \a index position, or -1
170 if there isn't a new one (for example, if there are no widgets
171 in the QTabWidget)
172
173 \sa currentWidget() currentIndex
174*/
175
176/*!
177 \fn void QTabWidget::tabCloseRequested(int index)
178 \since 4.5
179
180 This signal is emitted when the close button on a tab is clicked.
181 The \a index is the index that should be removed.
182
183 \sa setTabsClosable()
184*/
185
186class QTabWidgetPrivate : public QWidgetPrivate
187{
188 Q_DECLARE_PUBLIC(QTabWidget)
189
190public:
191 QTabWidgetPrivate();
192 ~QTabWidgetPrivate();
193 void updateTabBarPosition();
194 void _q_showTab(int);
195 void _q_removeTab(int);
196 void _q_tabMoved(int from, int to);
197 void init();
198
199 QTabBar *tabs;
200 QStackedWidget *stack;
201 QRect panelRect;
202 bool dirty;
203 QTabWidget::TabPosition pos;
204 QTabWidget::TabShape shape;
205 int alignment;
206 QWidget *leftCornerWidget;
207 QWidget *rightCornerWidget;
208};
209
210QTabWidgetPrivate::QTabWidgetPrivate()
211 : tabs(0), stack(0), dirty(true),
212 pos(QTabWidget::North), shape(QTabWidget::Rounded),
213 leftCornerWidget(0), rightCornerWidget(0)
214{}
215
216QTabWidgetPrivate::~QTabWidgetPrivate()
217{}
218
219void QTabWidgetPrivate::init()
220{
221 Q_Q(QTabWidget);
222
223 stack = new QStackedWidget(q);
224 stack->setObjectName(QLatin1String("qt_tabwidget_stackedwidget"));
225 stack->setLineWidth(0);
226 // hack so that QMacStyle::layoutSpacing() can detect tab widget pages
227 stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::TabWidget));
228
229 QObject::connect(stack, SIGNAL(widgetRemoved(int)), q, SLOT(_q_removeTab(int)));
230 QTabBar *tabBar = new QTabBar(q);
231 tabBar->setObjectName(QLatin1String("qt_tabwidget_tabbar"));
232 tabBar->setDrawBase(false);
233 q->setTabBar(tabBar);
234
235 q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding,
236 QSizePolicy::TabWidget));
237#ifdef QT_KEYPAD_NAVIGATION
238 if (QApplication::keypadNavigationEnabled())
239 q->setFocusPolicy(Qt::NoFocus);
240 else
241#endif
242 q->setFocusPolicy(Qt::TabFocus);
243 q->setFocusProxy(tabs);
244 q->setTabPosition(static_cast<QTabWidget::TabPosition> (q->style()->styleHint(
245 QStyle::SH_TabWidget_DefaultTabPosition, 0, q )));
246
247}
248
249/*!
250 Initialize \a option with the values from this QTabWidget. This method is useful
251 for subclasses when they need a QStyleOptionTabWidgetFrame, but don't want to fill
252 in all the information themselves.
253
254 \sa QStyleOption::initFrom() QTabBar::initStyleOption()
255*/
256void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const
257{
258 if (!option)
259 return;
260
261 Q_D(const QTabWidget);
262 option->initFrom(this);
263
264 if (documentMode())
265 option->lineWidth = 0;
266 else
267 option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this);
268
269 int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0, this);
270 QSize t(0, d->stack->frameWidth());
271 if (d->tabs->isVisibleTo(const_cast<QTabWidget *>(this))) {
272 t = d->tabs->sizeHint();
273 if (documentMode()) {
274 if (tabPosition() == East || tabPosition() == West) {
275 t.setHeight(height());
276 } else {
277 t.setWidth(width());
278 }
279 }
280 }
281
282 if (d->rightCornerWidget) {
283 const QSize rightCornerSizeHint = d->rightCornerWidget->sizeHint();
284 const QSize bounds(rightCornerSizeHint.width(), t.height() - exth);
285 option->rightCornerWidgetSize = rightCornerSizeHint.boundedTo(bounds);
286 } else {
287 option->rightCornerWidgetSize = QSize(0, 0);
288 }
289
290 if (d->leftCornerWidget) {
291 const QSize leftCornerSizeHint = d->leftCornerWidget->sizeHint();
292 const QSize bounds(leftCornerSizeHint.width(), t.height() - exth);
293 option->leftCornerWidgetSize = leftCornerSizeHint.boundedTo(bounds);
294 } else {
295 option->leftCornerWidgetSize = QSize(0, 0);
296 }
297
298 switch (d->pos) {
299 case QTabWidget::North:
300 option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedNorth
301 : QTabBar::TriangularNorth;
302 break;
303 case QTabWidget::South:
304 option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedSouth
305 : QTabBar::TriangularSouth;
306 break;
307 case QTabWidget::West:
308 option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedWest
309 : QTabBar::TriangularWest;
310 break;
311 case QTabWidget::East:
312 option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedEast
313 : QTabBar::TriangularEast;
314 break;
315 }
316
317 option->tabBarSize = t;
318
319 if (QStyleOptionTabWidgetFrameV2 *tabframe = qstyleoption_cast<QStyleOptionTabWidgetFrameV2*>(option)) {
320 QRect tbRect = tabBar()->geometry();
321 QRect selectedTabRect = tabBar()->tabRect(tabBar()->currentIndex());
322 tabframe->tabBarRect = tbRect;
323 selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + tbRect.topLeft());
324 tabframe->selectedTabRect = selectedTabRect;
325 }
326}
327
328/*!
329 Constructs a tabbed widget with parent \a parent.
330*/
331QTabWidget::QTabWidget(QWidget *parent)
332 : QWidget(*new QTabWidgetPrivate, parent, 0)
333{
334 Q_D(QTabWidget);
335 d->init();
336}
337
338#ifdef QT3_SUPPORT
339/*!
340 Use one of the constructors that doesn't take the \a name
341 argument and then use setObjectName() instead.
342*/
343QTabWidget::QTabWidget(QWidget *parent, const char *name, Qt::WindowFlags f)
344 : QWidget(*new QTabWidgetPrivate, parent, f)
345{
346 Q_D(QTabWidget);
347 setObjectName(QString::fromAscii(name));
348 d->init();
349}
350#endif
351
352/*!
353 Destroys the tabbed widget.
354*/
355QTabWidget::~QTabWidget()
356{
357}
358
359/*!
360 \fn int QTabWidget::addTab(QWidget *page, const QString &label)
361
362 Adds a tab with the given \a page and \a label to the tab widget,
363 and returns the index of the tab in the tab bar.
364
365 If the tab's \a label contains an ampersand, the letter following
366 the ampersand is used as a shortcut for the tab, e.g. if the
367 label is "Bro\&wse" then Alt+W becomes a shortcut which will
368 move the focus to this tab.
369
370 \note If you call addTab() after show(), the layout system will try
371 to adjust to the changes in its widgets hierarchy and may cause
372 flicker. To prevent this, you can set the QWidget::updatesEnabled
373 property to false prior to changes; remember to set the property
374 to true when the changes are done, making the widget receive paint
375 events again.
376
377 \sa insertTab()
378*/
379int QTabWidget::addTab(QWidget *child, const QString &label)
380{
381 return insertTab(-1, child, label);
382}
383
384
385/*!
386 \fn int QTabWidget::addTab(QWidget *page, const QIcon &icon, const QString &label)
387 \overload
388
389 Adds a tab with the given \a page, \a icon, and \a label to the tab
390 widget, and returns the index of the tab in the tab bar.
391
392 This function is the same as addTab(), but with an additional \a
393 icon.
394*/
395int QTabWidget::addTab(QWidget *child, const QIcon& icon, const QString &label)
396{
397 return insertTab(-1, child, icon, label);
398}
399
400
401/*!
402 \fn int QTabWidget::insertTab(int index, QWidget *page, const QString &label)
403
404 Inserts a tab with the given \a label and \a page into the tab
405 widget at the specified \a index, and returns the index of the
406 inserted tab in the tab bar.
407
408 The label is displayed in the tab and may vary in appearance depending
409 on the configuration of the tab widget.
410
411 If the tab's \a label contains an ampersand, the letter following
412 the ampersand is used as a shortcut for the tab, e.g. if the
413 label is "Bro\&wse" then Alt+W becomes a shortcut which will
414 move the focus to this tab.
415
416 If \a index is out of range, the tab is simply appended.
417 Otherwise it is inserted at the specified position.
418
419 If the QTabWidget was empty before this function is called, the
420 new page becomes the current page. Inserting a new tab at an index
421 less than or equal to the current index will increment the current
422 index, but keep the current page.
423
424 \note If you call insertTab() after show(), the layout system will try
425 to adjust to the changes in its widgets hierarchy and may cause
426 flicker. To prevent this, you can set the QWidget::updatesEnabled
427 property to false prior to changes; remember to set the property
428 to true when the changes are done, making the widget receive paint
429 events again.
430
431 \sa addTab()
432*/
433int QTabWidget::insertTab(int index, QWidget *w, const QString &label)
434{
435 return insertTab(index, w, QIcon(), label);
436}
437
438
439/*!
440 \fn int QTabWidget::insertTab(int index, QWidget *page, const QIcon& icon, const QString &label)
441 \overload
442
443 Inserts a tab with the given \a label, \a page, and \a icon into
444 the tab widget at the specified \a index, and returns the index of the
445 inserted tab in the tab bar.
446
447 This function is the same as insertTab(), but with an additional
448 \a icon.
449*/
450int QTabWidget::insertTab(int index, QWidget *w, const QIcon& icon, const QString &label)
451{
452 Q_D(QTabWidget);
453 if(!w)
454 return -1;
455 index = d->stack->insertWidget(index, w);
456 d->tabs->insertTab(index, icon, label);
457 setUpLayout();
458 tabInserted(index);
459
460 return index;
461}
462
463
464/*!
465 Defines a new \a label for the page at position \a index's tab.
466
467 If the provided text contains an ampersand character ('&'), a
468 shortcut is automatically created for it. The character that
469 follows the '&' will be used as the shortcut key. Any previous
470 shortcut will be overwritten, or cleared if no shortcut is defined
471 by the text. See the \l {QShortcut#mnemonic}{QShortcut}
472 documentation for details (to display an actual ampersand, use
473 '&&').
474
475*/
476void QTabWidget::setTabText(int index, const QString &label)
477{
478 Q_D(QTabWidget);
479 d->tabs->setTabText(index, label);
480 setUpLayout();
481}
482
483/*!
484 Returns the label text for the tab on the page at position \a index.
485*/
486
487QString QTabWidget::tabText(int index) const
488{
489 Q_D(const QTabWidget);
490 return d->tabs->tabText(index);
491}
492
493/*!
494 \overload
495
496 Sets the \a icon for the tab at position \a index.
497*/
498void QTabWidget::setTabIcon(int index, const QIcon &icon)
499{
500 Q_D(QTabWidget);
501 d->tabs->setTabIcon(index, icon);
502 setUpLayout();
503}
504
505/*!
506 Returns the icon for the tab on the page at position \a index.
507*/
508
509QIcon QTabWidget::tabIcon(int index) const
510{
511 Q_D(const QTabWidget);
512 return d->tabs->tabIcon(index);
513}
514
515/*!
516 Returns true if the page at position \a index is enabled; otherwise returns false.
517
518 \sa setTabEnabled(), QWidget::isEnabled()
519*/
520
521bool QTabWidget::isTabEnabled(int index) const
522{
523 Q_D(const QTabWidget);
524 return d->tabs->isTabEnabled(index);
525}
526
527/*!
528 If \a enable is true, the page at position \a index is enabled; otherwise the page at position \a index is
529 disabled. The page's tab is redrawn appropriately.
530
531 QTabWidget uses QWidget::setEnabled() internally, rather than
532 keeping a separate flag.
533
534 Note that even a disabled tab/page may be visible. If the page is
535 visible already, QTabWidget will not hide it; if all the pages are
536 disabled, QTabWidget will show one of them.
537
538 \sa isTabEnabled(), QWidget::setEnabled()
539*/
540
541void QTabWidget::setTabEnabled(int index, bool enable)
542{
543 Q_D(QTabWidget);
544 d->tabs->setTabEnabled(index, enable);
545 if (QWidget *widget = d->stack->widget(index))
546 widget->setEnabled(enable);
547}
548
549/*!
550 \fn void QTabWidget::setCornerWidget(QWidget *widget, Qt::Corner corner)
551
552 Sets the given \a widget to be shown in the specified \a corner of the
553 tab widget. The geometry of the widget is determined based on the widget's
554 sizeHint() and the style().
555
556 Only the horizontal element of the \a corner will be used.
557
558 Passing 0 shows no widget in the corner.
559
560 Any previously set corner widget is hidden.
561
562 All widgets set here will be deleted by the tab widget when it is
563 destroyed unless you separately reparent the widget after setting
564 some other corner widget (or 0).
565
566 Note: Corner widgets are designed for \l North and \l South tab positions;
567 other orientations are known to not work properly.
568
569 \sa cornerWidget(), setTabPosition()
570*/
571void QTabWidget::setCornerWidget(QWidget * widget, Qt::Corner corner)
572{
573 Q_D(QTabWidget);
574 if (widget && widget->parentWidget() != this)
575 widget->setParent(this);
576
577 if (corner & Qt::TopRightCorner) {
578 if (d->rightCornerWidget)
579 d->rightCornerWidget->hide();
580 d->rightCornerWidget = widget;
581 } else {
582 if (d->leftCornerWidget)
583 d->leftCornerWidget->hide();
584 d->leftCornerWidget = widget;
585 }
586 setUpLayout();
587}
588
589/*!
590 Returns the widget shown in the \a corner of the tab widget or 0.
591*/
592QWidget * QTabWidget::cornerWidget(Qt::Corner corner) const
593{
594 Q_D(const QTabWidget);
595 if (corner & Qt::TopRightCorner)
596 return d->rightCornerWidget;
597 return d->leftCornerWidget;
598}
599
600/*!
601 Removes the tab at position \a index from this stack of widgets.
602 The page widget itself is not deleted.
603
604 \sa addTab(), insertTab()
605*/
606void QTabWidget::removeTab(int index)
607{
608 Q_D(QTabWidget);
609 if (QWidget *w = d->stack->widget(index))
610 d->stack->removeWidget(w);
611}
612
613/*!
614 Returns a pointer to the page currently being displayed by the tab
615 dialog. The tab dialog does its best to make sure that this value
616 is never 0 (but if you try hard enough, it can be).
617
618 \sa currentIndex(), setCurrentWidget()
619*/
620
621QWidget * QTabWidget::currentWidget() const
622{
623 Q_D(const QTabWidget);
624 return d->stack->currentWidget();
625}
626
627/*!
628 Makes \a widget the current widget. The \a widget used must be a page in
629 this tab widget.
630
631 \sa addTab(), setCurrentIndex(), currentWidget()
632 */
633void QTabWidget::setCurrentWidget(QWidget *widget)
634{
635 Q_D(const QTabWidget);
636 d->tabs->setCurrentIndex(indexOf(widget));
637}
638
639
640/*!
641 \property QTabWidget::currentIndex
642 \brief the index position of the current tab page
643
644 The current index is -1 if there is no current widget.
645
646 By default, this property contains a value of -1 because there are initially
647 no tabs in the widget.
648*/
649
650int QTabWidget::currentIndex() const
651{
652 Q_D(const QTabWidget);
653 return d->tabs->currentIndex();
654}
655
656void QTabWidget::setCurrentIndex(int index)
657{
658 Q_D(QTabWidget);
659 d->tabs->setCurrentIndex(index);
660}
661
662
663/*!
664 Returns the index position of the page occupied by the widget \a
665 w, or -1 if the widget cannot be found.
666*/
667int QTabWidget::indexOf(QWidget* w) const
668{
669 Q_D(const QTabWidget);
670 return d->stack->indexOf(w);
671}
672
673
674/*!
675 \reimp
676*/
677void QTabWidget::resizeEvent(QResizeEvent *e)
678{
679 QWidget::resizeEvent(e);
680 setUpLayout();
681}
682
683/*!
684 Replaces the dialog's QTabBar heading with the tab bar \a tb. Note
685 that this must be called \e before any tabs have been added, or
686 the behavior is undefined.
687
688 \sa tabBar()
689*/
690void QTabWidget::setTabBar(QTabBar* tb)
691{
692 Q_D(QTabWidget);
693 Q_ASSERT(tb);
694
695 if (tb->parentWidget() != this) {
696 tb->setParent(this);
697 tb->show();
698 }
699 delete d->tabs;
700 d->tabs = tb;
701 setFocusProxy(d->tabs);
702 connect(d->tabs, SIGNAL(currentChanged(int)),
703 this, SLOT(_q_showTab(int)));
704 connect(d->tabs, SIGNAL(tabMoved(int,int)),
705 this, SLOT(_q_tabMoved(int,int)));
706 if (d->tabs->tabsClosable())
707 connect(d->tabs, SIGNAL(tabCloseRequested(int)),
708 this, SIGNAL(tabCloseRequested(int)));
709 tb->setExpanding(!documentMode());
710 setUpLayout();
711}
712
713
714/*!
715 Returns the current QTabBar.
716
717 \sa setTabBar()
718*/
719QTabBar* QTabWidget::tabBar() const
720{
721 Q_D(const QTabWidget);
722 return d->tabs;
723}
724
725/*!
726 Ensures that the selected tab's page is visible and appropriately
727 sized.
728*/
729
730void QTabWidgetPrivate::_q_showTab(int index)
731{
732 Q_Q(QTabWidget);
733 if (index < stack->count() && index >= 0)
734 stack->setCurrentIndex(index);
735 emit q->currentChanged(index);
736#ifdef QT3_SUPPORT
737 emit q->selected(q->tabText(index));
738 emit q->currentChanged(stack->widget(index));
739#endif
740}
741
742void QTabWidgetPrivate::_q_removeTab(int index)
743{
744 Q_Q(QTabWidget);
745 tabs->removeTab(index);
746 q->setUpLayout();
747 q->tabRemoved(index);
748}
749
750void QTabWidgetPrivate::_q_tabMoved(int from, int to)
751{
752 stack->blockSignals(true);
753 QWidget *w = stack->widget(from);
754 stack->removeWidget(w);
755 stack->insertWidget(to, w);
756 stack->blockSignals(false);
757}
758
759/*
760 Set up the layout.
761 Get subrect from the current style, and set the geometry for the
762 stack widget, tab bar and corner widgets.
763*/
764void QTabWidget::setUpLayout(bool onlyCheck)
765{
766 Q_D(QTabWidget);
767 if (onlyCheck && !d->dirty)
768 return; // nothing to do
769
770 QStyleOptionTabWidgetFrameV2 option;
771 initStyleOption(&option);
772
773 // this must be done immediately, because QWidgetItem relies on it (even if !isVisible())
774 d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option);
775
776 if (!isVisible()) {
777 d->dirty = true;
778 return; // we'll do it later
779 }
780
781 QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this);
782 d->panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
783 QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this);
784 QRect leftCornerRect = style()->subElementRect(QStyle::SE_TabWidgetLeftCorner, &option, this);
785 QRect rightCornerRect = style()->subElementRect(QStyle::SE_TabWidgetRightCorner, &option, this);
786
787 d->tabs->setGeometry(tabRect);
788 d->stack->setGeometry(contentsRect);
789 if (d->leftCornerWidget)
790 d->leftCornerWidget->setGeometry(leftCornerRect);
791 if (d->rightCornerWidget)
792 d->rightCornerWidget->setGeometry(rightCornerRect);
793
794 if (!onlyCheck)
795 update();
796 updateGeometry();
797}
798
799/*!
800 \internal
801*/
802static inline QSize basicSize(
803 bool horizontal, const QSize &lc, const QSize &rc, const QSize &s, const QSize &t)
804{
805 return horizontal
806 ? QSize(qMax(s.width(), t.width() + rc.width() + lc.width()),
807 s.height() + (qMax(rc.height(), qMax(lc.height(), t.height()))))
808 : QSize(s.width() + (qMax(rc.width(), qMax(lc.width(), t.width()))),
809 qMax(s.height(), t.height() + rc.height() + lc.height()));
810}
811
812/*!
813 \reimp
814*/
815QSize QTabWidget::sizeHint() const
816{
817 Q_D(const QTabWidget);
818 QSize lc(0, 0), rc(0, 0);
819 QStyleOption opt(0);
820 opt.init(this);
821 opt.state = QStyle::State_None;
822
823 if (d->leftCornerWidget)
824 lc = d->leftCornerWidget->sizeHint();
825 if(d->rightCornerWidget)
826 rc = d->rightCornerWidget->sizeHint();
827 if (!d->dirty) {
828 QTabWidget *that = (QTabWidget*)this;
829 that->setUpLayout(true);
830 }
831 QSize s(d->stack->sizeHint());
832 QSize t(d->tabs->sizeHint());
833 if(usesScrollButtons())
834 t = t.boundedTo(QSize(200,200));
835 else
836 t = t.boundedTo(QApplication::desktop()->size());
837
838 QSize sz = basicSize(d->pos == North || d->pos == South, lc, rc, s, t);
839
840 return style()->sizeFromContents(QStyle::CT_TabWidget, &opt, sz, this)
841 .expandedTo(QApplication::globalStrut());
842}
843
844
845/*!
846 \reimp
847
848 Returns a suitable minimum size for the tab widget.
849*/
850QSize QTabWidget::minimumSizeHint() const
851{
852 Q_D(const QTabWidget);
853 QSize lc(0, 0), rc(0, 0);
854
855 if(d->leftCornerWidget)
856 lc = d->leftCornerWidget->minimumSizeHint();
857 if(d->rightCornerWidget)
858 rc = d->rightCornerWidget->minimumSizeHint();
859 if (!d->dirty) {
860 QTabWidget *that = (QTabWidget*)this;
861 that->setUpLayout(true);
862 }
863 QSize s(d->stack->minimumSizeHint());
864 QSize t(d->tabs->minimumSizeHint());
865
866 QSize sz = basicSize(d->pos == North || d->pos == South, lc, rc, s, t);
867
868 QStyleOption opt(0);
869 opt.rect = rect();
870 opt.palette = palette();
871 opt.state = QStyle::State_None;
872 return style()->sizeFromContents(QStyle::CT_TabWidget, &opt, sz, this)
873 .expandedTo(QApplication::globalStrut());
874}
875
876/*!
877 \reimp
878 */
879void QTabWidget::showEvent(QShowEvent *)
880{
881 setUpLayout();
882}
883
884void QTabWidgetPrivate::updateTabBarPosition()
885{
886 Q_Q(QTabWidget);
887 switch (pos) {
888 case QTabWidget::North:
889 tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedNorth
890 : QTabBar::TriangularNorth);
891 break;
892 case QTabWidget::South:
893 tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedSouth
894 : QTabBar::TriangularSouth);
895 break;
896 case QTabWidget::West:
897 tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedWest
898 : QTabBar::TriangularWest);
899 break;
900 case QTabWidget::East:
901 tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedEast
902 : QTabBar::TriangularEast);
903 break;
904 }
905 q->setUpLayout();
906}
907
908/*!
909 \property QTabWidget::tabPosition
910 \brief the position of the tabs in this tab widget
911
912 Possible values for this property are described by the TabPosition
913 enum.
914
915 By default, this property is set to \l North.
916
917 \sa TabPosition
918*/
919QTabWidget::TabPosition QTabWidget::tabPosition() const
920{
921 Q_D(const QTabWidget);
922 return d->pos;
923}
924
925void QTabWidget::setTabPosition(TabPosition pos)
926{
927 Q_D(QTabWidget);
928 if (d->pos == pos)
929 return;
930 d->pos = pos;
931 d->updateTabBarPosition();
932}
933
934/*!
935 \property QTabWidget::tabsClosable
936 \brief whether close buttons are automatically added to each tab.
937
938 \since 4.5
939
940 \sa QTabBar::tabsClosable()
941*/
942bool QTabWidget::tabsClosable() const
943{
944 return tabBar()->tabsClosable();
945}
946
947void QTabWidget::setTabsClosable(bool closeable)
948{
949 if (tabsClosable() == closeable)
950 return;
951
952 tabBar()->setTabsClosable(closeable);
953 if (closeable)
954 connect(tabBar(), SIGNAL(tabCloseRequested(int)),
955 this, SIGNAL(tabCloseRequested(int)));
956 else
957 disconnect(tabBar(), SIGNAL(tabCloseRequested(int)),
958 this, SIGNAL(tabCloseRequested(int)));
959 setUpLayout();
960}
961
962/*!
963 \property QTabWidget::movable
964 \brief This property holds whether the user can move the tabs
965 within the tabbar area.
966
967 \since 4.5
968
969 By default, this property is false;
970*/
971
972bool QTabWidget::isMovable() const
973{
974 return tabBar()->isMovable();
975}
976
977void QTabWidget::setMovable(bool movable)
978{
979 tabBar()->setMovable(movable);
980}
981
982/*!
983 \property QTabWidget::tabShape
984 \brief the shape of the tabs in this tab widget
985
986 Possible values for this property are QTabWidget::Rounded
987 (default) or QTabWidget::Triangular.
988
989 \sa TabShape
990*/
991
992QTabWidget::TabShape QTabWidget::tabShape() const
993{
994 Q_D(const QTabWidget);
995 return d->shape;
996}
997
998void QTabWidget::setTabShape(TabShape s)
999{
1000 Q_D(QTabWidget);
1001 if (d->shape == s)
1002 return;
1003 d->shape = s;
1004 d->updateTabBarPosition();
1005}
1006
1007/*!
1008 \reimp
1009 */
1010bool QTabWidget::event(QEvent *ev)
1011{
1012 if (ev->type() == QEvent::LayoutRequest)
1013 setUpLayout();
1014 return QWidget::event(ev);
1015}
1016
1017/*!
1018 \reimp
1019 */
1020void QTabWidget::changeEvent(QEvent *ev)
1021{
1022 if (ev->type() == QEvent::StyleChange
1023#ifdef Q_WS_MAC
1024 || ev->type() == QEvent::MacSizeChange
1025#endif
1026 )
1027 setUpLayout();
1028 QWidget::changeEvent(ev);
1029}
1030
1031
1032/*!
1033 \reimp
1034 */
1035void QTabWidget::keyPressEvent(QKeyEvent *e)
1036{
1037 Q_D(QTabWidget);
1038 if (((e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) &&
1039 count() > 1 && e->modifiers() & Qt::ControlModifier)
1040#ifdef QT_KEYPAD_NAVIGATION
1041 || QApplication::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right) && count() > 1
1042#endif
1043 ) {
1044 int pageCount = d->tabs->count();
1045 int page = currentIndex();
1046 int dx = (e->key() == Qt::Key_Backtab || e->modifiers() & Qt::ShiftModifier) ? -1 : 1;
1047#ifdef QT_KEYPAD_NAVIGATION
1048 if (QApplication::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
1049 dx = e->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1;
1050#endif
1051 for (int pass = 0; pass < pageCount; ++pass) {
1052 page+=dx;
1053 if (page < 0
1054#ifdef QT_KEYPAD_NAVIGATION
1055 && !e->isAutoRepeat()
1056#endif
1057 ) {
1058 page = count() - 1;
1059 } else if (page >= pageCount
1060#ifdef QT_KEYPAD_NAVIGATION
1061 && !e->isAutoRepeat()
1062#endif
1063 ) {
1064 page = 0;
1065 }
1066 if (d->tabs->isTabEnabled(page)) {
1067 setCurrentIndex(page);
1068 break;
1069 }
1070 }
1071 if (!QApplication::focusWidget())
1072 d->tabs->setFocus();
1073 } else {
1074 e->ignore();
1075 }
1076}
1077
1078/*!
1079 Returns the tab page at index position \a index or 0 if the \a
1080 index is out of range.
1081*/
1082QWidget *QTabWidget::widget(int index) const
1083{
1084 Q_D(const QTabWidget);
1085 return d->stack->widget(index);
1086}
1087
1088/*!
1089 \property QTabWidget::count
1090 \brief the number of tabs in the tab bar
1091
1092 By default, this property contains a value of 0.
1093*/
1094int QTabWidget::count() const
1095{
1096 Q_D(const QTabWidget);
1097 return d->tabs->count();
1098}
1099
1100#ifndef QT_NO_TOOLTIP
1101/*!
1102 Sets the tab tool tip for the page at position \a index to \a tip.
1103
1104 \sa tabToolTip()
1105*/
1106void QTabWidget::setTabToolTip(int index, const QString & tip)
1107{
1108 Q_D(QTabWidget);
1109 d->tabs->setTabToolTip(index, tip);
1110}
1111
1112/*!
1113 Returns the tab tool tip for the page at position \a index or
1114 an empty string if no tool tip has been set.
1115
1116 \sa setTabToolTip()
1117*/
1118QString QTabWidget::tabToolTip(int index) const
1119{
1120 Q_D(const QTabWidget);
1121 return d->tabs->tabToolTip(index);
1122}
1123#endif // QT_NO_TOOLTIP
1124
1125#ifndef QT_NO_WHATSTHIS
1126/*!
1127 \since 4.1
1128
1129 Sets the What's This help text for the page at position \a index
1130 to \a text.
1131*/
1132void QTabWidget::setTabWhatsThis(int index, const QString &text)
1133{
1134 Q_D(QTabWidget);
1135 d->tabs->setTabWhatsThis(index, text);
1136}
1137
1138/*!
1139 \since 4.1
1140
1141 Returns the What's This help text for the page at position \a index,
1142 or an empty string if no help text has been set.
1143*/
1144QString QTabWidget::tabWhatsThis(int index) const
1145{
1146 Q_D(const QTabWidget);
1147 return d->tabs->tabWhatsThis(index);
1148}
1149#endif // QT_NO_WHATSTHIS
1150
1151/*!
1152 This virtual handler is called after a new tab was added or
1153 inserted at position \a index.
1154
1155 \sa tabRemoved()
1156 */
1157void QTabWidget::tabInserted(int index)
1158{
1159 Q_UNUSED(index)
1160}
1161
1162/*!
1163 This virtual handler is called after a tab was removed from
1164 position \a index.
1165
1166 \sa tabInserted()
1167 */
1168void QTabWidget::tabRemoved(int index)
1169{
1170 Q_UNUSED(index)
1171}
1172
1173/*!
1174 \fn void QTabWidget::paintEvent(QPaintEvent *event)
1175
1176 Paints the tab widget's tab bar in response to the paint \a event.
1177*/
1178void QTabWidget::paintEvent(QPaintEvent *)
1179{
1180 Q_D(QTabWidget);
1181 if (documentMode()) {
1182 QStylePainter p(this, tabBar());
1183 if (QWidget *w = cornerWidget(Qt::TopLeftCorner)) {
1184 QStyleOptionTabBarBaseV2 opt;
1185 QTabBarPrivate::initStyleBaseOption(&opt, tabBar(), w->size());
1186 opt.rect.moveLeft(w->x() + opt.rect.x());
1187 opt.rect.moveTop(w->y() + opt.rect.y());
1188 p.drawPrimitive(QStyle::PE_FrameTabBarBase, opt);
1189 }
1190 if (QWidget *w = cornerWidget(Qt::TopRightCorner)) {
1191 QStyleOptionTabBarBaseV2 opt;
1192 QTabBarPrivate::initStyleBaseOption(&opt, tabBar(), w->size());
1193 opt.rect.moveLeft(w->x() + opt.rect.x());
1194 opt.rect.moveTop(w->y() + opt.rect.y());
1195 p.drawPrimitive(QStyle::PE_FrameTabBarBase, opt);
1196 }
1197 return;
1198 }
1199 QStylePainter p(this);
1200
1201 QStyleOptionTabWidgetFrameV2 opt;
1202 initStyleOption(&opt);
1203 opt.rect = d->panelRect;
1204 p.drawPrimitive(QStyle::PE_FrameTabWidget, opt);
1205}
1206
1207/*!
1208 \property QTabWidget::iconSize
1209 \brief The size for icons in the tab bar
1210 \since 4.2
1211
1212 The default value is style-dependent. This is the maximum size
1213 that the icons will have. Icons are not scaled up if they are of
1214 smaller size.
1215
1216 \sa QTabBar::iconSize
1217*/
1218QSize QTabWidget::iconSize() const
1219{
1220 return d_func()->tabs->iconSize();
1221}
1222
1223void QTabWidget::setIconSize(const QSize &size)
1224{
1225 d_func()->tabs->setIconSize(size);
1226}
1227
1228/*!
1229 \property QTabWidget::elideMode
1230 \brief how to elide text in the tab bar
1231 \since 4.2
1232
1233 This property controls how items are elided when there is not
1234 enough space to show them for a given tab bar size.
1235
1236 By default the value is style dependant.
1237
1238 \sa QTabBar::elideMode usesScrollButtons QStyle::SH_TabBar_ElideMode
1239*/
1240Qt::TextElideMode QTabWidget::elideMode() const
1241{
1242 return d_func()->tabs->elideMode();
1243}
1244
1245void QTabWidget::setElideMode(Qt::TextElideMode mode)
1246{
1247 d_func()->tabs->setElideMode(mode);
1248}
1249
1250/*!
1251 \property QTabWidget::usesScrollButtons
1252 \brief Whether or not a tab bar should use buttons to scroll tabs when it
1253 has many tabs.
1254 \since 4.2
1255
1256 When there are too many tabs in a tab bar for its size, the tab bar can either choose
1257 to expand its size or to add buttons that allow you to scroll through the tabs.
1258
1259 By default the value is style dependant.
1260
1261 \sa elideMode QTabBar::usesScrollButtons QStyle::SH_TabBar_PreferNoArrows
1262*/
1263bool QTabWidget::usesScrollButtons() const
1264{
1265 return d_func()->tabs->usesScrollButtons();
1266}
1267
1268void QTabWidget::setUsesScrollButtons(bool useButtons)
1269{
1270 d_func()->tabs->setUsesScrollButtons(useButtons);
1271}
1272
1273/*!
1274 \property QTabWidget::documentMode
1275 \brief Whether or not the tab widget is rendered in a mode suitable for document
1276 pages. This is the same as document mode on Mac OS X.
1277 \since 4.5
1278
1279 When this property is set the tab widget frame is not rendered. This mode is useful
1280 for showing document-type pages where the page covers most of the tab widget
1281 area.
1282
1283 \sa elideMode, QTabBar::documentMode, QTabBar::usesScrollButtons, QStyle::SH_TabBar_PreferNoArrows
1284*/
1285bool QTabWidget::documentMode() const
1286{
1287 Q_D(const QTabWidget);
1288 return d->tabs->documentMode();
1289}
1290
1291void QTabWidget::setDocumentMode(bool enabled)
1292{
1293 Q_D(QTabWidget);
1294 d->tabs->setDocumentMode(enabled);
1295 d->tabs->setExpanding(!enabled);
1296 d->tabs->setDrawBase(enabled);
1297 setUpLayout();
1298}
1299
1300/*!
1301 Removes all the pages, but does not delete them. Calling this function
1302 is equivalent to calling removeTab() until the tab widget is empty.
1303*/
1304void QTabWidget::clear()
1305{
1306 // ### optimize by introduce QStackedLayout::clear()
1307 while (count())
1308 removeTab(0);
1309}
1310
1311/*!
1312 \fn void QTabWidget::insertTab(QWidget *widget, const QString &label, int index)
1313
1314 Use insertTab(index, widget, label) instead.
1315*/
1316
1317/*!
1318 \fn void QTabWidget::insertTab(QWidget *widget, const QIcon& icon, const QString &label, int index)
1319
1320 Use insertTab(index, widget, icon, label) instead.
1321*/
1322
1323/*!
1324 \fn void QTabWidget::changeTab(QWidget *widget, const QString
1325 &label)
1326
1327 Use setTabText() instead.
1328
1329*/
1330
1331/*!
1332 \fn void QTabWidget::changeTab(QWidget *widget, const QIcon& icon, const QString &label)
1333
1334 Use setTabText() and setTabIcon() instead.
1335*/
1336
1337/*!
1338 \fn bool QTabWidget::isTabEnabled( QWidget *widget) const
1339
1340 Use isTabEnabled(tabWidget->indexOf(widget)) instead.
1341*/
1342
1343/*!
1344 \fn void QTabWidget::setTabEnabled(QWidget *widget, bool b)
1345
1346 Use setTabEnabled(tabWidget->indexOf(widget), b) instead.
1347*/
1348
1349/*!
1350 \fn QString QTabWidget::tabLabel(QWidget *widget) const
1351
1352 Use tabText(tabWidget->indexOf(widget)) instead.
1353*/
1354
1355/*!
1356 \fn void QTabWidget::setTabLabel(QWidget *widget, const QString
1357 &label)
1358
1359 Use setTabText(tabWidget->indexOf(widget), label) instead.
1360*/
1361
1362/*!
1363 \fn QIcon QTabWidget::tabIconSet(QWidget * widget) const
1364
1365 Use tabIcon(tabWidget->indexOf(widget)) instead.
1366*/
1367
1368/*!
1369 \fn void QTabWidget::setTabIconSet(QWidget * widget, const QIcon & icon)
1370
1371 Use setTabIcon(tabWidget->indexOf(widget), icon) instead.
1372*/
1373
1374/*!
1375 \fn void QTabWidget::removeTabToolTip(QWidget * widget)
1376
1377 Use setTabToolTip(tabWidget->indexOf(widget), QString()) instead.
1378*/
1379
1380/*!
1381 \fn void QTabWidget::setTabToolTip(QWidget * widget, const QString & tip)
1382
1383 Use setTabToolTip(tabWidget->indexOf(widget), tip) instead.
1384*/
1385
1386/*!
1387 \fn QString QTabWidget::tabToolTip(QWidget * widget) const
1388
1389 Use tabToolTip(tabWidget->indexOf(widget)) instead.
1390*/
1391
1392/*!
1393 \fn QWidget * QTabWidget::currentPage() const
1394
1395 Use currentWidget() instead.
1396*/
1397
1398/*!
1399 \fn QWidget *QTabWidget::page(int index) const
1400
1401 Use widget() instead.
1402*/
1403
1404/*!
1405 \fn QString QTabWidget::label(int index) const
1406
1407 Use tabText() instead.
1408*/
1409
1410/*!
1411 \fn int QTabWidget::currentPageIndex() const
1412
1413 Use currentIndex() instead.
1414*/
1415
1416/*!
1417 \fn int QTabWidget::margin() const
1418
1419 This function is kept only to make old code compile.
1420 This functionality is no longer supported by QTabWidget.
1421
1422 \sa contentsRect(), setContentsMargins()
1423*/
1424
1425/*!
1426 \fn void QTabWidget::setMargin(int margin)
1427
1428 This function is kept only to make old code compile.
1429 This functionality is no longer supported by QTabWidget.
1430
1431 \sa contentsRect(), setContentsMargins()
1432*/
1433
1434/*!
1435 \fn void QTabWidget::setCurrentPage(int index)
1436
1437 Use setCurrentIndex() instead.
1438*/
1439
1440/*!
1441 \fn void QTabWidget::showPage(QWidget *widget)
1442
1443 Use setCurrentIndex(indexOf(widget)) instead.
1444*/
1445
1446/*!
1447 \fn void QTabWidget::removePage(QWidget *widget)
1448
1449 Use removeTab(indexOf(widget)) instead.
1450*/
1451
1452/*!
1453 \fn void QTabWidget::currentChanged(QWidget *widget)
1454
1455 Use currentChanged(int) instead.
1456*/
1457
1458QT_END_NAMESPACE
1459
1460#include "moc_qtabwidget.cpp"
1461
1462#endif //QT_NO_TABWIDGET
Note: See TracBrowser for help on using the repository browser.