Salome HOME
Update copyrights
[modules/gui.git] / src / Qtx / QtxListAction.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 5e40d15..8b18e21
-// File:      QtxListAction.cxx
-// Author:    Sergey TELKOV (Based on code by Eugene AKSENOV)
+// Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
+// File:      QtxListAction.cxx
+// Author:    Sergey TELKOV
+//
 #include "QtxListAction.h"
 
-#include <qvbox.h>
-#include <qlabel.h>
-#include <qlayout.h>
-#include <qtooltip.h>
-#include <qlistbox.h>
-#include <qtoolbar.h>
-#include <qwmatrix.h>
-#include <qpopupmenu.h>
-#include <qtoolbutton.h>
-#include <qobjectlist.h>
-#include <qapplication.h>
-
-static const char* list_arrow_icon[] = {
-"10 6 2 1",
-"# c #000000",
-"  c none",
-"          ",
-" #######  ",
-"  #####   ",
-"   ###    ",
-"    #     ",
-"          "
-};
+#include <QMenu>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QMouseEvent>
+#include <QListWidget>
+#include <QToolButton>
+#include <QApplication>
 
 /*!
-       Class: QtxListAction::ToolButton
-       Level: Internal
+  \class QtxListAction::ScrollEvent
+  \internal
+  \brief Event for the scrolling in the list of actions.
 */
 
-class QtxListAction::ToolButton : public QToolButton
+class QtxListAction::ScrollEvent : public QEvent
 {
 public:
-  ToolButton( QtxListAction*, QWidget* = 0, const char* = 0 );
-  virtual ~ToolButton();
+  enum { Scroll = User + 1 };
+
+  ScrollEvent( bool down ) : QEvent( (QEvent::Type)Scroll ), myDown( down ) {}
+  virtual ~ScrollEvent() {}
 
-  virtual QSize sizeHint() const;
+  bool isDown() const { return myDown; }
 
 private:
-  QtxListAction* myAction;
+  bool myDown;
 };
 
-QtxListAction::ToolButton::ToolButton( QtxListAction* a, QWidget* parent, const char* name )
-: QToolButton( parent, name ),
-myAction( a )
-{
-  setIconSet( QPixmap( list_arrow_icon ) );
-}
-
-QtxListAction::ToolButton::~ToolButton()
-{
-  if ( myAction )
-    myAction->controlDeleted( this );
-}
-
-QSize QtxListAction::ToolButton::sizeHint() const
-{
-  QSize sz = iconSet().pixmap().size();
-  return QSize( sz.width() + 2, sz.height() + 2 );
-}
-
 /*!
-       Class: QtxListAction
-       Level: Public
+  \class QtxListAction::ListWidget
+  \internal
+  \brief List of actions.
 */
 
-/*!
-       Name: QtxListAction [public]
-       Desc: Constructs an list action with given parent and name. If toggle is true the
-                   action will be a toggle action, otherwise it will be a command action.
-*/
-
-QtxListAction::QtxListAction( QObject* parent, const char* name, bool toggle )
-: QtxAction( parent, name, toggle ),
-myFrame( 0 ),
-myMode( Item ),
-myRaise( false )
+class QtxListAction::ListWidget : public QListWidget
 {
-  initialize();
-}
+public:
+  ListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {}
+  virtual ~ListWidget() {}
+
+protected:
+  virtual void scrollContentsBy( int dx, int dy )
+  {
+    QListWidget::scrollContentsBy( dx, dy );
+    if ( dy != 0 )
+      QApplication::postEvent( viewport(), new ScrollEvent( dy <= 0 ) );
+  }
+};
 
 /*!
-       Name: QtxListAction [public]
-       Desc: This constructor creates an action with the following properties: the
-                   description text, the icon or iconset icon, the menu text and keyboard
-                   accelerator. It is a child of given parent and named specified name.
-                   If toggle is true the action will be a toggle action, otherwise it will
-                   be a command action.
+  \class QtxListAction::ListFrame
+  \internal
+  \brief Expanding frame with action list and comment.
 */
 
-QtxListAction::QtxListAction( const QString& text, const QIconSet& icon,
-                              const QString& menuText, int accel,
-                              QObject* parent, const char* name, bool toggle )
-: QtxAction( text, icon, menuText, accel, parent, name, toggle ),
-myFrame( 0 ),
-myMode( Item ),
-myRaise( false )
+class QtxListAction::ListFrame: public QMenu
 {
-  initialize();
-}
+public:
+  ListFrame( QtxListAction*, QWidget* parent );
+  virtual ~ListFrame();
 
-/*!
-       Name: QtxListAction [public]
-       Desc: This constructor creates an action with the following properties: the
-                 description text, the menu text and keyboard accelerator. It is a child
-                 of given parent and named specified name. If toggle is true the action
-                 will be a toggle action, otherwise it will be a command action.
-*/
+  void                    clear();
+  const QStringList       names() const;
+  void                    addNames( const QStringList& );
 
-QtxListAction::QtxListAction( const QString& text, const QString& menuText,
-                              int accel, QObject* parent, const char* name, bool toggle )
-: QtxAction( text, menuText, accel, parent, name, toggle ),
-myFrame( 0 ),
-myMode( Item ),
-myRaise( false )
-{
-  initialize();
-}
+  void                    setSingleComment( const QString& );
+  void                    setMultipleComment( const QString& );
 
-/*!
-       Name: ~QtxListAction [virtual public]
-       Desc: Destructor.
-*/
+  int                     selected() const;
+  void                    setSelected( const int );
 
-QtxListAction::~QtxListAction()
-{
-}
+  int                     linesNumber() const;
+  int                     charsNumber() const;
 
-/*!
-       Name: popupMode [public]
-       Desc: Returns popup mode. If popup mode "Item" (default) then action will
-             be added into popup menu as menu item. If popup mode "SubMenu" then
-                   action will be added into popup menu as sub menu with list of items.
-*/
+  void                    setLinesNumber( const int );
+  void                    setCharsNumber( const int );
 
-int QtxListAction::popupMode() const
-{
-  return myMode;
-}
+  virtual QSize           sizeHint() const;
+  virtual QSize           minimumSizeHint() const;
 
-/*!
-       Name: setPopupMode [public]
-       Desc: Set the popup mode. Popup mode define way in this action will be
-             added into popup menu. This function should be used before addTo.
-*/
+  virtual bool            eventFilter( QObject*, QEvent* );
 
-void QtxListAction::setPopupMode( const int mode )
-{
-  myMode = mode;
-}
+  virtual void            setVisible( bool );
 
