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