source: vendor/trolltech/current/src/widgets/qtabbar.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 32.8 KB
Line 
1/****************************************************************************
2** $Id: qtabbar.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QTab and QTabBar classes
5**
6** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
7**
8** This file is part of the widgets module of the Qt GUI Toolkit.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20** licenses may use this file in accordance with the Qt Commercial License
21** Agreement provided with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36#include "qtabbar.h"
37#ifndef QT_NO_TABBAR
38#include "qaccel.h"
39#include "qbitmap.h"
40#include "qtoolbutton.h"
41#include "qtooltip.h"
42#include "qapplication.h"
43#include "qstyle.h"
44#include "qpainter.h"
45#include "qiconset.h"
46#include "qcursor.h"
47#include "../kernel/qinternal_p.h"
48#if defined(QT_ACCESSIBILITY_SUPPORT)
49#include "qaccessible.h"
50#endif
51
52
53/*!
54 \class QTab qtabbar.h
55 \brief The QTab class provides the structures in a QTabBar.
56
57 \ingroup advanced
58
59 This class is used for custom QTabBar tab headings.
60
61 \sa QTabBar
62*/
63
64
65/*!
66 Constructs an empty tab. All fields are set to empty.
67*/
68
69QTab::QTab()
70 : enabled( TRUE ),
71 id ( 0 ),
72 iconset( 0 ),
73 tb( 0 )
74{
75}
76
77/*!
78 Constructs a tab with the text \a text.
79*/
80
81QTab::QTab( const QString &text )
82 : label( text ),
83 enabled( TRUE ),
84 id( 0 ),
85 iconset( 0 ),
86 tb( 0 )
87{
88}
89
90/*!
91 Constructs a tab with an \a icon and the text, \a text.
92*/
93
94QTab::QTab( const QIconSet& icon, const QString& text )
95 : label( text ),
96 enabled( TRUE ),
97 id( 0 ),
98 iconset( new QIconSet(icon) ),
99 tb( 0 )
100{
101}
102
103/*!
104 \fn QString QTab::text() const
105
106 Returns the text of the QTab label.
107*/
108
109/*!
110 \fn QIconSet QTab::iconSet() const
111
112 Return the QIconSet of the QTab.
113*/
114
115/*!
116 \fn void QTab::setRect( const QRect &rect )
117
118 Set the QTab QRect to \a rect.
119*/
120
121/*!
122 \fn QRect QTab::rect() const
123
124 Return the QRect for the QTab.
125*/
126
127/*!
128 \fn void QTab::setEnabled( bool enable )
129
130 If \a enable is TRUE enable the QTab, otherwise disable it.
131*/
132
133/*!
134 \fn bool QTab::isEnabled() const
135
136 Returns TRUE if the QTab is enabled; otherwise returns FALSE.
137*/
138
139/*!
140 \fn void QTab::setIdentifier( int i )
141
142 Set the identifier for the QTab to \a i. Each QTab's identifier
143 within a QTabBar must be unique.
144*/
145
146/*!
147 \fn int QTab::identifier() const
148
149 Return the QTab's identifier.
150*/
151
152
153
154/*!
155 Destroys the tab and frees up all allocated resources.
156*/
157
158QTab::~QTab()
159{
160 delete iconset;
161 tb = 0;
162}
163
164/*!
165 \class QTabBar qtabbar.h
166 \brief The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
167
168 \ingroup advanced
169
170 QTabBar is straightforward to use; it draws the tabs using one of
171 the predefined \link QTabBar::Shape shapes\endlink, and emits a
172 signal when a tab is selected. It can be subclassed to tailor the
173 look and feel. Qt also provides a ready-made \l{QTabWidget} and a
174 \l{QTabDialog}.
175
176 The choice of tab shape is a matter of taste, although tab dialogs
177 (for preferences and similar) invariably use \c RoundedAbove;
178 nobody uses \c TriangularAbove. Tab controls in windows other than
179 dialogs almost always use either \c RoundedBelow or \c
180 TriangularBelow. Many spreadsheets and other tab controls in which
181 all the pages are essentially similar use \c TriangularBelow,
182 whereas \c RoundedBelow is used mostly when the pages are
183 different (e.g. a multi-page tool palette).
184
185 The most important part of QTabBar's API is the selected() signal.
186 This is emitted whenever the selected page changes (even at
187 startup, when the selected page changes from 'none'). There is
188 also a slot, setCurrentTab(), which can be used to select a page
189 programmatically.
190
191 QTabBar creates automatic accelerator keys in the manner of
192 QButton; e.g. if a tab's label is "\&Graphics", Alt+G becomes an
193 accelerator key for switching to that tab.
194
195 The following virtual functions may need to be reimplemented:
196 \list
197 \i paint() paints a single tab. paintEvent() calls paint() for
198 each tab so that any overlap will look right.
199 \i addTab() creates a new tab and adds it to the bar.
200 \i selectTab() decides which tab, if any, the user selects with the mouse.
201 \endlist
202
203 The index of the current tab is returned by currentTab(). The tab
204 with a particular index is returned by tabAt(), the tab with a
205 particular id is returned by tab(). The index of a tab is returned
206 by indexOf(). The current tab can be set by index or tab pointer
207 using one of the setCurrentTab() functions.
208
209 <img src=qtabbar-m.png> <img src=qtabbar-w.png>
210*/
211
212/*!
213 \enum QTabBar::Shape
214
215 This enum type lists the built-in shapes supported by QTabBar:
216
217 \value RoundedAbove the normal rounded look above the pages
218
219 \value RoundedBelow the normal rounded look below the pages
220
221 \value TriangularAbove triangular tabs above the pages (very
222 unusual; included for completeness)
223
224 \value TriangularBelow triangular tabs similar to those used in
225 the Excel spreadsheet, for example
226*/
227
228class QTabBarToolTip;
229
230struct QTabPrivate {
231 int id;
232 int focus;
233#ifndef QT_NO_ACCEL
234 QAccel * a;
235#endif
236 QTab *pressed;
237 QTabBar::Shape s;
238 QToolButton* rightB;
239 QToolButton* leftB;
240 int btnWidth;
241 bool scrolls;
242 QTabBarToolTip * toolTips;
243};
244
245#ifndef QT_NO_TOOLTIP
246/* \internal
247*/
248class QTabBarToolTip : public QToolTip
249{
250public:
251 QTabBarToolTip( QWidget * parent )
252 : QToolTip( parent ) {}
253 virtual ~QTabBarToolTip() {}
254
255 void add( QTab * tab, const QString & tip )
256 {
257 tabTips.replace( tab, tip );
258 }
259
260 void remove( QTab * tab )
261 {
262 tabTips.erase( tab );
263 }
264
265 QString tipForTab( QTab * tab ) const
266 {
267 QMapConstIterator<QTab *, QString> it;
268 it = tabTips.find( tab );
269 if ( it != tabTips.end() )
270 return it.data();
271 else
272 return QString();
273 }
274
275protected:
276 void maybeTip( const QPoint & p )
277 {
278 QTabBar * tb = (QTabBar *) parentWidget();
279 if ( !tb )
280 return;
281
282 // check if the scroll buttons in the tab bar are visible -
283 // don't display any tips if the pointer is over one of them
284 QRect rectL, rectR;
285 rectL.setRect( tb->d->leftB->x(), tb->d->leftB->y(),
286 tb->d->leftB->width(), tb->d->leftB->height() );
287 rectR.setRect( tb->d->rightB->x(), tb->d->rightB->y(),
288 tb->d->rightB->width(), tb->d->rightB->height() );
289 if ( tb->d->scrolls && (rectL.contains( p ) || rectR.contains( p )) )
290 return;
291
292#ifndef QT_NO_TOOLTIP
293 // find and show the tool tip for the tab under the point p
294 QMapIterator<QTab *, QString> it;
295 for ( it = tabTips.begin(); it != tabTips.end(); ++it ) {
296 if ( it.key()->rect().contains( p ) )
297 tip( it.key()->rect(), it.data() );
298 }
299#endif
300 }
301
302private:
303 QMap<QTab *, QString> tabTips;
304};
305#endif
306
307/*!
308 \fn void QTabBar::selected( int id )
309
310 QTabBar emits this signal whenever any tab is selected, whether by
311 the program or by the user. The argument \a id is the id of the
312 tab as returned by addTab().
313
314 show() is guaranteed to emit this signal; you can display your
315 page in a slot connected to this signal.
316*/
317
318/*!
319 \fn void QTabBar::layoutChanged()
320
321 QTabBar emits the signal whenever the layout of the tab bar has
322 been recalculated, for example when the contents of a tab change.
323*/
324
325/*!
326 Constructs a new, empty tab bar; the \a parent and \a name
327 arguments are passed on to the QWidget constructor.
328*/
329
330QTabBar::QTabBar( QWidget * parent, const char *name )
331 : QWidget( parent, name, WNoAutoErase | WNoMousePropagation )
332{
333 d = new QTabPrivate;
334 d->pressed = 0;
335 d->id = 0;
336 d->focus = 0;
337 d->toolTips = 0;
338#ifndef QT_NO_ACCEL
339 d->a = new QAccel( this, "tab accelerators" );
340 connect( d->a, SIGNAL(activated(int)), this, SLOT(setCurrentTab(int)) );
341 connect( d->a, SIGNAL(activatedAmbiguously(int)), this, SLOT(setCurrentTab(int)) );
342#endif
343 d->s = RoundedAbove;
344 d->scrolls = FALSE;
345 d->leftB = new QToolButton( LeftArrow, this, "qt_left_btn" );
346 connect( d->leftB, SIGNAL( clicked() ), this, SLOT( scrollTabs() ) );
347 d->leftB->hide();
348 d->rightB = new QToolButton( RightArrow, this, "qt_right_btn" );
349 connect( d->rightB, SIGNAL( clicked() ), this, SLOT( scrollTabs() ) );
350 d->rightB->hide();
351 d->btnWidth = style().pixelMetric(QStyle::PM_TabBarScrollButtonWidth, this);
352 l = new QPtrList<QTab>;
353 lstatic = new QPtrList<QTab>;
354 lstatic->setAutoDelete( TRUE );
355 setFocusPolicy( TabFocus );
356 setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
357}
358
359
360/*!
361 Destroys the tab control, freeing memory used.
362*/
363
364QTabBar::~QTabBar()
365{
366#ifndef QT_NO_TOOLTIP
367 if ( d->toolTips )
368 delete d->toolTips;
369#endif
370 delete d;
371 d = 0;
372 delete l;
373 l = 0;
374 delete lstatic;
375 lstatic = 0;
376}
377
378
379/*!
380 Adds the tab, \a newTab, to the tab control.
381
382 Sets \a newTab's id to a new id and places the tab just to the
383 right of the existing tabs. If the tab's label contains an
384 ampersand, the letter following the ampersand is used as an
385 accelerator for the tab, e.g. if the label is "Bro\&wse" then
386 Alt+W becomes an accelerator which will move the focus to this
387 tab. Returns the id.
388
389 \sa insertTab()
390*/
391
392int QTabBar::addTab( QTab * newTab )
393{
394 return insertTab( newTab );
395}
396
397
398/*!
399 Inserts the tab, \a newTab, into the tab control.
400
401 If \a index is not specified, the tab is simply appended.
402 Otherwise it's inserted at the specified position.
403
404 Sets \a newTab's id to a new id. If the tab's label contains an
405 ampersand, the letter following the ampersand is used as an
406 accelerator for the tab, e.g. if the label is "Bro\&wse" then
407 Alt+W becomes an accelerator which will move the focus to this
408 tab. Returns the id.
409
410 \sa addTab()
411*/
412
413int QTabBar::insertTab( QTab * newTab, int index )
414{
415 newTab->id = d->id++;
416 if ( !tab( d->focus ) )
417 d->focus = newTab->id;
418
419 newTab->setTabBar( this );
420 l->insert( 0, newTab );
421 if ( index < 0 || index > int(lstatic->count()) )
422 lstatic->append( newTab );
423 else
424 lstatic->insert( index, newTab );
425
426 layoutTabs();
427 updateArrowButtons();
428 makeVisible( tab( currentTab() ) );
429
430#ifndef QT_NO_ACCEL
431 int p = QAccel::shortcutKey( newTab->label );
432 if ( p )
433 d->a->insertItem( p, newTab->id );
434#endif
435
436 return newTab->id;
437}
438
439
440/*!
441 Removes tab \a t from the tab control, and deletes the tab.
442*/
443void QTabBar::removeTab( QTab * t )
444{
445 //#### accelerator labels??
446#ifndef QT_NO_TOOLTIP
447 if ( d->toolTips )
448 d->toolTips->remove( t );
449#endif
450#ifndef QT_NO_ACCEL
451 if ( d->a )
452 d->a->removeItem( t->id );
453#endif
454 bool updateFocus = t->id == d->focus;
455 // remove the TabBar Reference
456 if(d->pressed == t)
457 d->pressed = 0;
458 t->setTabBar( 0 );
459 l->remove( t );
460 lstatic->remove( t );
461 layoutTabs();
462 updateArrowButtons();
463 makeVisible( tab( currentTab() ) );
464 if ( updateFocus )
465 d->focus = currentTab();
466 update();
467}
468
469
470/*!
471 Enables tab \a id if \a enabled is TRUE or disables it if \a
472 enabled is FALSE. If \a id is currently selected,
473 setTabEnabled(FALSE) makes another tab selected.
474
475 setTabEnabled() updates the display if this causes a change in \a
476 id's status.
477
478 \sa update(), isTabEnabled()
479*/
480
481void QTabBar::setTabEnabled( int id, bool enabled )
482{
483 QTab * t;
484 for( t = l->first(); t; t = l->next() ) {
485 if ( t && t->id == id ) {
486 if ( t->enabled != enabled ) {
487 t->enabled = enabled;
488#ifndef QT_NO_ACCEL
489 d->a->setItemEnabled( t->id, enabled );
490#endif
491 QRect r( t->r );
492 if ( !enabled && id == currentTab() ) {
493 QPoint p1( t->r.center() ), p2;
494 int m = 2147483647;
495 int distance;
496 // look for the closest enabled tab - measure the
497 // distance between the centers of the two tabs
498 for( QTab * n = l->first(); n; n = l->next() ) {
499 if ( n->enabled ) {
500 p2 = n->r.center();
501 distance = (p2.x() - p1.x())*(p2.x() - p1.x()) +
502 (p2.y() - p1.y())*(p2.y() - p1.y());
503 if ( distance < m ) {
504 t = n;
505 m = distance;
506 }
507 }
508 }
509 if ( t->enabled ) {
510 r = r.unite( t->r );
511 l->append( l->take( l->findRef( t ) ) );
512 emit selected( t->id );
513 }
514 }
515 repaint( r, FALSE );
516 }
517 return;
518 }
519 }
520}
521
522
523/*!
524 Returns TRUE if the tab with id \a id exists and is enabled;
525 otherwise returns FALSE.
526
527 \sa setTabEnabled()
528*/
529
530bool QTabBar::isTabEnabled( int id ) const
531{
532 QTab * t = tab( id );
533 if ( t )
534 return t->enabled;
535 return FALSE;
536}
537
538
539
540/*!
541 \reimp
542*/
543QSize QTabBar::sizeHint() const
544{
545 QSize sz(0, 0);
546 if ( QTab * t = l->first() ) {
547 QRect r( t->r );
548 while ( (t = l->next()) != 0 )
549 r = r.unite( t->r );
550 sz = r.size();
551 }
552 return sz.expandedTo(QApplication::globalStrut());
553}
554
555/*!
556 \reimp
557*/
558
559QSize QTabBar::minimumSizeHint() const
560{
561 if(style().styleHint( QStyle::SH_TabBar_PreferNoArrows, this ))
562 return sizeHint();
563 return QSize( d->rightB->sizeHint().width() * 2 + 75, sizeHint().height() );
564}
565
566/*!
567 Paints the tab \a t using painter \a p. If and only if \a selected
568 is TRUE, \a t is drawn currently selected.
569
570 This virtual function may be reimplemented to change the look of
571 QTabBar. If you decide to reimplement it, you may also need to
572 reimplement sizeHint().
573*/
574
575void QTabBar::paint( QPainter * p, QTab * t, bool selected ) const
576{
577 QStyle::SFlags flags = QStyle::Style_Default;
578
579 if (isEnabled() && t->isEnabled())
580 flags |= QStyle::Style_Enabled;
581 if ( selected )
582 flags |= QStyle::Style_Selected;
583 else if(t == d->pressed)
584 flags |= QStyle::Style_Sunken;
585 //selection flags
586 if(t->rect().contains(mapFromGlobal(QCursor::pos())))
587 flags |= QStyle::Style_MouseOver;
588 style().drawControl( QStyle::CE_TabBarTab, p, this, t->rect(),
589 colorGroup(), flags, QStyleOption(t) );
590
591 QRect r( t->r );
592 p->setFont( font() );
593
594 int iw = 0;
595 int ih = 0;
596 if ( t->iconset != 0 ) {
597 iw = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4;
598 ih = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).height();
599 }
600 QFontMetrics fm = p->fontMetrics();
601 int fw = fm.width( t->label );
602 fw -= t->label.contains('&') * fm.width('&');
603 fw += t->label.contains("&&") * fm.width('&');
604 int w = iw + fw + 4;
605 int h = QMAX(fm.height() + 4, ih );
606 paintLabel( p, QRect( r.left() + (r.width()-w)/2 - 3,
607 r.top() + (r.height()-h)/2,
608 w, h ), t, t->id == keyboardFocusTab() );
609}
610
611/*!
612 Paints the label of tab \a t centered in rectangle \a br using
613 painter \a p. A focus indication is drawn if \a has_focus is TRUE.
614*/
615
616void QTabBar::paintLabel( QPainter* p, const QRect& br,
617 QTab* t, bool has_focus ) const
618{
619 QRect r = br;
620 bool selected = currentTab() == t->id;
621 if ( t->iconset) {
622 // the tab has an iconset, draw it in the right mode
623 QIconSet::Mode mode = (t->enabled && isEnabled())
624 ? QIconSet::Normal : QIconSet::Disabled;
625 if ( mode == QIconSet::Normal && has_focus )
626 mode = QIconSet::Active;
627 QPixmap pixmap = t->iconset->pixmap( QIconSet::Small, mode );
628 int pixw = pixmap.width();
629 int pixh = pixmap.height();
630 r.setLeft( r.left() + pixw + 4 );
631 r.setRight( r.right() + 2 );
632
633 int xoff = 0, yoff = 0;
634 if(!selected) {
635 xoff = style().pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, this);
636 yoff = style().pixelMetric(QStyle::PM_TabBarTabShiftVertical, this);
637 }
638 p->drawPixmap( br.left() + 2 + xoff, br.center().y()-pixh/2 + yoff, pixmap );
639 }
640
641 QStyle::SFlags flags = QStyle::Style_Default;
642
643 if (isEnabled() && t->isEnabled())
644 flags |= QStyle::Style_Enabled;
645 if (has_focus)
646 flags |= QStyle::Style_HasFocus;
647 if ( selected )
648 flags |= QStyle::Style_Selected;
649 else if(t == d->pressed)
650 flags |= QStyle::Style_Sunken;
651 if(t->rect().contains(mapFromGlobal(QCursor::pos())))
652 flags |= QStyle::Style_MouseOver;
653 style().drawControl( QStyle::CE_TabBarLabel, p, this, r,
654 t->isEnabled() ? colorGroup(): palette().disabled(),
655 flags, QStyleOption(t) );
656}
657
658
659/*!
660 Repaints the tab row. All the painting is done by paint();
661 paintEvent() only decides which tabs need painting and in what
662 order. The event is passed in \a e.
663
664 \sa paint()
665*/
666
667void QTabBar::paintEvent( QPaintEvent * e )
668{
669 if ( e->rect().isNull() )
670 return;
671
672 QSharedDoubleBuffer buffer( this, e->rect() );
673
674 QTab * t;
675 t = l->first();
676 do {
677 QTab * n = l->next();
678 if ( t && t->r.intersects( e->rect() ) )
679 paint( buffer.painter(), t, n == 0 );
680 t = n;
681 } while ( t != 0 );
682
683 if ( d->scrolls && lstatic->first()->r.left() < 0 ) {
684 QPointArray a;
685 int h = height();
686 if ( d->s == RoundedAbove ) {
687 buffer.painter()->fillRect( 0, 3, 4, h-5,
688 colorGroup().brush( QColorGroup::Background ) );
689 a.setPoints( 5, 0,2, 3,h/4, 0,h/2, 3,3*h/4, 0,h );
690 } else if ( d->s == RoundedBelow ) {
691 buffer.painter()->fillRect( 0, 2, 4, h-5,
692 colorGroup().brush( QColorGroup::Background ) );
693 a.setPoints( 5, 0,0, 3,h/4, 0,h/2, 3,3*h/4, 0,h-3 );
694 }
695
696 if ( !a.isEmpty() ) {
697 buffer.painter()->setPen( colorGroup().light() );
698 buffer.painter()->drawPolyline( a );
699 a.translate( 1, 0 );
700 buffer.painter()->setPen( colorGroup().midlight() );
701 buffer.painter()->drawPolyline( a );
702 }
703 }
704}
705
706
707/*!
708 This virtual function is called by the mouse event handlers to
709 determine which tab is pressed. The default implementation returns
710 a pointer to the tab whose bounding rectangle contains \a p, if
711 exactly one tab's bounding rectangle contains \a p. Otherwise it
712 returns 0.
713
714 \sa mousePressEvent() mouseReleaseEvent()
715*/
716
717QTab * QTabBar::selectTab( const QPoint & p ) const
718{
719 QTab * selected = 0;
720 bool moreThanOne = FALSE;
721
722 QPtrListIterator<QTab> i( *l );
723 while( i.current() ) {
724 QTab * t = i.current();
725 ++i;
726
727 if ( t && t->r.contains( p ) ) {
728 if ( selected )
729 moreThanOne = TRUE;
730 else
731 selected = t;
732 }
733 }
734
735 return moreThanOne ? 0 : selected;
736}
737
738
739/*!
740 \reimp
741*/
742void QTabBar::mousePressEvent( QMouseEvent * e )
743{
744 if ( e->button() != LeftButton ) {
745 e->ignore();
746 return;
747 }
748 QTab *t = selectTab( e->pos() );
749 if ( t && t->enabled ) {
750 d->pressed = t;
751 if(e->type() == style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ))
752 setCurrentTab( t );
753 else
754 repaint(t->rect(), FALSE);
755 }
756}
757
758
759/*!
760 \reimp
761*/
762
763void QTabBar::mouseMoveEvent ( QMouseEvent *e )
764{
765 if ( e->state() != LeftButton ) {
766 e->ignore();
767 return;
768 }
769 if(style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ) == QEvent::MouseButtonRelease) {
770 QTab *t = selectTab( e->pos() );
771 if(t != d->pressed) {
772 if(d->pressed)
773 repaint(d->pressed->rect(), FALSE);
774 if((d->pressed = t))
775 repaint(t->rect(), FALSE);
776 }
777 }
778}
779
780/*!
781 \reimp
782*/
783
784void QTabBar::mouseReleaseEvent( QMouseEvent *e )
785{
786 if ( e->button() != LeftButton )
787 e->ignore();
788 if(d->pressed) {
789 QTab *t = selectTab( e->pos() ) == d->pressed ? d->pressed : 0;
790 d->pressed = 0;
791 if(t && t->enabled && e->type() == style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ))
792 setCurrentTab( t );
793 }
794}
795
796
797/*!
798 \reimp
799*/
800void QTabBar::show()
801{
802 // ensures that one tab is selected.
803 QTab * t = l->last();
804 QWidget::show();
805
806 if ( t )
807 emit selected( t->id );
808}
809
810/*!
811 \property QTabBar::currentTab
812 \brief the id of the tab bar's visible tab
813
814 If no tab page is currently visible, the property's value is -1.
815 Even if the property's value is not -1, you cannot assume that the
816 user can see the relevant page, or that the tab is enabled. When
817 you need to display something the value of this property
818 represents the best page to display.
819
820 When this property is set to \e id, it will raise the tab with the
821 id \e id and emit the selected() signal.
822
823 \sa selected() isTabEnabled()
824*/
825
826int QTabBar::currentTab() const
827{
828 const QTab * t = l->getLast();
829
830 return t ? t->id : -1;
831}
832
833void QTabBar::setCurrentTab( int id )
834{
835 setCurrentTab( tab( id ) );
836}
837
838
839/*!
840 \overload
841
842 Raises \a tab and emits the selected() signal unless the tab was
843 already current.
844
845 \sa currentTab() selected()
846*/
847
848void QTabBar::setCurrentTab( QTab * tab )
849{
850 if ( tab && l ) {
851 if ( l->last() == tab )
852 return;
853
854 QRect r = l->last()->r;
855 if ( l->findRef( tab ) >= 0 )
856 l->append( l->take() );
857
858 d->focus = tab->id;
859
860 setMicroFocusHint( tab->rect().x(), tab->rect().y(), tab->rect().width(), tab->rect().height(), FALSE );
861
862 if ( tab->r.intersects( r ) ) {
863 repaint( r.unite( tab->r ), FALSE );
864 } else {
865 repaint( r, FALSE );
866 repaint( tab->r, FALSE );
867 }
868 makeVisible( tab );
869 emit selected( tab->id );
870
871#ifdef QT_ACCESSIBILITY_SUPPORT
872 QAccessible::updateAccessibility( this, indexOf(tab->id)+1, QAccessible::Focus );
873#endif
874 }
875}
876
877/*!
878 \property QTabBar::keyboardFocusTab
879 \brief the id of the tab that has the keyboard focus
880
881 This property contains the id of the tab that has the keyboard
882 focus or -1 if the tab bar does not have the keyboard focus.
883*/
884
885int QTabBar::keyboardFocusTab() const
886{
887 return hasFocus() ? d->focus : -1;
888}
889
890
891/*!
892 \reimp
893*/
894void QTabBar::keyPressEvent( QKeyEvent * e )
895{
896 // The right and left arrow keys move a selector, the spacebar
897 // makes the tab with the selector active. All other keys are
898 // ignored.
899
900 int old = d->focus;
901
902 bool reverse = QApplication::reverseLayout();
903 if ( ( !reverse && e->key() == Key_Left ) || ( reverse && e->key() == Key_Right ) ) {
904 // left - skip past any disabled ones
905 if ( d->focus > 0 ) {
906 QTab * t = lstatic->last();
907 while ( t && t->id != d->focus )
908 t = lstatic->prev();
909 do {
910 t = lstatic->prev();
911 } while ( t && !t->enabled);
912 if (t)
913 d->focus = t->id;
914 }
915 if ( d->focus < 0 )
916 d->focus = old;
917 } else if ( ( !reverse && e->key() == Key_Right ) || ( reverse && e->key() == Key_Left ) ) {
918 QTab * t = lstatic->first();
919 while ( t && t->id != d->focus )
920 t = lstatic->next();
921 do {
922 t = lstatic->next();
923 } while ( t && !t->enabled);
924
925 if (t)
926 d->focus = t->id;
927 if ( d->focus >= d->id )
928 d->focus = old;
929 } else {
930 // other keys - ignore
931 e->ignore();
932 return;
933 }
934
935 // if the focus moved, repaint and signal
936 if ( old != d->focus ) {
937 setCurrentTab( d->focus );
938 }
939}
940
941
942/*!
943 Returns the tab with id \a id or 0 if there is no such tab.
944
945 \sa count()
946*/
947
948QTab * QTabBar::tab( int id ) const
949{
950 QTab * t;
951 for( t = l->first(); t; t = l->next() )
952 if ( t && t->id == id )
953 return t;
954 return 0;
955}
956
957
958/*!
959 Returns the tab at position \a index.
960
961 \sa indexOf()
962*/
963
964QTab * QTabBar::tabAt( int index ) const
965{
966 QTab * t;
967 t = lstatic->at( index );
968 return t;
969}
970
971
972/*!
973 Returns the position index of the tab with id \a id or -1 if no
974 tab has this \a id.
975
976 \sa tabAt()
977*/
978int QTabBar::indexOf( int id ) const
979{
980 QTab * t;
981 int idx = 0;
982 for( t = lstatic->first(); t; t = lstatic->next() ) {
983 if ( t && t->id == id )
984 return idx;
985 idx++;
986 }
987 return -1;
988}
989
990
991/*!
992 \property QTabBar::count
993 \brief the number of tabs in the tab bar
994
995 \sa tab()
996*/
997int QTabBar::count() const
998{
999 return l->count();
1000}
1001
1002
1003/*!
1004 The list of QTab objects in the tab bar.
1005
1006 This list is unlikely to be in the order that the QTab elements
1007 appear visually. One way of iterating over the tabs is like this:
1008 \code
1009 for ( uint i = 0; i < myTabBar->count(); ++i ) {
1010 nextTab = myTabBar->tabAt( i );
1011 // do something with nextTab
1012 }
1013 \endcode
1014*/
1015QPtrList<QTab> * QTabBar::tabList()
1016{
1017 return l;
1018}
1019
1020
1021/*!
1022 \property QTabBar::shape
1023 \brief the shape of the tabs in the tab bar
1024
1025 The value of this property is one of the following: \c
1026 RoundedAbove (default), \c RoundedBelow, \c TriangularAbove or \c
1027 TriangularBelow.
1028
1029 \sa Shape
1030*/
1031QTabBar::Shape QTabBar::shape() const
1032{
1033 return d ? d->s : RoundedAbove;
1034}
1035
1036void QTabBar::setShape( Shape s )
1037{
1038 if ( !d || d->s == s )
1039 return;
1040 //######### must recalculate heights
1041 d->s = s;
1042 update();
1043}
1044
1045/*!
1046 Lays out all existing tabs according to their label and their
1047 iconset.
1048 */
1049void QTabBar::layoutTabs()
1050{
1051 if ( lstatic->isEmpty() )
1052 return;
1053
1054 QSize oldSh(0, 0);
1055 if ( QTab * t = l->first() ) {
1056 QRect r( t->r );
1057 while ( (t = l->next()) != 0 )
1058 r = r.unite( t->r );
1059 oldSh = r.size();
1060 }
1061
1062 d->btnWidth = style().pixelMetric(QStyle::PM_TabBarScrollButtonWidth, this);
1063 int hframe, vframe, overlap;
1064 hframe = style().pixelMetric( QStyle::PM_TabBarTabHSpace, this );
1065 vframe = style().pixelMetric( QStyle::PM_TabBarTabVSpace, this );
1066 overlap = style().pixelMetric( QStyle::PM_TabBarTabOverlap, this );
1067
1068 QFontMetrics fm = fontMetrics();
1069 QRect r;
1070 QTab *t;
1071 bool reverse = QApplication::reverseLayout();
1072 if ( reverse )
1073 t = lstatic->last();
1074 else
1075 t = lstatic->first();
1076 int x = 0;
1077 int offset = (t && d->scrolls) ? t->r.x() : 0;
1078 while ( t ) {
1079 int lw = fm.width( t->label );
1080 lw -= t->label.contains('&') * fm.width('&');
1081 lw += t->label.contains("&&") * fm.width('&');
1082 int iw = 0;
1083 int ih = 0;
1084 if ( t->iconset != 0 ) {
1085 iw = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4;
1086 ih = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).height();
1087 }
1088 int h = QMAX( fm.height(), ih );
1089 h = QMAX( h, QApplication::globalStrut().height() );
1090
1091 h += vframe;
1092 t->r = QRect(QPoint(x, 0), style().sizeFromContents(QStyle::CT_TabBarTab, this,
1093 QSize( QMAX( lw + hframe + iw, QApplication::globalStrut().width() ), h ),
1094 QStyleOption(t) ));
1095 x += t->r.width() - overlap;
1096 r = r.unite( t->r );
1097 if ( reverse )
1098 t = lstatic->prev();
1099 else
1100 t = lstatic->next();
1101 }
1102 x += overlap;
1103 int w = (d->scrolls) ? d->leftB->x() : width();
1104 if (x + offset < w)
1105 offset = w - x;
1106 if (offset > 0)
1107 offset = 0;
1108
1109 for ( t = lstatic->first(); t; t = lstatic->next() ) {
1110 t->r.moveBy( offset, 0 );
1111 t->r.setHeight( r.height() );
1112 }
1113
1114 if ( sizeHint() != oldSh )
1115 updateGeometry();
1116
1117 emit layoutChanged();
1118}
1119
1120/*!
1121 \reimp
1122*/
1123
1124bool QTabBar::event( QEvent *e )
1125{
1126 if ( e->type() == QEvent::LanguageChange ) {
1127 layoutTabs();
1128 updateArrowButtons();
1129 makeVisible( tab( currentTab() ));
1130 }
1131
1132 return QWidget::event( e );
1133}
1134
1135/*!
1136 \reimp
1137*/
1138
1139void QTabBar::styleChange( QStyle& old )
1140{
1141 layoutTabs();
1142 updateArrowButtons();
1143 QWidget::styleChange( old );
1144}
1145
1146/*!
1147 \reimp
1148*/
1149void QTabBar::focusInEvent( QFocusEvent * )
1150{
1151 QTab *t = tab( d->focus );
1152 if ( t )
1153 repaint( t->r, FALSE );
1154}
1155
1156/*!
1157 \reimp
1158*/
1159void QTabBar::focusOutEvent( QFocusEvent * )
1160{
1161 QTab *t = tab( d->focus );
1162 if ( t )
1163 repaint( t->r, FALSE );
1164}
1165
1166/*!
1167 \reimp
1168*/
1169void QTabBar::resizeEvent( QResizeEvent * )
1170{
1171 const int arrowWidth = QMAX( d->btnWidth, QApplication::globalStrut().width() );;
1172 d->rightB->setGeometry( width() - arrowWidth, 0, arrowWidth, height() );
1173 d->leftB->setGeometry( width() - 2*arrowWidth, 0, arrowWidth, height() );
1174 layoutTabs();
1175 updateArrowButtons();
1176 makeVisible( tab( currentTab() ));
1177}
1178
1179void QTabBar::scrollTabs()
1180{
1181 QTab* left = 0;
1182 QTab* right = 0;
1183 for ( QTab* t = lstatic->first(); t; t = lstatic->next() ) {
1184 if ( t->r.left() < 0 && t->r.right() > 0 )
1185 left = t;
1186 if ( t->r.left() < d->leftB->x()+2 )
1187 right = t;
1188 }
1189
1190 if ( sender() == d->leftB )
1191 makeVisible( left );
1192 else if ( sender() == d->rightB )
1193 makeVisible( right );
1194}
1195
1196void QTabBar::makeVisible( QTab* tab )
1197{
1198 bool tooFarLeft = ( tab && tab->r.left() < 0 );
1199 bool tooFarRight = ( tab && tab->r.right() >= d->leftB->x() );
1200
1201 if ( !d->scrolls || ( !tooFarLeft && ! tooFarRight ) )
1202 return;
1203
1204 bool bs = signalsBlocked();
1205 blockSignals(TRUE);
1206 layoutTabs();
1207 blockSignals(bs);
1208
1209 int offset = 0;
1210
1211 if ( tooFarLeft ) {
1212 offset = tab->r.left();
1213 if (tab != lstatic->first())
1214 offset -= 8;
1215 } else if ( tooFarRight ) {
1216 offset = tab->r.right() - d->leftB->x() + 1;
1217 }
1218
1219 for ( QTab* t = lstatic->first(); t; t = lstatic->next() )
1220 t->r.moveBy( -offset, 0 );
1221
1222 d->leftB->setEnabled( lstatic->first()->r.left() < 0);
1223 d->rightB->setEnabled( lstatic->last()->r.right() >= d->leftB->x() );
1224
1225 // Make sure disabled buttons pop up again
1226 if ( !d->leftB->isEnabled() && d->leftB->isDown() )
1227 d->leftB->setDown( FALSE );
1228 if ( !d->rightB->isEnabled() && d->rightB->isDown() )
1229 d->rightB->setDown( FALSE );
1230
1231 update();
1232 emit layoutChanged();
1233}
1234
1235void QTabBar::updateArrowButtons()
1236{
1237 if (lstatic->isEmpty()) {
1238 d->scrolls = FALSE;
1239 } else {
1240 d->scrolls = (lstatic->last()->r.right() - lstatic->first()->r.left() > width());
1241 }
1242 if ( d->scrolls ) {
1243 const int arrowWidth = QMAX( d->btnWidth, QApplication::globalStrut().width() );
1244 if ( QApplication::reverseLayout() ) {
1245 d->rightB->setGeometry( arrowWidth, 0, arrowWidth, height() );
1246 d->leftB->setGeometry( 0, 0, arrowWidth, height() );
1247 } else {
1248 d->rightB->setGeometry( width() - arrowWidth, 0, arrowWidth, height() );
1249 d->leftB->setGeometry( width() - 2*arrowWidth, 0, arrowWidth, height() );
1250 }
1251
1252 d->leftB->setEnabled( lstatic->first()->r.left() < 0);
1253 d->rightB->setEnabled( lstatic->last()->r.right() >= d->leftB->x() );
1254 d->leftB->show();
1255 d->rightB->show();
1256 } else {
1257 d->leftB->hide();
1258 d->rightB->hide();
1259 layoutTabs();
1260 }
1261}
1262
1263/*!
1264 Removes the tool tip for the tab at index position \a index.
1265*/
1266void QTabBar::removeToolTip( int index )
1267{
1268#ifndef QT_NO_TOOLTIP
1269 QTab * tab = tabAt( index );
1270 if ( !tab || !d->toolTips )
1271 return;
1272 d->toolTips->remove( tab );
1273#endif
1274}
1275
1276/*!
1277 Sets the tool tip for the tab at index position \a index to \a
1278 tip.
1279*/
1280void QTabBar::setToolTip( int index, const QString & tip )
1281{
1282#ifndef QT_NO_TOOLTIP
1283 QTab * tab = tabAt( index );
1284 if ( !tab )
1285 return;
1286 if ( d->toolTips == 0 )
1287 d->toolTips = new QTabBarToolTip( this );
1288 d->toolTips->add( tab, tip );
1289#endif
1290}
1291
1292/*!
1293 Returns the tool tip for the tab at index position \a index.
1294*/
1295QString QTabBar::toolTip( int index ) const
1296{
1297#ifndef QT_NO_TOOLTIP
1298 if ( d->toolTips )
1299 return d->toolTips->tipForTab( tabAt( index ) );
1300 else
1301#endif
1302 return QString();
1303}
1304
1305/*!
1306 Sets the text of the tab to \a text.
1307*/
1308void QTab::setText( const QString& text )
1309{
1310 label = text;
1311 if ( tb ) {
1312#ifndef QT_NO_ACCEL
1313 tb->d->a->removeItem( id );
1314 int p = QAccel::shortcutKey( text );
1315 if ( p )
1316 tb->d->a->insertItem( p, id );
1317#endif
1318 tb->layoutTabs();
1319 tb->repaint(FALSE);
1320
1321#if defined(QT_ACCESSIBILITY_SUPPORT)
1322 QAccessible::updateAccessibility( tb, tb->indexOf(id)+1, QAccessible::NameChanged );
1323#endif
1324 }
1325}
1326
1327/*!
1328 Sets the tab's iconset to \a icon
1329*/
1330void QTab::setIconSet( const QIconSet &icon )
1331{
1332 iconset = new QIconSet( icon );
1333}
1334
1335// this allows us to handle accelerators that are in a QTabBar.
1336void QTab::setTabBar( QTabBar *newTb )
1337{
1338 tb = newTb;
1339}
1340
1341/*!
1342 \internal
1343*/
1344void QTabBar::fontChange( const QFont & oldFont )
1345{
1346 layoutTabs();
1347 QWidget::fontChange( oldFont );
1348}
1349
1350#endif
Note: See TracBrowser for help on using the repository browser.