source: vendor/trolltech/current/src/widgets/qtoolbox.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: 18.2 KB
Line 
1/****************************************************************************
2** $Id: qtoolbox.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QToolBox widget class
5**
6** Created : 961105
7**
8** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qtoolbox.h"
39
40#ifndef QT_NO_TOOLBOX
41
42#include <qbutton.h>
43#include <qlayout.h>
44#include <qscrollview.h>
45#include <qpainter.h>
46#include <qstyle.h>
47#include <qobjectlist.h>
48#include <qapplication.h>
49#include <qwidgetlist.h>
50#include <qlayout.h>
51#include <qvaluelist.h>
52#include <qtooltip.h>
53#include <qeventloop.h>
54#include <qdatetime.h>
55
56class QToolBoxButton : public QButton
57{
58public:
59 QToolBoxButton( QWidget *parent, const char *name )
60 : QButton( parent, name ), selected( FALSE )
61 {
62 setBackgroundMode(PaletteBackground);
63 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
64 setFocusPolicy(NoFocus);
65 }
66
67 inline void setSelected( bool b ) { selected = b; update(); }
68 inline void setTextLabel( const QString &text ) { label = text; update(); }
69 inline QString textLabel() const { return label; }
70 inline void setIconSet( const QIconSet &is ) { icon = is; update(); }
71 inline QIconSet iconSet() const { return icon; }
72
73 QSize sizeHint() const;
74 QSize minimumSizeHint() const;
75
76protected:
77 void drawButton( QPainter * );
78
79private:
80 bool selected;
81 QString label;
82 QIconSet icon;
83};
84
85class QToolBoxPrivate
86{
87public:
88 struct Page
89 {
90 QToolBoxButton *button;
91 QScrollView *sv;
92 QWidget *widget;
93 QString toolTip;
94
95 inline void setTextLabel( const QString &text ) { button->setTextLabel(text); }
96 inline void setIconSet( const QIconSet &is ) { button->setIconSet(is); }
97 inline void setToolTip( const QString &tip )
98 {
99 toolTip = tip;
100 QToolTip::remove( button );
101 if ( !tip.isNull() )
102 QToolTip::add( button, tip );
103 }
104
105 inline bool operator==(const Page& other) const
106 {
107 return widget == other.widget;
108 }
109 };
110 typedef QValueList<Page> PageList;
111
112 inline QToolBoxPrivate()
113 : currentPage( 0 )
114 {
115 }
116
117 Page *page( QWidget *widget );
118 Page *page( int index );
119
120 void updateTabs();
121
122 PageList pageList;
123 QVBoxLayout *layout;
124 Page *currentPage;
125};
126
127QToolBoxPrivate::Page *QToolBoxPrivate::page( QWidget *widget )
128{
129 if ( !widget )
130 return 0;
131
132 for ( PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i )
133 if ( (*i).widget == widget )
134 return (Page*) &(*i);
135 return 0;
136}
137
138QToolBoxPrivate::Page *QToolBoxPrivate::page( int index )
139{
140 if (index >= 0 && index < (int)pageList.size() )
141 return &*pageList.at(index);
142 return 0;
143}
144
145void QToolBoxPrivate::updateTabs()
146{
147 QToolBoxButton *lastButton = currentPage ? currentPage->button : 0;
148 bool after = FALSE;
149 for ( PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i ) {
150 if (after) {
151 (*i).button->setEraseColor((*i).widget->eraseColor());
152 (*i).button->update();
153 } else if ( (*i).button->backgroundMode() != Qt::PaletteBackground ) {
154 (*i).button->setBackgroundMode( Qt::PaletteBackground );
155 (*i).button->update();
156 }
157 after = (*i).button == lastButton;
158 }
159}
160
161QSize QToolBoxButton::sizeHint() const
162{
163 QSize iconSize(8, 8);
164 if ( !icon.isNull() )
165 iconSize += icon.pixmap( QIconSet::Small, QIconSet::Normal ).size() + QSize( 2, 0 );
166 QSize textSize = fontMetrics().size( Qt::ShowPrefix, label ) + QSize(0, 8);
167
168 QSize total(iconSize.width() + textSize.width(), QMAX(iconSize.height(), textSize.height()));
169 return total.expandedTo(QApplication::globalStrut());
170}
171
172QSize QToolBoxButton::minimumSizeHint() const
173{
174 if ( icon.isNull() )
175 return QSize();
176 return QSize(8, 8) + icon.pixmap( QIconSet::Small, QIconSet::Normal ).size();
177}
178
179void QToolBoxButton::drawButton( QPainter *p )
180{
181 QStyle::SFlags flags = QStyle::Style_Default;
182 const QColorGroup &cg = colorGroup();
183
184 if ( isEnabled() )
185 flags |= QStyle::Style_Enabled;
186 if ( selected )
187 flags |= QStyle::Style_Selected;
188 if ( hasFocus() )
189 flags |= QStyle::Style_HasFocus;
190 if (isDown())
191 flags |= QStyle::Style_Down;
192 style().drawControl( QStyle::CE_ToolBoxTab, p, parentWidget(), rect(), cg, flags );
193
194 QPixmap pm = icon.pixmap( QIconSet::Small, isEnabled() ? QIconSet::Normal : QIconSet::Disabled );
195
196 QRect cr = style().subRect( QStyle::SR_ToolBoxTabContents, this );
197 QRect tr, ir;
198 int ih = 0;
199 if ( pm.isNull() ) {
200 tr = cr;
201 tr.addCoords( 4, 0, -8, 0 );
202 } else {
203 int iw = pm.width() + 4;
204 ih = pm.height();
205 ir = QRect( cr.left() + 4, cr.top(), iw + 2, ih );
206 tr = QRect( ir.right(), cr.top(), cr.width() - ir.right() - 4, cr.height() );
207 }
208
209 if ( selected && style().styleHint( QStyle::SH_ToolBox_SelectedPageTitleBold ) ) {
210 QFont f( p->font() );
211 f.setBold( TRUE );
212 p->setFont( f );
213 }
214
215 QString txt;
216 if ( p->fontMetrics().width(label) < tr.width() ) {
217 txt = label;
218 } else {
219 txt = label.left( 1 );
220 int ew = p->fontMetrics().width( "..." );
221 int i = 1;
222 while ( p->fontMetrics().width( txt ) + ew +
223 p->fontMetrics().width( label[i] ) < tr.width() )
224 txt += label[i++];
225 txt += "...";
226 }
227
228 if ( ih )
229 p->drawPixmap( ir.left(), (height() - ih) / 2, pm );
230
231 QToolBox *tb = (QToolBox*)parentWidget();
232
233 const QColor* fill = 0;
234 if ( selected &&
235 style().styleHint( QStyle::SH_ToolBox_SelectedPageTitleBold ) &&
236 tb->backgroundMode() != NoBackground )
237 fill = &cg.color( QPalette::foregroundRoleFromMode( tb->backgroundMode() ) );
238
239 int alignment = AlignLeft | AlignVCenter | ShowPrefix;
240 if (!style().styleHint(QStyle::SH_UnderlineAccelerator, this))
241 alignment |= NoAccel;
242 style().drawItem( p, tr, alignment, cg,
243 isEnabled(), 0, txt, -1, fill );
244
245 if ( !txt.isEmpty() && hasFocus() )
246 style().drawPrimitive( QStyle::PE_FocusRect, p, tr, cg );
247}
248
249/*!
250 \class QToolBox
251
252 \brief The QToolBox class provides a column of tabbed widget
253 items.
254
255 \mainclass
256 \ingroup advanced
257
258 A toolbox is a widget that displays a column of tabs one above the
259 other, with the current item displayed below the current tab.
260 Every tab has an index position within the column of tabs. A tab's
261 item is a QWidget.
262
263 Each item has an itemLabel(), an optional icon, itemIconSet(), an
264 optional itemToolTip(), and a \link item() widget\endlink. The
265 item's attributes can be changed with setItemLabel(),
266 setItemIconSet() and setItemToolTip().
267
268 Items are added using addItem(), or inserted at particular
269 positions using insertItem(). The total number of items is given
270 by count(). Items can be deleted with delete, or removed from the
271 toolbox with removeItem(). Combining removeItem() and insertItem()
272 allows to move items to different positions.
273
274 The current item widget is returned by currentItem() and set with
275 setCurrentItem(). If you prefer you can work in terms of indexes
276 using currentIndex(), setCurrentIndex(), indexOf() and item().
277
278 The currentChanged() signal is emitted when the current item is
279 changed.
280
281 \sa QTabWidget
282*/
283
284/*!
285 \fn void QToolBox::currentChanged( int index )
286
287 This signal is emitted when the current item changed. The new
288 current item's index is passed in \a index, or -1 if there is no
289 current item.
290*/
291
292/*!
293 Constructs a toolbox called \a name with parent \a parent and flags \a f.
294*/
295
296QToolBox::QToolBox( QWidget *parent, const char *name, WFlags f )
297 : QFrame( parent, name, f )
298{
299 d = new QToolBoxPrivate;
300 d->layout = new QVBoxLayout( this );
301 QWidget::setBackgroundMode( PaletteButton );
302}
303
304/*! \reimp */
305
306QToolBox::~QToolBox()
307{
308 delete d;
309}
310
311/*!
312 \fn int QToolBox::addItem( QWidget *w, const QString &label )
313 \overload
314
315 Adds the widget \a w in a new tab at bottom of the toolbox. The
316 new tab's label is set to \a label. Returns the new tab's index.
317*/
318
319/*!
320 \fn int QToolBox::addItem( QWidget *item, const QIconSet &iconSet,const QString &label )
321 Adds the widget \a item in a new tab at bottom of the toolbox. The
322 new tab's label is set to \a label, and the \a iconSet is
323 displayed to the left of the \a label. Returns the new tab's index.
324*/
325
326/*!
327 \fn int QToolBox::insertItem( int index, QWidget *item, const QString &label )
328 \overload
329
330 Inserts the widget \a item at position \a index, or at the bottom
331 of the toolbox if \a index is out of range. The new item's label is
332 set to \a label. Returns the new item's index.
333*/
334
335/*!
336 Inserts the widget \a item at position \a index, or at the bottom
337 of the toolbox if \a index is out of range. The new item's label
338 is set to \a label, and the \a iconSet is displayed to the left of
339 the \a label. Returns the new item's index.
340*/
341
342int QToolBox::insertItem( int index, QWidget *item, const QIconSet &iconSet,
343 const QString &label )
344{
345 if ( !item )
346 return -1;
347
348 connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(itemDestroyed(QObject*)));
349
350 QToolBoxPrivate::Page c;
351 c.widget = item;
352 c.button = new QToolBoxButton( this, label.latin1() );
353 connect( c.button, SIGNAL( clicked() ), this, SLOT( buttonClicked() ) );
354
355 c.sv = new QScrollView( this );
356 c.sv->hide();
357 c.sv->setResizePolicy( QScrollView::AutoOneFit );
358 c.sv->addChild( item );
359 c.sv->setFrameStyle( QFrame::NoFrame );
360
361 c.setTextLabel( label );
362 c.setIconSet( iconSet );
363
364 if ( index < 0 || index >= (int)d->pageList.count() ) {
365 index = d->pageList.count();
366 d->pageList.append( c );
367 d->layout->addWidget( c.button );
368 d->layout->addWidget( c.sv );
369 if ( index == 0 )
370 setCurrentIndex( index );
371 } else {
372 d->pageList.insert( d->pageList.at(index), c );
373 relayout();
374 if (d->currentPage) {
375 QWidget *current = d->currentPage->widget;
376 int oldindex = indexOf(current);
377 if ( index <= oldindex ) {
378 d->currentPage = 0; // trigger change
379 setCurrentIndex(oldindex);
380 }
381 }
382 }
383
384 c.button->show();
385
386 d->updateTabs();
387 itemInserted(index);
388 return index;
389}
390
391void QToolBox::buttonClicked()
392{
393 QToolBoxButton *tb = ::qt_cast<QToolBoxButton*>(sender());
394 QWidget* item = 0;
395 for ( QToolBoxPrivate::PageList::ConstIterator i = d->pageList.constBegin(); i != d->pageList.constEnd(); ++i )
396 if ( (*i).button == tb ) {
397 item = (*i).widget;
398 break;
399 }
400
401 setCurrentItem( item );
402}
403
404/*!
405 \property QToolBox::count
406 \brief The number of items contained in the toolbox.
407*/
408
409int QToolBox::count() const
410{
411 return d->pageList.count();
412}
413
414void QToolBox::setCurrentIndex( int index )
415{
416 setCurrentItem( item( index ) );
417}
418
419/*!
420 Sets the current item to be \a item.
421*/
422
423void QToolBox::setCurrentItem( QWidget *item )
424{
425 QToolBoxPrivate::Page *c = d->page( item );
426 if ( !c || d->currentPage == c )
427 return;
428
429 c->button->setSelected( TRUE );
430 if ( d->currentPage ) {
431 d->currentPage->sv->hide();
432 d->currentPage->button->setSelected(FALSE);
433 }
434 d->currentPage = c;
435 d->currentPage->sv->show();
436 d->updateTabs();
437 emit currentChanged( indexOf(item) );
438}
439
440void QToolBox::relayout()
441{
442 delete d->layout;
443 d->layout = new QVBoxLayout( this );
444 for ( QToolBoxPrivate::PageList::ConstIterator i = d->pageList.constBegin(); i != d->pageList.constEnd(); ++i ) {
445 d->layout->addWidget( (*i).button );
446 d->layout->addWidget( (*i).sv );
447 }
448}
449
450void QToolBox::itemDestroyed(QObject *object)
451{
452 // no verification - vtbl corrupted already
453 QWidget *page = (QWidget*)object;
454
455 QToolBoxPrivate::Page *c = d->page(page);
456 if ( !page || !c )
457 return;
458
459 d->layout->remove( c->sv );
460 d->layout->remove( c->button );
461 c->sv->deleteLater(); // page might still be a child of sv
462 delete c->button;
463
464 bool removeCurrent = c == d->currentPage;
465 d->pageList.remove( *c );
466
467 if ( !d->pageList.count() ) {
468 d->currentPage = 0;
469 emit currentChanged(-1);
470 } else if ( removeCurrent ) {
471 d->currentPage = 0;
472 setCurrentIndex(0);
473 }
474}
475
476/*!
477 Removes the widget \a item from the toolbox. Note that the widget
478 is \e not deleted. Returns the removed widget's index, or -1 if
479 the widget was not in this tool box.
480*/
481
482int QToolBox::removeItem( QWidget *item )
483{
484 int index = indexOf(item);
485 if (index >= 0) {
486 disconnect(item, SIGNAL(destroyed(QObject*)), this, SLOT(itemDestroyed(QObject*)));
487 item->reparent( this, QPoint(0,0) );
488 // destroy internal data
489 itemDestroyed(item);
490 }
491 itemRemoved(index);
492 return index;
493}
494
495
496/*!
497 Returns the toolbox's current item, or 0 if the toolbox is empty.
498*/
499
500QWidget *QToolBox::currentItem() const
501{
502 return d->currentPage ? d->currentPage->widget : 0;
503}
504
505/*!
506 \property QToolBox::currentIndex
507 \brief the index of the current item, or -1 if the toolbox is empty.
508 \sa currentItem(), indexOf(), item()
509*/
510
511
512int QToolBox::currentIndex() const
513{
514 return d->currentPage ? indexOf( d->currentPage->widget ) : -1;
515}
516
517/*!
518 Returns the item at position \a index, or 0 if there is no such
519 item.
520*/
521
522QWidget *QToolBox::item( int index ) const
523{
524 if ( index < 0 || index >= (int) d->pageList.size() )
525 return 0;
526 return (*d->pageList.at( index )).widget;
527}
528
529/*!
530 Returns the index of item \a item, or -1 if the item does not
531 exist.
532*/
533
534int QToolBox::indexOf( QWidget *item ) const
535{
536 QToolBoxPrivate::Page *c = d->page(item);
537 return c ? d->pageList.findIndex( *c ) : -1;
538}
539
540/*!
541 If \a enabled is TRUE then the item at position \a index is enabled; otherwise item
542 \a index is disabled.
543*/
544
545void QToolBox::setItemEnabled( int index, bool enabled )
546{
547 QToolBoxPrivate::Page *c = d->page( index );
548 if ( !c )
549 return;
550
551 c->button->setEnabled( enabled );
552 if ( !enabled && c == d->currentPage ) {
553 int curIndexUp = index;
554 int curIndexDown = curIndexUp;
555 const int count = d->pageList.count();
556 while ( curIndexUp > 0 || curIndexDown < count-1 ) {
557 if ( curIndexDown < count-1 ) {
558 if (d->page(++curIndexDown)->button->isEnabled()) {
559 index = curIndexDown;
560 break;
561 }
562 }
563 if ( curIndexUp > 0 ) {
564 if (d->page(--curIndexUp)->button->isEnabled()) {
565 index = curIndexUp;
566 break;
567 }
568 }
569 }
570 setCurrentIndex(index);
571 }
572}
573
574
575/*!
576 Sets the label of the item at position \a index to \a label.
577*/
578
579void QToolBox::setItemLabel( int index, const QString &label )
580{
581 QToolBoxPrivate::Page *c = d->page( index );
582 if ( c )
583 c->setTextLabel( label );
584}
585
586/*!
587 Sets the icon of the item at position \a index to \a iconSet.
588*/
589
590void QToolBox::setItemIconSet( int index, const QIconSet &iconSet )
591{
592 QToolBoxPrivate::Page *c = d->page( index );
593 if ( c )
594 c->setIconSet( iconSet );
595}
596
597/*!
598 Sets the tooltip of the item at position \a index to \a toolTip.
599*/
600
601void QToolBox::setItemToolTip( int index, const QString &toolTip )
602{
603 QToolBoxPrivate::Page *c = d->page( index );
604 if ( c )
605 c->setToolTip( toolTip );
606}
607
608/*!
609 Returns TRUE if the item at position \a index is enabled; otherwise returns FALSE.
610*/
611
612bool QToolBox::isItemEnabled( int index ) const
613{
614 QToolBoxPrivate::Page *c = d->page( index );
615 return c && c->button->isEnabled();
616}
617
618/*!
619 Returns the label of the item at position \a index, or a null string if
620 \a index is out of range.
621*/
622
623QString QToolBox::itemLabel( int index ) const
624{
625 QToolBoxPrivate::Page *c = d->page( index );
626 return ( c ? c->button->textLabel() : QString::null );
627}
628
629/*!
630 Returns the icon of the item at position \a index, or a null
631 icon if \a index is out of range.
632*/
633
634QIconSet QToolBox::itemIconSet( int index ) const
635{
636 QToolBoxPrivate::Page *c = d->page( index );
637 return ( c ? c->button->iconSet() : QIconSet() );
638}
639
640/*!
641 Returns the tooltip of the item at position \a index, or a null
642 string if \a index is out of range.
643*/
644
645QString QToolBox::itemToolTip( int index ) const
646{
647 QToolBoxPrivate::Page *c = d->page( index );
648 return ( c ? c->toolTip : QString::null );
649}
650
651/*! \reimp */
652void QToolBox::showEvent( QShowEvent *e )
653{
654 QWidget::showEvent( e );
655}
656
657/*! \reimp */
658void QToolBox::frameChanged()
659{
660 d->layout->setMargin( frameWidth() );
661 QFrame::frameChanged();
662}
663
664/*! \reimp */
665void QToolBox::styleChange(QStyle &style)
666{
667 d->updateTabs();
668 QFrame::styleChange(style);
669}
670
671/*!
672 This virtual handler is called after a new item was added or
673 inserted at position \a index.
674 */
675void QToolBox::itemInserted( int index )
676{
677 Q_UNUSED(index)
678}
679
680/*!
681 This virtual handler is called after an item was removed from
682 position \a index.
683 */
684void QToolBox::itemRemoved( int index )
685{
686 Q_UNUSED(index)
687}
688
689#endif //QT_NO_TOOLBOX
Note: See TracBrowser for help on using the repository browser.