-/*!
-       Name: addNames [public]
-       Desc: Fills the list of actions. Removes the old contents from
-             the list if 'clear' is true.
-*/
+protected:
+  virtual void            keyPressEvent( QKeyEvent* );
 
-void QtxListAction::addNames( const QStringList& names, bool clear )
-{
-  if ( !myFrame )
-    return;
+private:
+  void                    accept();
+  void                    updateComment();
+  void                    setNames( const QStringList& );
+  void                    removePostedEvens( QObject*, int );
 
-  if ( clear )
-    myFrame->clear();
+private:
+  QListWidget*            myList;
+  QStringList             myNames;
+  QtxListAction*          myAction;
+  QLabel*                 myComment;
 
-       myFrame->addNames( names );
+  int                     myLines;
+  int                     myChars;
 
-       QStringList lst = myFrame->names();
-       for ( PopupsMap::Iterator pit = myPopups.begin(); pit != myPopups.end(); ++pit )
-       {
-               int i = 1;
-               QPopupMenu* pm = (QPopupMenu*)pit.key();
-               for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
-                       pit.data().popup->insertItem( *it, i++ );
-               pm->setItemEnabled( pit.data().id, isEnabled() && pit.data().popup->count() );
-  }
+  QString                 mySingleComment;
+  QString                 myMultipleComment;
+};
+
+/*!
+  \brief Constructor.
+  \param a list action
+  \param parent parent widget
+*/
+QtxListAction::ListFrame::ListFrame( QtxListAction* a, QWidget* parent )
+: QMenu( parent ),
+  myList( 0 ),
+  myAction( a ),
+  myComment( 0 ),
+  myLines( 5 ),
+  myChars( 5 )
+{
+  QVBoxLayout* top = new QVBoxLayout( this );
+  top->setMargin( 0 );
+  QFrame* main = new QFrame( this );
+  main->setFrameStyle( QFrame::Panel | QFrame::Raised );
+  top->addWidget( main );
+
+  QVBoxLayout* base = new QVBoxLayout( main );
+  base->setMargin( 3 );
+  base->setSpacing( 2 );
+
+  myList = new ListWidget( main );
+  myList->setSelectionMode( QListWidget::MultiSelection );
+  myList->setVerticalScrollMode( QListWidget::ScrollPerItem );
+  myList->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
+  myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+  myList->viewport()->installEventFilter( this );
+  myList->viewport()->setMouseTracking( true );
+  myList->setFocusPolicy( Qt::NoFocus );
+
+  myComment = new QLabel( main );
+  myComment->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+  myComment->setAlignment( Qt::AlignCenter );
+  myMultipleComment = "%1";
 
-       for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
-       {
-               bit.data().drop->setEnabled( isEnabled() && !lst.isEmpty() );
-               bit.data().main->setEnabled( isEnabled() && !lst.isEmpty() );
-       }
+  base->addWidget( myList );
+  base->addWidget( myComment );
 }
 
 /*!
-       Name: addTo [virtual public]
-       Desc: Adds this control to 'popup' or 'toolbar'.
+  \brief Destructor.
 */
