| 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 |
|
|---|
| 69 | QTab::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 |
|
|---|
| 81 | QTab::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 |
|
|---|
| 94 | QTab::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 |
|
|---|
| 158 | QTab::~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 |
|
|---|
| 228 | class QTabBarToolTip;
|
|---|
| 229 |
|
|---|
| 230 | struct 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 | */
|
|---|
| 248 | class QTabBarToolTip : public QToolTip
|
|---|
| 249 | {
|
|---|
| 250 | public:
|
|---|
| 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 |
|
|---|
| 275 | protected:
|
|---|
| 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 |
|
|---|
| 302 | private:
|
|---|
| 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 |
|
|---|
| 330 | QTabBar::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 |
|
|---|
| 364 | QTabBar::~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 |
|
|---|
| 392 | int 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 |
|
|---|
| 413 | int 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 | */
|
|---|
| 443 | void 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 |
|
|---|
| 481 | void 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 |
|
|---|
| 530 | bool 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 | */
|
|---|
| 543 | QSize 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 |
|
|---|
| 559 | QSize 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 |
|
|---|
| 575 | void 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 |
|
|---|
| 616 | void 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 |
|
|---|
| 667 | void 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 |
|
|---|
| 717 | QTab * 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 | */
|
|---|
| 742 | void 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 |
|
|---|
| 763 | void 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 |
|
|---|
| 784 | void 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 | */
|
|---|
| 800 | void 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 |
|
|---|
| 826 | int QTabBar::currentTab() const
|
|---|
| 827 | {
|
|---|
| 828 | const QTab * t = l->getLast();
|
|---|
| 829 |
|
|---|
| 830 | return t ? t->id : -1;
|
|---|
| 831 | }
|
|---|
| 832 |
|
|---|
| 833 | void 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 |
|
|---|
| 848 | void 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 |
|
|---|
| 885 | int QTabBar::keyboardFocusTab() const
|
|---|
| 886 | {
|
|---|
| 887 | return hasFocus() ? d->focus : -1;
|
|---|
| 888 | }
|
|---|
| 889 |
|
|---|
| 890 |
|
|---|
| 891 | /*!
|
|---|
| 892 | \reimp
|
|---|
| 893 | */
|
|---|
| 894 | void 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 |
|
|---|
| 948 | QTab * 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 |
|
|---|
| 964 | QTab * 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 | */
|
|---|
| 978 | int 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 | */
|
|---|
| 997 | int 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 | */
|
|---|
| 1015 | QPtrList<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 | */
|
|---|
| 1031 | QTabBar::Shape QTabBar::shape() const
|
|---|
| 1032 | {
|
|---|
| 1033 | return d ? d->s : RoundedAbove;
|
|---|
| 1034 | }
|
|---|
| 1035 |
|
|---|
| 1036 | void 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 | */
|
|---|
| 1049 | void 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 |
|
|---|
| 1124 | bool 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 |
|
|---|
| 1139 | void QTabBar::styleChange( QStyle& old )
|
|---|
| 1140 | {
|
|---|
| 1141 | layoutTabs();
|
|---|
| 1142 | updateArrowButtons();
|
|---|
| 1143 | QWidget::styleChange( old );
|
|---|
| 1144 | }
|
|---|
| 1145 |
|
|---|
| 1146 | /*!
|
|---|
| 1147 | \reimp
|
|---|
| 1148 | */
|
|---|
| 1149 | void QTabBar::focusInEvent( QFocusEvent * )
|
|---|
| 1150 | {
|
|---|
| 1151 | QTab *t = tab( d->focus );
|
|---|
| 1152 | if ( t )
|
|---|
| 1153 | repaint( t->r, FALSE );
|
|---|
| 1154 | }
|
|---|
| 1155 |
|
|---|
| 1156 | /*!
|
|---|
| 1157 | \reimp
|
|---|
| 1158 | */
|
|---|
| 1159 | void QTabBar::focusOutEvent( QFocusEvent * )
|
|---|
| 1160 | {
|
|---|
| 1161 | QTab *t = tab( d->focus );
|
|---|
| 1162 | if ( t )
|
|---|
| 1163 | repaint( t->r, FALSE );
|
|---|
| 1164 | }
|
|---|
| 1165 |
|
|---|
| 1166 | /*!
|
|---|
| 1167 | \reimp
|
|---|
| 1168 | */
|
|---|
| 1169 | void 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 |
|
|---|
| 1179 | void 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 |
|
|---|
| 1196 | void 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 |
|
|---|
| 1235 | void 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 | */
|
|---|
| 1266 | void 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 | */
|
|---|
| 1280 | void 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 | */
|
|---|
| 1295 | QString 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 | */
|
|---|
| 1308 | void 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 | */
|
|---|
| 1330 | void 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.
|
|---|
| 1336 | void QTab::setTabBar( QTabBar *newTb )
|
|---|
| 1337 | {
|
|---|
| 1338 | tb = newTb;
|
|---|
| 1339 | }
|
|---|
| 1340 |
|
|---|
| 1341 | /*!
|
|---|
| 1342 | \internal
|
|---|
| 1343 | */
|
|---|
| 1344 | void QTabBar::fontChange( const QFont & oldFont )
|
|---|
| 1345 | {
|
|---|
| 1346 | layoutTabs();
|
|---|
| 1347 | QWidget::fontChange( oldFont );
|
|---|
| 1348 | }
|
|---|
| 1349 |
|
|---|
| 1350 | #endif
|
|---|