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