-
-bool QtxListAction::addTo( QWidget* w )
+QtxListAction::ListFrame::~ListFrame()
 {
-       if ( myButtons.contains( w ) || myPopups.contains( w ) )
-               return false;
-
-       if ( !w->inherits( "QPopupMenu" ) || popupMode() != SubMenu )
-               if ( !QtxAction::addTo( w ) )
-                       return false;
-
-#if QT_VER < 3
-  if ( w->children() )
-    addedTo( (QWidget*)w->children()->getLast(), w );
-#endif
-
-  if ( w->inherits( "QToolBar" ) )
-  {
-               Buttons& entry = myButtons[w];
-               QHBox* dropWrap = new QHBox( w );
-    entry.drop = new ToolButton( this, dropWrap, "qt_dockwidget_internal" );
-
-    entry.drop->setTextLabel( text() );
-    entry.drop->setToggleButton( true );
-    entry.drop->setAutoRaise( entry.main->autoRaise() );
-
-    entry.main->setEnabled( isEnabled() && !myFrame->names().isEmpty() );
-    entry.drop->setEnabled( isEnabled() && !myFrame->names().isEmpty() );
-
-               entry.main->installEventFilter( this );
-    entry.drop->installEventFilter( this );
-
-               QToolTip::add( entry.drop, toolTip(), myTipGroup, statusTip() );
-
-    connect( entry.drop, SIGNAL( toggled( bool ) ), this, SLOT( onExpand( bool ) ) );
-  }
-       else if ( w->inherits( "QPopupMenu" ) && popupMode() == SubMenu )
-       {
-               Popups entry;
-               QPopupMenu* pm = (QPopupMenu*)w;
-
-               entry.popup = new QPopupMenu( pm );
-               entry.id = pm->insertItem( text(), entry.popup );
-
-               int i = 1;
-               QStringList lst = myFrame->names();
-               for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
-               {
-                       int id = entry.popup->insertItem( *it );
-                       entry.popup->setItemParameter( id, i++ );
-               }
-               pm->setItemEnabled( entry.id, isEnabled() && entry.popup->count() );
-               myPopups.insert( w, entry );
-
-               connect( entry.popup, SIGNAL( activated( int ) ), this, SLOT( onActivated( int ) ) );
-       }
-
-#if QT_VER >= 3
-       connect( w, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
-#endif
-
-    return true;
 }
 
 /*!
-       Name: addTo [virtual public]
-       Desc: Adds this control to 'popup' or 'toolbar'. Allow to specify index
-             for adding into 'popup'.
+  \brief Clear list of names.
 */
-
-bool QtxListAction::addTo( QWidget* w, const int idx )
+void QtxListAction::ListFrame::clear()
 {
-  return QtxAction::addTo( w, idx );
+  myNames.clear();
+  setNames( myNames );
 }
 
 /*!
-       Name: removeFrom [virtual public]
-       Desc: Removes this control from 'popup' or 'toolbar'.
+  \brief Add names to the list.
+
+  Truncates each name to fit the frame width.
+  Method QtxListAction::setCharsNumber(int) can be used to change
+  the frame width (in characters).
+
+  \param names list of names to be added
+  \sa setNames(), QtxListAction::setCharsNumber(int)
 */
+void QtxListAction::ListFrame::addNames( const QStringList& names )
+{
+  for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
+    myNames.append( *it );
+  setNames( myNames );
+}
+
+/*!
+  \brief Set names to the list.
 
-bool QtxListAction::removeFrom( QWidget* w )
+  Truncates each name to fit the frame width.
+  Method QtxListAction::setCharsNumber(int) can be used to change
+  the frame width (in characters).
+
+  \param names list of names to be set
+  \sa addNames(), QtxListAction::setCharsNumber(int)
+*/
+void QtxListAction::ListFrame::setNames( const QStringList& names )
 {
-  if ( !QtxAction::removeFrom( w ) )
-    return false;
+  if ( !myList )
+    return;
 
-  if ( w->inherits( "QToolBar" ) )
+  myList->clear();
+  QStringList strList;
+  for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
   {
-    if ( myFrame )
-      myFrame->hide();
-
-    if ( myButtons.contains( w ) )
+    QString s = *it;
+    QFontMetrics fm = myList->fontMetrics();
+    int maxW = charsNumber() * fm.maxWidth();
+    int w = fm.width( s );
+    if ( w > maxW )
     {
-      Buttons& entry = myButtons[w];
-
-      if ( entry.drop->parent() && entry.drop->parent()->parent() == w )
-        delete entry.drop->parent();
-      else
-        delete entry.drop;
+      QString extra( "..." );
+      int len = s.length();
+      int extraLen = fm.width( extra ) + 1;
+      while ( true )
+      {
+        w = fm.width( s, --len );
+        if ( w + extraLen < maxW )
+        {
+          s = s.left( len );
+          break;
+        }
+      }
+      s += extra;
     }
-    myButtons.remove( w );
+    strList.append( s );
   }
-  else if ( w->inherits( "QPopupMenu" ) )
-    myPopups.remove( w );
-
-  return true;
+  myList->addItems( strList );
 }
 
 /*!
-       Name: setEnabled [virtual public slot]
-       Desc: Enables/disables this control.
+  \brief Get list of names.
+  \return list of names
 */
-
-void QtxListAction::setEnabled( bool enable )
+const QStringList QtxListAction::ListFrame::names() const
 {
-  QtxAction::setEnabled( enable );
-
-       bool isOn = enable && !myFrame->names().isEmpty();
-
-       for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
-       {
-               bit.data().drop->setEnabled( isOn );
-               bit.data().main->setEnabled( isOn );
-       }
-
-       for ( PopupsMap::Iterator pit = myPopups.begin(); pit != myPopups.end(); ++pit )
-       {
-               QPopupMenu* cont = (QPopupMenu*)pit.key();
-               cont->setItemEnabled( pit.data().id, isOn );
-  }
+  return myNames;
 }
 
 /*!
-       Name: setMaxLines [public]
-       Desc: Sets max number of lines that list frame shows
-                 without vertical scroll bar. Default value is 5.
+  \brief Get maximum numer of lines shown without activation of vertical scroll bar.
+  \return number of lines
+  \sa setLinesNumber(), charsNumber(), setCharsNumber()
 */
-
-void QtxListAction::setMaxLines( int nlines )
+int QtxListAction::ListFrame::linesNumber() const
 {
-  myFrame->setMaxLines( nlines );
+  return myLines;
 }
 
 /*!
-       Name: setMaxLineChars [public]
-       Desc: Sets max number of characters in a line which list frame shows
-             without truncation. Default value is 12 (the widest char size is used).
-*/
+  \brief Get maximum numer of characters in the line.
 
-void QtxListAction::setMaxLineChars( int nchars )
-{
-  myFrame->setMaxLineChars( nchars );
-}
+  If the name length is greater than this value, it will be truncated.
 
-/*!
-       Name: setComment [public]
-       Desc: Sets the format Qt string for comments displayed under the list
-             of actions for one action and for several actions.
-                   Ex. "Undo %1 actions" format string will work as "Undo 3 actions"
-                   when 3 actions are selected. The default format string is "%1".
+  \return number of characters
+  \sa setCharsNumber(), linesNumber(), setLinesNumber()
 */
-
-void QtxListAction::setComment( const QString& c, const QString& sc )
+int QtxListAction::ListFrame::charsNumber() const
 {
-  if ( !myFrame )
-    return;
-
-  myFrame->setSingleComment( sc.isEmpty() ? c : sc );
-       myFrame->setMultipleComment( c );
+  return myChars;
 }
 
 /*!
-       Name: eventFilter [virtual public]
-       Desc: Reimplemented to paint the tool buttons in 2D/3D.
+  \brief Set maximum numer of lines shown without activation of vertical scroll bar.
+  \param maxLines number of lines
+  \sa linesNumber(), charsNumber(), setCharsNumber()
 */
-
-bool QtxListAction::eventFilter( QObject* o, QEvent* e )
+void QtxListAction::ListFrame::setLinesNumber( const int maxLines )
 {
-  if ( !myRaise && ( e->type() == QEvent::Enter || e->type() == QEvent::Leave ) )
-  {
-               QWidget* obj = 0;
-               QWidget* wid = widget( (QWidget*)o );
-               if ( o == mainButton( wid ) )
-                       obj = dropButton( wid );
-               else if ( o == dropButton( wid ) )
-                       obj = mainButton( wid );
-
-               if ( obj )
-               {
-                       myRaise = true;
-                       QApplication::sendEvent( obj, e );
-            obj->repaint();
-                       myRaise = false;
-               }
-  }
-  return QObject::eventFilter( o, e );
+  myLines = maxLines;
 }
 
 /*!
-       Name: addedTo [protected]
-       Desc: Reimplemented for internal reasons.
-*/
-
-void QtxListAction::addedTo( QWidget* actionWidget, QWidget* container )
-{
-#if QT_VER >= 3
-       QtxAction::addedTo( actionWidget, container );
-#endif
+  \brief Set maximum numer of characters in the line.
 
-       if ( !container->inherits( "QToolBar" ) )
-               return;
+  If the name length is greater than this value, it will be truncated.
 
-       Buttons entry;
-       entry.main = (QToolButton*)actionWidget;
+  \param maxChars number of characters
+  \sa charsNumber(), linesNumber(), setLinesNumber()
+*/
+void QtxListAction::ListFrame::setCharsNumber( const int maxChars )
+{
+  if ( myChars == maxChars )
+    return;
 
-       myButtons.insert( container, entry );
+  myChars = maxChars;
+  setNames( myNames );
 }
 
 /*!
-       Name: initialize [private]
-       Desc: Initialization of object QtxListAction.
+  \brief Set comment which is displayed when single name is selected.
+  \param comment comment format
 */
-
-void QtxListAction::initialize()
+void QtxListAction::ListFrame::setSingleComment( const QString& comment )
 {
-       myTipGroup = new QToolTipGroup( this );
-
-       myFrame = new QtxListFrame( qApp->mainWidget() );
-  myFrame->setMaxLines( 5 );
-  myFrame->setMaxLineChars( 7 );
-
-       myFrame->hide();
-
-       connect( myFrame, SIGNAL( hided() ), this, SLOT( onHided() ) );
-  connect( this, SIGNAL( activated() ), this, SLOT( onSingle() ) );
-       connect( myFrame, SIGNAL( selected( int ) ), this, SLOT( onMultiple( int ) ) );
-
-       connect( myTipGroup, SIGNAL( removeTip() ), this, SLOT( clearStatusText() ) );
-       connect( myTipGroup, SIGNAL( showTip( const QString& ) ), this, SLOT( showStatusText( const QString& ) ) );
+  mySingleComment = comment;
+  setNames( myNames );
+  updateComment();
 }
 
 /*!
-       Name: onSingle [private slot]
-       Desc: Called when a single action is selected.
+  \brief Set comment which is displayed when multiple names are selected.
+  \param comment comment format
 */
-
-void QtxListAction::onSingle()
+void QtxListAction::ListFrame::setMultipleComment( const QString& comment )
 {
-  emit activated( 1 );
+  myMultipleComment = comment;
+  setNames( myNames );
+  updateComment();
 }
 
 /*!
-       Name: onMultiple [private slot]
-       Desc: Called when multiple actions are selected.
+  \brief Update displayed comment.
 */
-
-void QtxListAction::onMultiple( int numActions )
+void QtxListAction::ListFrame::updateComment()
 {
-  if ( myFrame )
-    myFrame->hide();
-
-  if ( numActions > 0 )
-    emit activated( numActions );
+  QString com;
+  int selNum = selected();
+  if ( selNum > 1 )
+    com = myMultipleComment;
+  else if ( selNum > 0 && !mySingleComment.isEmpty() )
+    com = mySingleComment;
+  
+  if ( !com.isEmpty() )
+    com = com.arg( selNum );
+  
+  myComment->setText( com );
 }
 
 /*!
-       Name: onExpand [private slot]
-       Desc: Activates the list of actions.
+  \brief Get preferable size for the list widget.
+  \return preferable size
 */
-
-void QtxListAction::onExpand( bool on )
+QSize QtxListAction::ListFrame::sizeHint() const
 {
-       const QObject* obj = sender();
-  if ( on )
-  {
-    QWidget* wid = widget( (QToolButton*)obj );
-               QToolButton* main = mainButton( wid );
-    myFrame->setOwner( main );
-               if ( main )
-                       myFrame->show();
-  }
-  else
-    myFrame->hide();
+  return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
+                qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
+                myComment->sizeHint().height() );
 }
 
-void QtxListAction::onHided()
+/*!
+  \brief Get preferable minimum size for the list widget.
+  \return preferable minimum size
+*/
+QSize QtxListAction::ListFrame::minimumSizeHint() const
 {
-  for ( ButtonsMap::Iterator bit = myButtons.begin(); bit != myButtons.end(); ++bit )
-       {
-    bool block = bit.data().drop->signalsBlocked();
-    bit.data().drop->blockSignals( true );
-    bit.data().drop->setOn( false );
-    bit.data().drop->blockSignals( block );
-  }
+  return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
+                qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
+                myComment->sizeHint().height() );
 }
 
 /*!
-       Name: onActivated [private slot]
-       Desc: Called when a sub menu item is activated.
+  \brief Validate the action.
 */
