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