]> SALOME platform Git repositories - modules/gui.git/blob - src/Qtx/QtxListAction.cxx
Salome HOME
no message
[modules/gui.git] / src / Qtx / QtxListAction.cxx
1 // File:      QtxListAction.cxx
2 // Author:    Sergey TELKOV (Based on code by Eugene AKSENOV)
3
4 #include "QtxListAction.h"
5
6 #include <qvbox.h>
7 #include <qlabel.h>
8 #include <qlayout.h>
9 #include <qtooltip.h>
10 #include <qlistbox.h>
11 #include <qtoolbar.h>
12 #include <qwmatrix.h>
13 #include <qpopupmenu.h>
14 #include <qtoolbutton.h>
15 #include <qobjectlist.h>
16 #include <qapplication.h>
17
18 static const char* list_arrow_icon[] = {
19 "10 6 2 1",
20 "# c #000000",
21 "  c none",
22 "          ",
23 " #######  ",
24 "  #####   ",
25 "   ###    ",
26 "    #     ",
27 "          "
28 };
29
30 /*!
31         Class: QtxListAction::ToolButton
32         Level: Internal
33 */
34
35 class QtxListAction::ToolButton : public QToolButton
36 {
37 public:
38   ToolButton( QtxListAction*, QWidget* = 0, const char* = 0 );
39   virtual ~ToolButton();
40
41   virtual QSize sizeHint() const;
42
43 private:
44   QtxListAction* myAction;
45 };
46
47 QtxListAction::ToolButton::ToolButton( QtxListAction* a, QWidget* parent, const char* name )
48 : QToolButton( parent, name ),
49 myAction( a )
50 {
51   setIconSet( QPixmap( list_arrow_icon ) );
52 }
53
54 QtxListAction::ToolButton::~ToolButton()
55 {
56   if ( myAction )
57     myAction->controlDeleted( this );
58 }
59
60 QSize QtxListAction::ToolButton::sizeHint() const
61 {
62   QSize sz = iconSet().pixmap().size();
63   return QSize( sz.width() + 2, sz.height() + 2 );
64 }
65
66 /*!
67         Class: QtxListAction
68         Level: Public
69 */
70
71 /*!
72         Name: QtxListAction [public]
73         Desc: Constructs an list action with given parent and name. If toggle is true the
74                     action will be a toggle action, otherwise it will be a command action.
75 */
76
77 QtxListAction::QtxListAction( QObject* parent, const char* name, bool toggle )
78 : QtxAction( parent, name, toggle ),
79 myFrame( 0 ),
80 myMode( Item ),
81 myRaise( false )
82 {
83   initialize();
84 }
85
86 /*!
87         Name: QtxListAction [public]
88         Desc: This constructor creates an action with the following properties: the
89                     description text, the icon or iconset icon, the menu text and keyboard
90                     accelerator. It is a child of given parent and named specified name.
91                     If toggle is true the action will be a toggle action, otherwise it will
92                     be a command action.
93 */
94
95 QtxListAction::QtxListAction( const QString& text, const QIconSet& icon,
96                               const QString& menuText, int accel,
97                               QObject* parent, const char* name, bool toggle )
98 : QtxAction( text, icon, menuText, accel, parent, name, toggle ),
99 myFrame( 0 ),
100 myMode( Item ),
101 myRaise( false )
102 {
103   initialize();
104 }
105
106 /*!
107         Name: QtxListAction [public]
108         Desc: This constructor creates an action with the following properties: the
109                   description text, the menu text and keyboard accelerator. It is a child
110                   of given parent and named specified name. If toggle is true the action
111                   will be a toggle action, otherwise it will be a command action.
112 */
113
114 QtxListAction::QtxListAction( const QString& text, const QString& menuText,
115                               int accel, QObject* parent, const char* name, bool toggle )
116 : QtxAction( text, menuText, accel, parent, name, toggle ),
117 myFrame( 0 ),
118 myMode( Item ),
119 myRaise( false )
120 {
121   initialize();
122 }
123
124 /*!
125         Name: ~QtxListAction [virtual public]
126         Desc: Destructor.
127 */
128
129 QtxListAction::~QtxListAction()
130 {
131 }
132
133 /*!
134         Name: popupMode [public]
135         Desc: Returns popup mode. If popup mode "Item" (default) then action will
136               be added into popup menu as menu item. If popup mode "SubMenu" then
137                     action will be added into popup menu as sub menu with list of items.
138 */
139
140 int QtxListAction::popupMode() const
141 {
142   return myMode;
143 }
144
145 /*!
146         Name: setPopupMode [public]
147         Desc: Set the popup mode. Popup mode define way in this action will be
148               added into popup menu. This function should be used before addTo.
149 */
150
151 void QtxListAction::setPopupMode( const int mode )
152 {
153   myMode = mode;
154 }
155
156 QStringList QtxListAction::names() const
157 {
158   QStringList lst;
159   if ( myFrame )
160     lst = myFrame->names();
161   return lst;
162 }
163
164 /*!
165         Name: addNames [public]
166         Desc: Fills the list of actions. Removes the old contents from
167               the list if 'clear' is true.
168 */
169
170 void QtxListAction::addNames( const QStringList& names, bool clear )
171 {
172   if ( !myFrame )
173     return;
174
175   if ( clear )
176     myFrame->clear();
177
178         myFrame->addNames( names );
179
180         QStringList lst = myFrame->names();
181         for ( PopupsMap::Iterator pit = myPopups.begin(); pit != myPopups.end(); ++pit )
182         {
183                 int i = 1;
184                 QPopupMenu* pm = (QPopupMenu*)pit.key();
185                 for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
186                         pit.data().popup->insertItem( *it, i++ );
187                 pm->setItemEnabled( pit.data().id, isEnabled() && pit.data().popup->count() );
188   }
189
190         for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
191         {
192                 bit.data().drop->setEnabled( isEnabled() && !lst.isEmpty() );
193                 bit.data().main->setEnabled( isEnabled() && !lst.isEmpty() );
194         }
195 }
196
197 /*!
198         Name: addTo [virtual public]
199         Desc: Adds this control to 'popup' or 'toolbar'.
200 */
201
202 bool QtxListAction::addTo( QWidget* w )
203 {
204         if ( myButtons.contains( w ) || myPopups.contains( w ) )
205                 return false;
206
207         if ( !w->inherits( "QPopupMenu" ) || popupMode() != SubMenu )
208                 if ( !QtxAction::addTo( w ) )
209                         return false;
210
211 #if QT_VER < 3
212   if ( w->children() )
213     addedTo( (QWidget*)w->children()->getLast(), w );
214 #endif
215
216   if ( w->inherits( "QToolBar" ) )
217   {
218                 Buttons& entry = myButtons[w];
219                 QHBox* dropWrap = new QHBox( w );
220     entry.drop = new ToolButton( this, dropWrap, "qt_dockwidget_internal" );
221
222     entry.drop->setTextLabel( text() );
223     entry.drop->setToggleButton( true );
224     entry.drop->setAutoRaise( entry.main->autoRaise() );
225
226     entry.main->setEnabled( isEnabled() && !myFrame->names().isEmpty() );
227     entry.drop->setEnabled( isEnabled() && !myFrame->names().isEmpty() );
228
229                 entry.main->installEventFilter( this );
230     entry.drop->installEventFilter( this );
231
232                 QToolTip::add( entry.drop, toolTip(), myTipGroup, statusTip() );
233
234     connect( entry.drop, SIGNAL( toggled( bool ) ), this, SLOT( onExpand( bool ) ) );
235   }
236         else if ( w->inherits( "QPopupMenu" ) && popupMode() == SubMenu )
237         {
238                 Popups entry;
239                 QPopupMenu* pm = (QPopupMenu*)w;
240
241                 entry.popup = new QPopupMenu( pm );
242                 entry.id = pm->insertItem( text(), entry.popup );
243
244                 int i = 1;
245                 QStringList lst = myFrame->names();
246                 for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
247                 {
248                         int id = entry.popup->insertItem( *it );
249                         entry.popup->setItemParameter( id, i++ );
250                 }
251                 pm->setItemEnabled( entry.id, isEnabled() && entry.popup->count() );
252                 myPopups.insert( w, entry );
253
254                 connect( entry.popup, SIGNAL( activated( int ) ), this, SLOT( onActivated( int ) ) );
255         }
256
257 #if QT_VER >= 3
258         connect( w, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
259 #endif
260
261     return true;
262 }
263
264 /*!
265         Name: addTo [virtual public]
266         Desc: Adds this control to 'popup' or 'toolbar'. Allow to specify index
267               for adding into 'popup'.
268 */
269
270 bool QtxListAction::addTo( QWidget* w, const int idx )
271 {
272   return QtxAction::addTo( w, idx );
273 }
274
275 /*!
276         Name: removeFrom [virtual public]
277         Desc: Removes this control from 'popup' or 'toolbar'.
278 */
279
280 bool QtxListAction::removeFrom( QWidget* w )
281 {
282   if ( !QtxAction::removeFrom( w ) )
283     return false;
284
285   if ( w->inherits( "QToolBar" ) )
286   {
287     if ( myFrame )
288       myFrame->hide();
289
290     if ( myButtons.contains( w ) )
291     {
292       Buttons& entry = myButtons[w];
293
294       if ( entry.drop->parent() && entry.drop->parent()->parent() == w )
295         delete entry.drop->parent();
296       else
297         delete entry.drop;
298     }
299     myButtons.remove( w );
300   }
301   else if ( w->inherits( "QPopupMenu" ) )
302     myPopups.remove( w );
303
304   return true;
305 }
306
307 /*!
308         Name: setEnabled [virtual public slot]
309         Desc: Enables/disables this control.
310 */
311
312 void QtxListAction::setEnabled( bool enable )
313 {
314   QtxAction::setEnabled( enable );
315
316         bool isOn = enable && !myFrame->names().isEmpty();
317
318         for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
319         {
320                 bit.data().drop->setEnabled( isOn );
321                 bit.data().main->setEnabled( isOn );
322         }
323
324         for ( PopupsMap::Iterator pit = myPopups.begin(); pit != myPopups.end(); ++pit )
325         {
326                 QPopupMenu* cont = (QPopupMenu*)pit.key();
327                 cont->setItemEnabled( pit.data().id, isOn );
328   }
329 }
330
331 /*!
332         Name: setMaxLines [public]
333         Desc: Sets max number of lines that list frame shows
334                   without vertical scroll bar. Default value is 5.
335 */
336
337 void QtxListAction::setMaxLines( int nlines )
338 {
339   myFrame->setMaxLines( nlines );
340 }
341
342 /*!
343         Name: setMaxLineChars [public]
344         Desc: Sets max number of characters in a line which list frame shows
345               without truncation. Default value is 12 (the widest char size is used).
346 */
347
348 void QtxListAction::setMaxLineChars( int nchars )
349 {
350   myFrame->setMaxLineChars( nchars );
351 }
352
353 /*!
354         Name: setComment [public]
355         Desc: Sets the format Qt string for comments displayed under the list
356               of actions for one action and for several actions.
357                     Ex. "Undo %1 actions" format string will work as "Undo 3 actions"
358                     when 3 actions are selected. The default format string is "%1".
359 */
360
361 void QtxListAction::setComment( const QString& c, const QString& sc )
362 {
363   if ( !myFrame )
364     return;
365
366   myFrame->setSingleComment( sc.isEmpty() ? c : sc );
367         myFrame->setMultipleComment( c );
368 }
369
370 /*!
371         Name: eventFilter [virtual public]
372         Desc: Reimplemented to paint the tool buttons in 2D/3D.
373 */
374
375 bool QtxListAction::eventFilter( QObject* o, QEvent* e )
376 {
377   if ( !myRaise && ( e->type() == QEvent::Enter || e->type() == QEvent::Leave ) )
378   {
379                 QWidget* obj = 0;
380                 QWidget* wid = widget( (QWidget*)o );
381                 if ( o == mainButton( wid ) )
382                         obj = dropButton( wid );
383                 else if ( o == dropButton( wid ) )
384                         obj = mainButton( wid );
385
386                 if ( obj )
387                 {
388                         myRaise = true;
389                         QApplication::sendEvent( obj, e );
390             obj->repaint();
391                         myRaise = false;
392                 }
393   }
394   return QObject::eventFilter( o, e );
395 }
396
397 /*!
398         Name: addedTo [protected]
399         Desc: Reimplemented for internal reasons.
400 */
401
402 void QtxListAction::addedTo( QWidget* actionWidget, QWidget* container )
403 {
404 #if QT_VER >= 3
405         QtxAction::addedTo( actionWidget, container );
406 #endif
407
408         if ( !container->inherits( "QToolBar" ) )
409                 return;
410
411         Buttons entry;
412         entry.main = (QToolButton*)actionWidget;
413
414         myButtons.insert( container, entry );
415 }
416
417 /*!
418         Name: initialize [private]
419         Desc: Initialization of object QtxListAction.
420 */
421
422 void QtxListAction::initialize()
423 {
424         myTipGroup = new QToolTipGroup( this );
425
426         myFrame = new QtxListFrame( qApp->mainWidget() );
427   myFrame->setMaxLines( 5 );
428   myFrame->setMaxLineChars( 7 );
429
430         myFrame->hide();
431
432         connect( myFrame, SIGNAL( hided() ), this, SLOT( onHided() ) );
433   connect( this, SIGNAL( activated() ), this, SLOT( onSingle() ) );
434         connect( myFrame, SIGNAL( selected( int ) ), this, SLOT( onMultiple( int ) ) );
435
436         connect( myTipGroup, SIGNAL( removeTip() ), this, SLOT( clearStatusText() ) );
437         connect( myTipGroup, SIGNAL( showTip( const QString& ) ), this, SLOT( showStatusText( const QString& ) ) );
438 }
439
440 /*!
441         Name: onSingle [private slot]
442         Desc: Called when a single action is selected.
443 */
444
445 void QtxListAction::onSingle()
446 {
447   emit activated( 1 );
448 }
449
450 /*!
451         Name: onMultiple [private slot]
452         Desc: Called when multiple actions are selected.
453 */
454
455 void QtxListAction::onMultiple( int numActions )
456 {
457   if ( myFrame )
458     myFrame->hide();
459
460   if ( numActions > 0 )
461     emit activated( numActions );
462 }
463
464 /*!
465         Name: onExpand [private slot]
466         Desc: Activates the list of actions.
467 */
468
469 void QtxListAction::onExpand( bool on )
470 {
471         const QObject* obj = sender();
472   if ( on )
473   {
474     QWidget* wid = widget( (QToolButton*)obj );
475                 QToolButton* main = mainButton( wid );
476     myFrame->setOwner( main );
477                 if ( main )
478                         myFrame->show();
479   }
480   else
481     myFrame->hide();
482 }
483
484 void QtxListAction::onHided()
485 {
486   for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
487         {
488     bool block = bit.data().drop->signalsBlocked();
489     bit.data().drop->blockSignals( true );
490     bit.data().drop->setOn( false );
491     bit.data().drop->blockSignals( block );
492   }
493 }
494
495 /*!
496         Name: onActivated [private slot]
497         Desc: Called when a sub menu item is activated.
498 */
499
500 void QtxListAction::onActivated( int id )
501 {
502         QPopupMenu* pm = (QPopupMenu*)sender();
503         int num = pm->itemParameter( id );
504         if ( num > 0 )
505                 emit activated( num );
506 }
507
508 /*!
509         Name: onDestroyed [private slot]
510         Desc: Called when a container widget is destroyed.
511 */
512
513 void QtxListAction::onDestroyed( QObject* obj )
514 {
515         if ( !obj->isWidgetType() )
516                 return;
517
518         myPopups.remove( (QWidget*)obj );
519         myButtons.remove( (QWidget*)obj );
520 }
521
522 /*!
523         Name: widget [private]
524         Desc: Returns container widget for specified control.
525 */
526
527 QWidget* QtxListAction::widget( QWidget* obj ) const
528 {
529         QWidget* wid = 0;
530         for ( PopupsMap::ConstIterator pit = myPopups.begin(); pit != myPopups.end() && !wid; ++pit )
531                 if ( pit.data().popup == obj )
532                         wid = pit.key();
533
534         for ( ButtonsMap::ConstIterator bit = myButtons.begin(); bit != myButtons.end() && !wid; ++bit )
535                 if ( bit.data().main == obj || bit.data().drop == obj )
536                         wid = bit.key();
537
538         return wid;
539 }
540
541 /*!
542         Name: listPopup [private]
543         Desc: Returns sub popup menu widget for specified container.
544 */
545
546 QPopupMenu* QtxListAction::listPopup( QWidget* wid ) const
547 {
548         QPopupMenu* p = 0;
549         if ( myPopups.contains( wid ) )
550                 p = myPopups[wid].popup;
551         return p;
552 }
553
554 /*!
555         Name: mainButton [private]
556         Desc: Returns main tool button for specified container.
557 */
558
559 QToolButton* QtxListAction::mainButton( QWidget* wid ) const
560 {
561         QToolButton* mb = 0;
562         if ( myButtons.contains( wid ) )
563                 mb = myButtons[wid].main;
564         return mb;
565 }
566
567 /*!
568         Name: dropButton [private]
569         Desc: Returns drop tool button for specified container.
570 */
571
572 QToolButton* QtxListAction::dropButton( QWidget* wid ) const
573 {
574         QToolButton* db = 0;
575         if ( myButtons.contains( wid ) )
576                 db = myButtons[wid].drop;
577         return db;
578 }
579
580 /*!
581         Name: controlDeleted [private]
582         Desc: Called when action child controls deleted.
583 */
584
585 void QtxListAction::controlDeleted( QWidget* wid )
586 {
587   QWidget* w = 0;
588   for ( ButtonsMap::Iterator it = myButtons.begin(); it != myButtons.end() && !w; ++it )
589   {
590     if ( it.data().main == wid || it.data().drop == wid )
591       w = it.key();
592   }
593
594   if ( w )
595   {
596     if ( myFrame )
597       myFrame->hide();
598
599     myButtons.remove( w );
600   }
601 }
602
603 /**********************************************************************
604 **  Class:  QtxListFrame
605 **  Descr:  Frame for the list of actions
606 **  Level:  Internal
607 ***********************************************************************/
608
609 class QtxListFrame::ScrollEvent : public QCustomEvent
610 {
611 public:
612         enum { Scroll = User + 1 };
613
614         ScrollEvent( bool down ) : QCustomEvent( Scroll ), myDown( down ) {};
615         virtual ~ScrollEvent() {};
616
617         bool isDown() const { return myDown; };
618
619 private:
620         bool myDown;
621 };
622
623 /*!
624         Class: QtxListAction
625         Level: Public
626 */
627
628 /*!
629     Constructor
630 */
631 QtxListFrame::QtxListFrame( QWidget* parent, WFlags f )
632 : QFrame( parent, 0, WStyle_Customize | WStyle_NoBorderEx | WType_Popup | WStyle_Tool | WStyle_StaysOnTop ),
633 myList( 0 ),
634 myOwner( 0 ),
635 myComment( 0 ),
636 myMaxLines( 5 ),
637 myMaxLineChars( 10 ),
638 myScrollVal( 0 ),
639 myScrollBlock( false )
640 {
641   QVBoxLayout* theLayout = new QVBoxLayout( this, 3 );
642         theLayout->setResizeMode( QLayout::FreeResize );
643
644   myList = new QListBox( this );
645   myList->setSelectionMode( QListBox::Multi );
646   myList->setHScrollBarMode( QScrollView::AlwaysOff );
647         myList->setFocusPolicy( NoFocus );
648
649         QPalette p = myList->palette();
650         p.setColor( QPalette::Inactive, QColorGroup::Highlight,
651                                       p.color( QPalette::Active, QColorGroup::Highlight ) );
652         p.setColor( QPalette::Inactive, QColorGroup::HighlightedText,
653                                       p.color( QPalette::Active, QColorGroup::HighlightedText ) );
654         myList->setPalette( p );
655
656   /*  We'll have the vertical scroll bar only and
657       truncate the names which are too wide */
658   connect( myList, SIGNAL( contentsMoving( int, int ) ), this, SLOT( onScroll( int, int ) ) );
659
660   myComment = new QLabel( this );
661   myComment->setFrameStyle( Panel | Sunken );
662   myComment->setAlignment( AlignCenter );
663   myMultipleComment = "%1";
664
665   theLayout->addWidget( myList );
666   theLayout->addWidget( myComment );
667
668   setFrameStyle( Panel | Raised );
669 }
670
671 QtxListFrame::~QtxListFrame()
672 {
673 }
674
675 /*!
676     Clears list of names [ public ]
677 */
678
679 void QtxListFrame::clear()
680 {
681         myNames.clear();
682         setNames( myNames );
683 }
684
685 void QtxListFrame::addNames( const QStringList& names )
686 {
687         for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
688                 myNames.append( *it );
689         setNames( myNames );
690 }
691
692 /*!
693     Sets a names to the list. Truncates the name to fit to the frame width.
694     Use QtxListAction::setMaxLineChar( int ) to set the width in characters. [ public ]
695 */
696
697 void QtxListFrame::setNames( const QStringList& names )
698 {
699   if ( !myList )
700                 return;
701
702         myList->clear();
703
704         for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
705         {
706                 QString s = *it;
707     QFontMetrics fm = myList->fontMetrics();
708     int maxW = myMaxLineChars * fm.maxWidth();
709     int w = fm.width( s );
710     if ( w > maxW )
711     {
712       QString extra( "..." );
713       int len = s.length();
714       int extraLen = fm.width( extra ) + 1;
715       while ( true )
716       {
717         w = fm.width( s, --len );
718         if ( w + extraLen < maxW )
719         {
720           s = s.left( len );
721           break;
722         }
723       }
724       s += extra;
725     }
726     myList->insertItem( s );
727   }
728 }
729
730 const QStringList QtxListFrame::names() const
731 {
732         return myNames;
733 }
734
735 /*!
736     Sets max number of lines shown without activation of vertical scroll bar. [ public ]
737 */
738
739 void QtxListFrame::setMaxLines( int maxLines )
740 {
741   myMaxLines = maxLines;
742 }
743
744 /*!
745     Sets max number of chars in line ( the rest will be truncated ). [ public ]
746 */
747
748 void QtxListFrame::setMaxLineChars( int maxChars )
749 {
750         if ( myMaxLineChars == maxChars )
751                 return;
752
753   myMaxLineChars = maxChars;
754         setNames( myNames );
755 }
756
757 /*!
758     Sets the format of single comment. [ public ]
759 */
760
761 void QtxListFrame::setSingleComment( const QString& comment )
762 {
763   mySingleComment = comment;
764         setNames( myNames );
765   updateComment();
766 }
767
768 /*!
769     Sets the format of multiple comment. [ public ]
770 */
771
772 void QtxListFrame::setMultipleComment( const QString& comment )
773 {
774   myMultipleComment = comment;
775         setNames( myNames );
776   updateComment();
777 }
778
779 /*!
780     Updates comment display. [ public ]
781 */
782
783 void QtxListFrame::updateComment()
784 {
785         QString com;
786         int selNum = selected();
787         if ( selNum > 1 )
788                 com = myMultipleComment;
789         else if ( selNum > 0 && !mySingleComment.isEmpty() )
790                 com = mySingleComment;
791
792         if ( !com.isEmpty() )
793                 com = com.arg( selNum );
794
795   myComment->setText( com );
796 }
797
798 void QtxListFrame::setOwner( QWidget* wo )
799 {
800   myOwner = wo;
801   if ( myOwner )
802   {
803     QPoint lpos;
804     if ( myOwner->parentWidget() && myOwner->parentWidget()->inherits( "QToolBar" ) &&
805          ((QToolBar*)myOwner->parentWidget())->orientation() == Qt::Vertical )
806       lpos = QPoint( myOwner->x() + myOwner->width() + 2, myOwner->y() );
807     else
808                   lpos = QPoint( myOwner->x(), myOwner->y() + myOwner->height() + 2 );
809       QPoint gpos = myOwner->parentWidget() ? myOwner->parentWidget()->mapToGlobal( lpos )
810                                             : myOwner->mapToGlobal( lpos );
811     if ( parentWidget() )
812                         move( parentWidget()->mapFromGlobal( gpos ) );
813     else
814                   move( gpos );
815   }
816 }
817
818 /*!
819     Validates the action. [ private slot ]
820 */
821
822 void QtxListFrame::accept()
823 {
824   emit selected( selected() );
825 }
826
827 /*!
828     Cancels the action. [ private slot ]
829 */
830
831 void QtxListFrame::reject()
832 {
833   emit selected( 0 );
834 }
835
836 /*!
837     Initializes / shows the frame. [ virtual public slot ]
838 */
839
840 void QtxListFrame::show()
841 {
842   int cnt = (int)myList->count();
843   if ( cnt )
844   {
845     myScrollVal = 0;
846                 myList->setTopItem( 0 );
847     myList->clearSelection();
848                 myList->setMinimumSize( 0, ( QMIN( cnt + 1, myMaxLines ) ) * myList->itemHeight() + 1 );
849     setSelected( 1 );
850
851     int linstep = myList->itemHeight();
852     myList->verticalScrollBar()->setLineStep( linstep );
853     myList->verticalScrollBar()->setPageStep( myMaxLines * linstep );
854
855     QFontMetrics fm = myList->fontMetrics();
856     layout()->invalidate();
857     int maxHeight = layout()->minimumSize().height() + layout()->margin();
858     int maxWidth = myMaxLineChars * fm.maxWidth();
859                 for ( uint i = 0; i <= myList->count(); i++ )
860                         maxWidth = QMAX( maxWidth, fm.width( myList->text( i ) ) );
861
862                 resize( width(), maxHeight );
863
864                 myList->updateGeometry();
865
866                 QApplication::sendPostedEvents();
867
868     myList->resizeContents( myList->contentsWidth(),
869                             myList->itemHeight() * cnt );
870     if ( myList->contentsHeight() > myList->visibleHeight() )
871          maxWidth += myList->verticalScrollBar()->width();
872
873                 QString single = mySingleComment.arg( cnt );
874                 QString multi = myMultipleComment.arg( cnt );
875                 int comWidth = QMAX( myComment->fontMetrics().width( single ), myComment->fontMetrics().width( multi ) );
876                 if ( myComment->frameWidth() )
877                         comWidth += myComment->fontMetrics().width( "x" );
878
879                 maxWidth = QMAX( maxWidth, comWidth );
880
881                 resize( maxWidth, maxHeight );
882     updateComment();
883
884     qApp->installEventFilter( this );
885
886     QFrame::show();
887   }
888 }
889
890 /*!
891     Cleanup. [ virtual public slot ]
892 */
893
894 void QtxListFrame::hide()
895 {
896   qApp->removeEventFilter( this );
897   QFrame::hide();
898   emit hided();
899 }
900
901 /*!
902     Processes KeyUp/KeyDown, PageUp/PageDown, CR and Esc keys.
903     Returns 'true' if event is eaten, 'false' otherwise. [ private ]
904 */
905
906 bool QtxListFrame::handleKeyEvent( QObject* , QKeyEvent* e )
907 {
908   if ( e->type() == QEvent::KeyRelease )
909     return true;
910
911   int selNum = selected();
912   switch( e->key() )
913   {
914   case Key_Up:
915     setSelected( QMAX( 1, selNum - 1 ) );
916     break;
917   case Key_Down:
918     setSelected( QMAX( 1, selNum + 1 ) );
919     break;
920   case Key_PageUp:
921     setSelected( QMAX( 1, selNum - myMaxLines ) );
922     break;
923   case Key_PageDown:
924           setSelected( selNum += myMaxLines );
925     break;
926   case Key_Home:
927           setSelected( 1 );
928                 break;
929   case Key_End:
930           setSelected( myList->count() );
931                 break;
932   case Key_Return:
933     accept();
934     break;
935   case Key_Escape:
936     reject();
937     break;
938   }
939   return true;
940 }
941
942 /*!
943     Selects items on move, validates on button release. If object 'o' is not our name list,
944     we close the frame. Returns 'true' if event is eaten, 'false' otherwise. [ private ]
945 */
946
947 bool QtxListFrame::handleMouseEvent( QObject* o, QMouseEvent* e )
948 {
949   switch( e->type() )
950   {
951   case QEvent::MouseButtonPress:
952   {
953           if ( o != myList->viewport() && !isPopup() )
954                   reject();
955     return true;
956   }
957   case QEvent::MouseMove:
958   {
959     if ( o == myList->viewport() )
960     {
961       QListBoxItem* lbi = myList->itemAt( e->pos() );
962       if ( lbi )
963         setSelected( myList->index( lbi ) + 1 );
964     }
965     break;
966   }
967   case QEvent::MouseButtonRelease:
968   {
969     if ( o == myList->viewport() )
970       accept();
971     else
972                   reject();
973     break;
974   }
975   default:
976     break;
977   }
978   return true;
979 }
980
981 bool QtxListFrame::event( QEvent* e )
982 {
983   if ( e->type() != (int)ScrollEvent::Scroll )
984     return QFrame::event( e );
985
986   ScrollEvent* se = (ScrollEvent*)e;
987   if ( se->isDown() )
988     setSelected( myList->topItem() + myList->numItemsVisible() );
989   else
990     setSelected( myList->topItem() + 1 );
991   
992   return true;
993 }
994
995 /*!
996     Watches mouse events on the viewport of the list. [ virtual public ]
997 */
998
999 bool QtxListFrame::eventFilter( QObject* o, QEvent* e )
1000 {
1001   bool isKeyEvent = ( e->type() == QEvent::KeyPress ||
1002                       e->type() == QEvent::KeyRelease );
1003   bool isMouseEvent = ( e->type() == QEvent::MouseMove ||
1004                         e->type() == QEvent::MouseButtonPress ||
1005                         e->type() == QEvent::MouseButtonRelease ||
1006                         e->type() == QEvent::MouseButtonDblClick );
1007
1008   if ( isKeyEvent )
1009   {
1010     if ( handleKeyEvent( o, ( QKeyEvent* )e ) )
1011       return true;
1012   }
1013   else if ( isMouseEvent && o != myList->verticalScrollBar() )
1014   {
1015     if ( handleMouseEvent( o, ( QMouseEvent*)e ) )
1016       return true;
1017   }
1018
1019   if ( o != this && ( e->type() == QEvent::Resize || e->type() == QEvent::Move ) )
1020     setOwner( myOwner );
1021
1022   return QFrame::eventFilter( o, e );
1023 }
1024
1025 /*!
1026     Selects operations while scrolling the list. [ private slot ]
1027 */
1028
1029 void QtxListFrame::onScroll( int x, int y )
1030 {
1031   int dx = y - myScrollVal;
1032         if ( !myScrollBlock )
1033                 QApplication::postEvent( this, new ScrollEvent( dx > 0 ) );
1034   myScrollVal = y;
1035 }
1036
1037 /*!
1038     Selects the actions [ 0 - lastSel ]. [ public ]
1039 */
1040
1041 void QtxListFrame::setSelected( const int lastSel )
1042 {
1043         int last = QMIN( lastSel, (int)myList->count() );
1044
1045         for ( int i = 0; i < (int)myList->count(); i++ )
1046                 myList->setSelected( i, i < last );
1047
1048         int item = last - 1;
1049
1050         myScrollBlock = true;
1051
1052         if ( item < myList->topItem() )
1053                 myList->setTopItem( item );
1054
1055         if ( item >= myList->topItem() + myList->numItemsVisible() )
1056                 myList->setTopItem( item - myList->numItemsVisible() + 1 );
1057
1058         myScrollBlock = false;
1059
1060   myList->clearFocus();
1061
1062   updateComment();
1063 }
1064
1065 int QtxListFrame::selected() const
1066 {
1067         uint sel = 0;
1068         while ( sel < myList->count() && myList->isSelected( sel ) )
1069                 sel++;
1070         return sel;
1071 }