-
-void QtxListAction::onActivated( int id )
+void QtxListAction::ListFrame::accept()
 {
-       QPopupMenu* pm = (QPopupMenu*)sender();
-       int num = pm->itemParameter( id );
-       if ( num > 0 )
-               emit activated( num );
+  int sel = selected();
+  if ( sel && myAction )
+    myAction->onMultiple( sel );
 }
 
 /*!
-       Name: onDestroyed [private slot]
-       Desc: Called when a container widget is destroyed.
+  \brief Called when list widget is shown/hidden.
+  \param on if \c true, widget is shown, otherswise it is hidden
 */
-
-void QtxListAction::onDestroyed( QObject* obj )
+void QtxListAction::ListFrame::setVisible( bool on )
 {
-       if ( !obj->isWidgetType() )
-               return;
+  if ( on )
+  {
+    myList->setFocus();
+    myList->scrollToItem( myList->item( 0 ), QListWidget::PositionAtTop );
+    setSelected( 0 );
+    updateComment();
+  }
 
-       myPopups.remove( (QWidget*)obj );
-       myButtons.remove( (QWidget*)obj );
+  QMenu::setVisible( on );
 }
 
 /*!
-       Name: widget [private]
-       Desc: Returns container widget for specified control.
-*/
+  \brief Process key press event.
+
+  The following keys are supported:
+  - Up/Down
+  - PageUp/PageDown
+  - Enter
+  - Escape
 
-QWidget* QtxListAction::widget( QWidget* obj ) const
+  \param e key press event
+*/
+void QtxListAction::ListFrame::keyPressEvent( QKeyEvent* e )
 {
-       QWidget* wid = 0;
-       for ( PopupsMap::ConstIterator pit = myPopups.begin(); pit != myPopups.end() && !wid; ++pit )
-               if ( pit.data().popup == obj )
-                       wid = pit.key();
+  if ( e->type() == QEvent::KeyRelease )
+    return;
 
-       for ( ButtonsMap::ConstIterator bit = myButtons.begin(); bit != myButtons.end() && !wid; ++bit )
-               if ( bit.data().main == obj || bit.data().drop == obj )
-                       wid = bit.key();
+  e->accept();
 
-       return wid;
+  int selNum = selected();
+  switch( e->key() )
+  {
+  case Qt::Key_Up:
+    setSelected( qMax( 1, selNum - 1 ) );
+    break;
+  case Qt::Key_Down:
+    setSelected( qMax( 1, selNum + 1 ) );
+    break;
+  case Qt::Key_PageUp:
+    setSelected( qMax( 1, selNum - linesNumber() ) );
+    break;
+  case Qt::Key_PageDown:
+    setSelected( selNum += linesNumber() );
+    break;
+  case Qt::Key_Home:
+    setSelected( 1 );
+    break;
+  case Qt::Key_End:
+    setSelected( myList->count() );
+    break;
+  case Qt::Key_Return:
+    accept();
+    break;
+  case Qt::Key_Escape:
+    hide();
+    break;
+  }
 }
 
 /*!
-       Name: listPopup [private]
-       Desc: Returns sub popup menu widget for specified container.
+  \brief Process mouse events on the viewport of the list widget.
+  \param o object recieving event (viewport)
+  \param e event
+  \return \c true if further event processing should be stopped.
 */
-
-QPopupMenu* QtxListAction::listPopup( QWidget* wid ) const
+bool QtxListAction::ListFrame::eventFilter( QObject* o, QEvent* e )
 {
-       QPopupMenu* p = 0;
-       if ( myPopups.contains( wid ) )
-               p = myPopups[wid].popup;
-       return p;
-}
+  bool res = true;
 
