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