-/*!
-       Name: mainButton [private]
-       Desc: Returns main tool button for specified container.
-*/
+  switch( e->type() )
+  {
+  case QEvent::MouseMove:
+    {
+      QMouseEvent* me = (QMouseEvent*)e;
+      if ( !myList->viewport()->rect().contains( me->pos() ) )
+        setSelected( 0 );
+      else if ( myList->itemAt( me->pos() ) )
+        setSelected( myList->row( myList->itemAt( me->pos() ) ) + 1 );
+    }
+    break;
+  case QEvent::MouseButtonRelease:
+    accept();
+  case QEvent::MouseButtonPress:
+  case QEvent::MouseButtonDblClick:
+    break;
+  case ScrollEvent::Scroll:
+    {
+      ScrollEvent* se = (ScrollEvent*)e;
+      QPoint pos = myList->viewport()->mapFromGlobal( QCursor::pos() );
+      if ( myList->viewport()->rect().contains( pos ) )
+      {
+        if ( myList->itemAt( pos ) )
+          setSelected( myList->row( myList->itemAt( pos ) ) + 1 );
+      }
+      else if ( se->isDown() )
+        setSelected( myList->row( myList->itemAt( myList->viewport()->rect().bottomLeft() -
+                                                  QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
+      else
+        setSelected( myList->row( myList->itemAt( myList->viewport()->rect().topLeft() +
+                                                  QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
+    }
+    break;
+  default:
+    res = false;
+    break;
+  }
 
-QToolButton* QtxListAction::mainButton( QWidget* wid ) const
-{
-       QToolButton* mb = 0;
-       if ( myButtons.contains( wid ) )
-               mb = myButtons[wid].main;
-       return mb;
+  if ( res )
+    return true;
+  else
+    return QMenu::eventFilter( o, e );
 }
 
 /*!
-       Name: dropButton [private]
-       Desc: Returns drop tool button for specified container.
+  \brief Get number of selected names.
+  \return number of selected items
 */
-
-QToolButton* QtxListAction::dropButton( QWidget* wid ) const
+int QtxListAction::ListFrame::selected() const
 {
-       QToolButton* db = 0;
-       if ( myButtons.contains( wid ) )
-               db = myButtons[wid].drop;
-       return db;
+  int sel = 0;
+  QModelIndexList indexes = myList->selectionModel()->selectedRows();
+  for ( QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it )
+    sel = qMax( sel, (*it).row() + 1 );
+  
+  return sel;
 }
 
 /*!
-       Name: controlDeleted [private]
-       Desc: Called when action child controls deleted.
+  \brief Set number of selected names.
+  \param lastSel number of items to be selected
 */
-
-void QtxListAction::controlDeleted( QWidget* wid )
+void QtxListAction::ListFrame::setSelected( const int lastSel )
 {
-  QWidget* w = 0;
-  for ( ButtonsMap::Iterator it = myButtons.begin(); it != myButtons.end() && !w; ++it )
-  {
-    if ( it.data().main == wid || it.data().drop == wid )
-      w = it.key();
-  }
+  int last = qMin( lastSel, (int)myList->count() );
 
-  if ( w )
-  {
-    if ( myFrame )
-      myFrame->hide();
+  QItemSelection selection;
+  QItemSelectionModel* selModel = myList->selectionModel();
 
-    myButtons.remove( w );
-  }
-}
+  for ( int i = 0; i < last; i++ )
+    selection.select( selModel->model()->index( i, 0 ), selModel->model()->index( i, 0 ) );
 
-/**********************************************************************
-**  Class:  QtxListFrame
-**  Descr:  Frame for the list of actions
-**  Level:  Internal
-***********************************************************************/
+  selModel->select( selection, QItemSelectionModel::ClearAndSelect );
+  
+  int item = last - 1;
 
-class QtxListFrame::ScrollEvent : public QCustomEvent
-{
-public:
-       enum { Scroll = User + 1 };
+  myList->scrollToItem( myList->item( item ) );
+  myList->clearFocus();
 
-       ScrollEvent( bool down ) : QCustomEvent( Scroll ), myDown( down ) {};
-       virtual ~ScrollEvent() {};
+  removePostedEvens( myList->viewport(), ScrollEvent::Scroll );
 
-       bool isDown() const { return myDown; };
+  updateComment();
+}
 
-private:
-       bool myDown;
-};
+/*!
+  \brief Filter all events of specified type sent to specified object.
+  \param o object
+  \param type event type to be filtered
+*/
+void QtxListAction::ListFrame::removePostedEvens( QObject* o, int type )
+{
+  class Filter : public QObject
+  {
+  public:
+    Filter() : QObject( 0 ) {}
+    virtual bool eventFilter( QObject*, QEvent* )
+    {
+      return true;
+    }
+  };
+
+  Filter f;
+  o->installEventFilter( &f );
+  QApplication::sendPostedEvents( o, type );
+}
 
 /*!
-       Class: QtxListAction
-       Level: Public
+  \class QtxListAction
+  \brief Action with associated list of items.
+  
+  This class can be helpuful, for example, for creation of Undo/Redo
+  toolbar items which show list of available commands in the popup list box.
 */
 
 /*!
-    Constructor
+  \brief Constructor.
+  \param parent parent object
 */
-QtxListFrame::QtxListFrame( QWidget* parent, WFlags f )
-: QFrame( parent, 0, WStyle_Customize | WStyle_NoBorderEx | WType_Popup | WStyle_Tool | WStyle_StaysOnTop ),
-myList( 0 ),
-myOwner( 0 ),
-myComment( 0 ),
-myMaxLines( 5 ),
-myMaxLineChars( 10 ),
-myScrollVal( 0 ),
-myScrollBlock( false )
+QtxListAction::QtxListAction( QObject* parent )
+: QtxAction( parent ),
+  myFrame( 0 )
 {
-  QVBoxLayout* theLayout = new QVBoxLayout( this, 3 );
-       theLayout->setResizeMode( QLayout::FreeResize );
-
-  myList = new QListBox( this );
-  myList->setSelectionMode( QListBox::Multi );
-  myList->setHScrollBarMode( QScrollView::AlwaysOff );
-       myList->setFocusPolicy( NoFocus );
-
-       QPalette p = myList->palette();
-       p.setColor( QPalette::Inactive, QColorGroup::Highlight,
-                                     p.color( QPalette::Active, QColorGroup::Highlight ) );
-       p.setColor( QPalette::Inactive, QColorGroup::HighlightedText,
-                                     p.color( QPalette::Active, QColorGroup::HighlightedText ) );
-       myList->setPalette( p );
-
-  /*  We'll have the vertical scroll bar only and
-      truncate the names which are too wide */
-  connect( myList, SIGNAL( contentsMoving( int, int ) ), this, SLOT( onScroll( int, int ) ) );
-
-  myComment = new QLabel( this );
-  myComment->setFrameStyle( Panel | Sunken );
-  myComment->setAlignment( AlignCenter );
-  myMultipleComment = "%1";
-
-  theLayout->addWidget( myList );
-  theLayout->addWidget( myComment );
-
-  setFrameStyle( Panel | Raised );
+  initialize();
 }
 
-QtxListFrame::~QtxListFrame()
+/*!
+  \brief Constructor.
+  \param icon action icon
+  \param menuText menu text
+  \param accel key accelerator
+  \param parent parent object
+*/
+QtxListAction::QtxListAction( const QIcon& icon, const QString& menuText, 
+                              int accel, QObject* parent )
+: QtxAction( menuText, icon, menuText, accel, parent ),
+  myFrame( 0 )
 {
+  initialize();
 }
 
 /*!
-    Clears list of names [ public ]
+  \brief Constructor.
+  \param menuText menu text
+  \param accel key accelerator
+  \param parent parent object
 */
-
-void QtxListFrame::clear()
+QtxListAction::QtxListAction( const QString& menuText, int accel, QObject* parent )
+: QtxAction( menuText, menuText, accel, parent ),
+  myFrame( 0 )
 {
-       myNames.clear();
-       setNames( myNames );
+  initialize();
 }
 
-void QtxListFrame::addNames( const QStringList& names )
+/*!
+  \brief Constructor.
+  \param text action description text (tooltip)
+  \param menuText menu text
+  \param accel key accelerator
+  \param parent parent object
+*/
+QtxListAction::QtxListAction( const QString& text, const QString& menuText, 
+                              int accel, QObject* parent )
+: QtxAction( text, menuText, accel, parent ),
+  myFrame( 0 )
 {
-       for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
-               myNames.append( *it );
-       setNames( myNames );
+  initialize();
 }
 
 /*!
-    Sets a names to the list. Truncates the name to fit to the frame width.
-    Use QtxListAction::setMaxLineChar( int ) to set the width in characters. [ public ]
+  \brief Constructor.
+  \param text action description text (tooltip)
+  \param icon action icon
+  \param menuText menu text
+  \param accel key accelerator
+  \param parent parent object
 */
-
-void QtxListFrame::setNames( const QStringList& names )
+QtxListAction::QtxListAction( const QString& text, const QIcon& icon, 
+                              const QString& menuText, int accel, QObject* parent )
+: QtxAction( text, icon, menuText, accel, parent ),
+  myFrame( 0 )
 {
-  if ( !myList )
-               return;
-
-       myList->clear();
-
-       for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
-       {
-               QString s = *it;
-    QFontMetrics fm = myList->fontMetrics();
-    int maxW = myMaxLineChars * fm.maxWidth();
-    int w = fm.width( s );
-    if ( w > maxW )
-    {
-      QString extra( "..." );
-      int len = s.length();
-      int extraLen = fm.width( extra ) + 1;
-      while ( true )
-      {
-        w = fm.width( s, --len );
-        if ( w + extraLen < maxW )
-        {
-          s = s.left( len );
-          break;
-        }
-      }
-      s += extra;
-    }
-    myList->insertItem( s );
-  }
+  initialize();
 }
 
-const QStringList QtxListFrame::names() const
+/*!
+  \brief Destructor.
+*/
+QtxListAction::~QtxListAction()
 {
-       return myNames;
+  delete myFrame;
+  myFrame = 0;
 }
 
 /*!
-    Sets max number of lines shown without activation of vertical scroll bar. [ public ]
+  \brief Get popup mode.
+  \return current popup mode (QtxListAction::PopupMode)
+  \sa setPopupMode()
 */
-
-void QtxListFrame::setMaxLines( int maxLines )
+int QtxListAction::popupMode() const
 {
-  myMaxLines = maxLines;
+  return menu() ? SubMenu : Item;
 }
 
 /*!
-    Sets max number of chars in line ( the rest will be truncated ). [ public ]
+  \brief Set popup mode.
+  \param mode new popup mode (QtxListAction::PopupMode)
+  \sa popupMode()
 */
-
-void QtxListFrame::setMaxLineChars( int maxChars )
+void QtxListAction::setPopupMode( const int mode )
 {
-       if ( myMaxLineChars == maxChars )
-               return;
+  if ( mode == popupMode() )
+    return;
+
+  if ( mode == Item )
+  {
+    delete menu();
+    setMenu( 0 );
+  }
+  else
+    setMenu( new QMenu( 0 ) );
 
-  myMaxLineChars = maxChars;
-       setNames( myNames );
+  onChanged();
 }
 
 /*!
-    Sets the format of single comment. [ public ]
+  \brief Get current list of names.
+  \return list of names
 */
-
-void QtxListFrame::setSingleComment( const QString& comment )
+QStringList QtxListAction::names() const
 {
-  mySingleComment = comment;
-       setNames( myNames );
-  updateComment();
+  QStringList lst;
+  if ( myFrame )
+    lst = myFrame->names();
+  return lst;
 }
 
 /*!
-    Sets the format of multiple comment. [ public ]
-*/
+  \brief Add names to the list.
 
-void QtxListFrame::setMultipleComment( const QString& comment )
-{
-  myMultipleComment = comment;
-       setNames( myNames );
-  updateComment();
-}
+  Truncates each name to fit the frame width.
+  Method setCharsNumber() can be used to change
+  the frame width (in characters).
 
-/*!
-    Updates comment display. [ public ]
+  \param names list of names to be added
+  \param clear if \c true, remove the old contents from the list
+  \sa setCharsNumber()
 */
-
-void QtxListFrame::updateComment()
+void QtxListAction::addNames( const QStringList& names, bool clear )
 {
-       QString com;
-       int selNum = selected();
-       if ( selNum > 1 )
-               com = myMultipleComment;
-       else if ( selNum > 0 && !mySingleComment.isEmpty() )
-               com = mySingleComment;
+  if ( !myFrame )
+    return;
 
-       if ( !com.isEmpty() )
-               com = com.arg( selNum );
+  if ( clear )
+    myFrame->clear();
 
-  myComment->setText( com );
-}
+  myFrame->addNames( names );
 
-void QtxListFrame::setOwner( QWidget* wo )
-{
-  myOwner = wo;
-  if ( myOwner )
-  {
-    QPoint lpos;
-    if ( myOwner->parentWidget() && myOwner->parentWidget()->inherits( "QToolBar" ) &&
-         ((QToolBar*)myOwner->parentWidget())->orientation() == Qt::Vertical )
-      lpos = QPoint( myOwner->x() + myOwner->width() + 2, myOwner->y() );
-    else
-                 lpos = QPoint( myOwner->x(), myOwner->y() + myOwner->height() + 2 );
-      QPoint gpos = myOwner->parentWidget() ? myOwner->parentWidget()->mapToGlobal( lpos )
-                                            : myOwner->mapToGlobal( lpos );
-    if ( parentWidget() )
-                       move( parentWidget()->mapFromGlobal( gpos ) );
-    else
-                 move( gpos );
-  }
+  onChanged();
 }
 
 /*!
-    Validates the action. [ private slot ]
+  \brief Get maximum numer of lines shown without activation of vertical scroll bar.
+  \return number of lines
+  \sa setLinesNumber(), charsNumber(), setCharsNumber()
 */
-
-void QtxListFrame::accept()
+int QtxListAction::linesNumber() const
 {
-  emit selected( selected() );
+  return myFrame->linesNumber();
 }
 
 /*!
-    Cancels the action. [ private slot ]
-*/
+  \brief Get maximum numer of characters in the line.
+
+  If the name length is greater than this value, it will be truncated.
 
-void QtxListFrame::reject()
+  \return number of characters
+  \sa setCharsNumber(), linesNumber(), setLinesNumber()
+*/
+int QtxListAction::charsNumber() const
 {
-  emit selected( 0 );
+  return myFrame->charsNumber();
 }
 
 /*!
-    Initializes / shows the frame. [ virtual public slot ]
+  \brief Set maximum numer of lines shown without activation of vertical scroll bar.
+  \param nlines number of lines (5 by default)
+  \sa linesNumber(), charsNumber(), setCharsNumber()
 */
-
-void QtxListFrame::show()
+void QtxListAction::setLinesNumber( const int nlines )
 {
-  int cnt = (int)myList->count();
-  if ( cnt )
-  {
-    myScrollVal = 0;
-               myList->setTopItem( 0 );
-    myList->clearSelection();
-               myList->setMinimumSize( 0, ( QMIN( cnt + 1, myMaxLines ) ) * myList->itemHeight() + 1 );
-    setSelected( 1 );
+  myFrame->setLinesNumber( nlines );
+}
 
-    int linstep = myList->itemHeight();
-    myList->verticalScrollBar()->setLineStep( linstep );
-    myList->verticalScrollBar()->setPageStep( myMaxLines * linstep );
+/*!
+  \brief Set maximum numer of characters in the line.
 
-    QFontMetrics fm = myList->fontMetrics();
-    layout()->invalidate();
-    int maxHeight = layout()->minimumSize().height() + layout()->margin();
-    int maxWidth = myMaxLineChars * fm.maxWidth();
-               for ( uint i = 0; i <= myList->count(); i++ )
-                       maxWidth = QMAX( maxWidth, fm.width( myList->text( i ) ) );
+  If the name length is greater than this value, it will be truncated.
 
-               resize( width(), maxHeight );
+  \param maxChars number of characters (5 by default)
+  \sa charsNumber(), linesNumber(), setLinesNumber()
+*/
 
-               myList->updateGeometry();
+void QtxListAction::setCharsNumber( const int nchars )
+{
+  myFrame->setCharsNumber( nchars );
+}
 
-               QApplication::sendPostedEvents();
+/*!
+  \brief Set the format Qt string for comments displayed under the list
+         of actions for one action and for several actions.
 
-    myList->resizeContents( myList->contentsWidth(),
-                            myList->itemHeight() * cnt );
-    if ( myList->contentsHeight() > myList->visibleHeight() )
-         maxWidth += myList->verticalScrollBar()->width();
+  Example: "Undo %1 actions" format string will work as "Undo 3 actions"
+  when 3 actions are selected. The default format string is "%1".
 
-               QString single = mySingleComment.arg( cnt );
-               QString multi = myMultipleComment.arg( cnt );
-               int comWidth = QMAX( myComment->fontMetrics().width( single ), myComment->fontMetrics().width( multi ) );
-               if ( myComment->frameWidth() )
-                       comWidth += myComment->fontMetrics().width( "x" );
+  \param c single action comment format
+  \param c multiple actions comment format
+*/
+void QtxListAction::setComment( const QString& c, const QString& sc )
+{
+  if ( !myFrame )
+    return;
 
-               maxWidth = QMAX( maxWidth, comWidth );
+  myFrame->setSingleComment( sc.isEmpty() ? c : sc );
+  myFrame->setMultipleComment( c );
+}
 
-               resize( maxWidth, maxHeight );
-    updateComment();
+/*!
+  \brief Create action widget.
 
-    qApp->installEventFilter( this );
+  This function is called whenever the action is added 
+  to a container widget that supports custom widgets like menu or toolbar.
+  
+  \param parent container widget the action is added to
+  \return tool button for toolbar and 0 otherwise
+*/
+QWidget* QtxListAction::createWidget( QWidget* parent )
+{
+  if ( parent && parent->inherits( "QMenu" ) )
+    return 0;
 
-    QFrame::show();
-  }
+  QToolButton* tb = new QToolButton( parent );
+  tb->setText( text() );
+  tb->setIcon( icon() );
+  tb->setPopupMode( QToolButton::MenuButtonPopup );
+  tb->setMenu( myFrame );
+  tb->setEnabled( isEnabled() && !names().isEmpty() );
+  tb->setToolTip( toolTip() );
+  connect( tb, SIGNAL( clicked( bool ) ), this, SLOT( onSingle( bool ) ) );
+
+  return tb;
 }
 
 /*!
-    Cleanup. [ virtual public slot ]
-*/
+  \brief Destroy action widget.
 
-void QtxListFrame::hide()
+  This function is called whenever the action is removed
+  from a container widget that supports custom widgets like menu or toolbar.
+  
+  \param widget container widget the action is removed from
+*/
+void QtxListAction::deleteWidget( QWidget* widget )
 {
-  qApp->removeEventFilter( this );
-  QFrame::hide();
-  emit hided();
+  delete widget;
 }
 
 /*!
-    Processes KeyUp/KeyDown, PageUp/PageDown, CR and Esc keys.
-    Returns 'true' if event is eaten, 'false' otherwise. [ private ]
+  \brief Initialize the action.
 */
-
-bool QtxListFrame::handleKeyEvent( QObject* , QKeyEvent* e )
+void QtxListAction::initialize()
 {
-  if ( e->type() == QEvent::KeyRelease )
-    return true;
+  setPopupMode( Item );
+  
+  myFrame = new QtxListAction::ListFrame( this, 0 );
+  myFrame->setLinesNumber( 7 );
+  myFrame->setCharsNumber( 5 );
 
-  int selNum = selected();
-  switch( e->key() )
-  {
-  case Key_Up:
-    setSelected( QMAX( 1, selNum - 1 ) );
-    break;
-  case Key_Down:
-    setSelected( QMAX( 1, selNum + 1 ) );
-    break;
-  case Key_PageUp:
-    setSelected( QMAX( 1, selNum - myMaxLines ) );
-    break;
-  case Key_PageDown:
-         setSelected( selNum += myMaxLines );
-    break;
-  case Key_Home:
-         setSelected( 1 );
-               break;
-  case Key_End:
-         setSelected( myList->count() );
-               break;
-  case Key_Return:
-    accept();
-    break;
-  case Key_Escape:
-    reject();
-    break;
-  }
-  return true;
+  myFrame->hide();
+
+  connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) );
+  connect( this, SIGNAL( triggered( bool ) ), this, SLOT( onSingle( bool ) ) );
 }
 
 /*!
-    Selects items on move, validates on button release. If object 'o' is not our name list,
-    we close the frame. Returns 'true' if event is eaten, 'false' otherwise. [ private ]
+  \brief Called the action contents is changed.
 */
-
-bool QtxListFrame::handleMouseEvent( QObject* o, QMouseEvent* e )
+void QtxListAction::onChanged()
 {
-  switch( e->type() )
-  {
-  case QEvent::MouseButtonPress:
-  {
-         if ( o != myList->viewport() && !isPopup() )
-                 reject();
-    return true;
-  }
-  case QEvent::MouseMove:
+  QStringList lst = myFrame->names();
+
+  if ( menu() )
   {
-    if ( o == myList->viewport() )
+    menu()->clear();
+    for ( QStringList::iterator iter = lst.begin(); iter != lst.end(); ++iter )
     {
-      QListBoxItem* lbi = myList->itemAt( e->pos() );
-      if ( lbi )
-        setSelected( myList->index( lbi ) + 1 );
+      QAction* a = new QAction( *iter, menu() );
+      menu()->addAction( a );
+      connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTriggered( bool ) ) );
     }
-    break;
   }
-  case QEvent::MouseButtonRelease:
+
+  QList<QWidget*> widList = createdWidgets();
+  for ( QList<QWidget*>::iterator it = widList.begin(); it != widList.end(); ++it )
   {
-    if ( o == myList->viewport() )
-      accept();
-    else
-                 reject();
-    break;
-  }
-  default:
-    break;
+    (*it)->setEnabled( isEnabled() && !lst.isEmpty() );
+    QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
+    if ( tb )
+    {
+      tb->setText( text() );
+      tb->setIcon( icon() );
+      tb->setToolTip( toolTip() );
+    }
   }
-  return true;
-}
-
-bool QtxListFrame::event( QEvent* e )
-{
-       if ( e->type() != ScrollEvent::Scroll )
-               return QFrame::event( e );
-
-       ScrollEvent* se = (ScrollEvent*)e;
-       if ( se->isDown() )
-               setSelected( myList->topItem() + myList->numItemsVisible() );
-       else
-               setSelected( myList->topItem() + 1 );
-
-       return true;
 }
 
 /*!
-    Watches mouse events on the viewport of the list. [ virtual public ]
+  \brief Called when a user click action button.
+  \param on (not used)
 */
 
-bool QtxListFrame::eventFilter( QObject* o, QEvent* e )
+void QtxListAction::onSingle( bool /*on*/ )
 {
-  bool isKeyEvent = ( e->type() == QEvent::KeyPress ||
-                      e->type() == QEvent::KeyRelease );
-  bool isMouseEvent = ( e->type() == QEvent::MouseMove ||
-                        e->type() == QEvent::MouseButtonPress ||
-                        e->type() == QEvent::MouseButtonRelease ||
-                        e->type() == QEvent::MouseButtonDblClick );
-
-  if ( isKeyEvent )
-  {
-    if ( handleKeyEvent( o, ( QKeyEvent* )e ) )
-      return true;
-  }
-  else if ( isMouseEvent && o != myList->verticalScrollBar() )
-  {
-    if ( handleMouseEvent( o, ( QMouseEvent*)e ) )
-      return true;
-  }
-
-  if ( o != this && ( e->type() == QEvent::Resize || e->type() == QEvent::Move ) )
-    setOwner( myOwner );
-
-  return QFrame::eventFilter( o, e );
+  onMultiple( 1 );
 }
 
 /*!
-    Selects operations while scrolling the list. [ private slot ]
+  \brief Called when multiple items are selected. 
 */
-
-void QtxListFrame::onScroll( int x, int y )
+void QtxListAction::onMultiple( const int numActions )
 {
-  int dx = y - myScrollVal;
-       if ( !myScrollBlock )
-               QApplication::postEvent( this, new ScrollEvent( dx > 0 ) );
-  myScrollVal = y;
+  if ( myFrame )
+    myFrame->hide();
+
+  if ( numActions > 0 )
+    emit triggered( numActions );
 }
 
 /*!
-    Selects the actions [ 0 - lastSel ]. [ public ]
+  \brief Called when user activates an items in the popup sub menu. 
+  \param on (not used)
 */
-
-void QtxListFrame::setSelected( const int lastSel )
+void QtxListAction::onTriggered( bool /*on*/ )
 {
-       int last = QMIN( lastSel, (int)myList->count() );
-
-       for ( int i = 0; i < (int)myList->count(); i++ )
-               myList->setSelected( i, i < last );
-
-       int item = last - 1;
-
-       myScrollBlock = true;
-
-       if ( item < myList->topItem() )
-               myList->setTopItem( item );
-
-       if ( item >= myList->topItem() + myList->numItemsVisible() )
-               myList->setTopItem( item - myList->numItemsVisible() + 1 );
-
-       myScrollBlock = false;
+  if ( !menu() )
+    return;
 
-  myList->clearFocus();
+  QList<QAction*> actionList = menu()->actions();
+  int idx = actionList.indexOf( ::qobject_cast<QAction*>( sender() ) );
+  if ( idx < 0 )
+    return;
 
-  updateComment();
+  emit triggered( idx + 1 );
 }
 
-int QtxListFrame::selected() const
-{
-       uint sel = 0;
-       while ( sel < myList->count() && myList->isSelected( sel ) )
-               sel++;
-       return sel;
-}
+/*!
+  \fn QtxListAction::activated(int numItems );
+  \brief This signal is emitted when an action is activated.
+  \param numItems number of items being selected in the action list.
+*/