Salome HOME
[bos #38087][CEA] The Inspection menu from SHAPER is not well placed if GEOM is launc...
[modules/gui.git] / src / Qtx / QtxActionMenuMgr.cxx
index 2d09b2d0989777498eb2b0d3400dc93f11fc4dcb..f57d41c1da3cb51112b9f4146f7850aa2680b943 100644 (file)
-// Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
-// 
+// Copyright (C) 2007-2023  CEA, EDF, 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.
-// 
-// 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 
+// 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 
+// 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/
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
-// File:      QtxActionMenuMgr.cxx
-// Author:    Alexander SOLOVYEV, Sergey TELKOV
 
+// File:      QtxActionMenuMgr.cxx
+// Author:    Alexander SOLOVYOV, Sergey TELKOV
+//
 #include "QtxActionMenuMgr.h"
 
 #include "QtxAction.h"
 
-#include <qwidget.h>
-#include <qmenubar.h>
-#include <qpopupmenu.h>
-#include <qwidgetlist.h>
-#include <qobjectlist.h>
-#include <qmainwindow.h>
-#include <qfile.h>
-#include <qdom.h>
+#include <QMenu>
+#include <QMenuBar>
+#include <QWidget>
+#include <QMainWindow>
 
 /*!
-       Class: QtxActionMenuMgr::MenuAction
-       Level: Internal
+  \class QtxActionMenuMgr::MenuNode
+  \brief Represents a menu item inside main menu structure.
+  \internal
 */
 
-class QtxActionMenuMgr::MenuAction : public QtxAction
+class QtxActionMenuMgr::MenuNode
 {
 public:
-  MenuAction( const QString&, const QString&, QObject*, const bool = false );
-  virtual ~MenuAction();
-
-  virtual bool addTo( QWidget* );
-
-  virtual bool removeFrom( QWidget* );
-
-  QPopupMenu*  popup() const;
-
-private:
-  int          myId;
-  QPopupMenu*  myPopup;
-  bool         myEmptyEnabled;
+  MenuNode();
+  MenuNode( MenuNode*, const int, const int, const int );
+  ~MenuNode();
+  
+  MenuNode* parent;       //!< parent menu node
+  int       id;           //!< menu nodeID
+  int       idx;          //!< menu node index 
+  int       group;        //!< menu group ID
+  bool      visible;      //!< visibility status
+  int       emptyEnabled; //!< enable empty menu flag
+  NodeList  children;     //!< children menu nodes list
 };
 
-QtxActionMenuMgr::MenuAction::MenuAction( const QString& text,
-                                         const QString& menuText,
-                                         QObject*       parent,
-                                         const bool     allowEmpty )
-: QtxAction( text, menuText, 0, parent ),
-  myId( -1 ),
-  myPopup( 0 ),
-  myEmptyEnabled( allowEmpty )
+/*!
+  \brief Default constructor.
+  \internal
+*/
+QtxActionMenuMgr::MenuNode::MenuNode()
+  : parent( 0 ), id( -1 ), idx( -1 ), group( -1 ), visible( true ), emptyEnabled( 0 )
 {
-  myPopup = new QPopupMenu();
 }
 
-QtxActionMenuMgr::MenuAction::~MenuAction()
+/*!
+  \brief Constructor.
+  \internal
+  \param p parent menu node
+  \param _id menu node ID
+  \param _idx menu node index
+  \param _group menu node group ID
+*/
+QtxActionMenuMgr::MenuNode::MenuNode( MenuNode* p,
+                                      const int _id,
+                                      const int _idx,
+                                      const int _group )
+: parent( p ), id( _id ), idx( _idx ), group( _group ), visible( true ), emptyEnabled( 0 )
 {
-  delete myPopup;
+  if ( p )
+    p->children.append( this );
 }
 
-bool QtxActionMenuMgr::MenuAction::addTo( QWidget* w )
+/*!
+  \brief Destructor.
+  \internal
+*/
+QtxActionMenuMgr::MenuNode::~MenuNode()
 {
-  if ( myId != -1 || !w )
-    return false;
-
-  if ( !w->inherits( "QPopupMenu" ) && !w->inherits( "QMenuBar" ) )
-    return false;
-
-  if ( !myPopup )
-    return false;
-
-  if ( !myEmptyEnabled && !myPopup->count() )
-    return false;
+  for ( NodeList::iterator it = children.begin(); it != children.end(); ++it )
+    delete *it;
+}
 
-  if ( w->inherits( "QPopupMenu" ) && QAction::addTo( w ) )
-  {
-    QPopupMenu* pm = (QPopupMenu*)w;
-    myId = pm->idAt( pm->count() - 1 );
-    setPopup( pm, myId, myPopup );
-  }
-  else if ( w->inherits( "QMenuBar" ) )
-  {
-    QMenuBar* mb = (QMenuBar*)w;
-    myId = iconSet().isNull() ? mb->insertItem( menuText(), myPopup ) :
-                                mb->insertItem( iconSet(), menuText(), myPopup );
-    mb->setItemEnabled( myId, isEnabled() );
-  }
-  else
-    return false;
+/*!
+  \class QtxActionMenuMgr
+  \brief Main menu actions manager.
 
-  return true;
-}
+  Menu manager allows using of set of action for automatic generating of
+  application main menu and dynamic update of its contents.
 
-bool QtxActionMenuMgr::MenuAction::removeFrom( QWidget* w )
-{
-  if ( w->inherits( "QPopupMenu" ) && QAction::removeFrom( w ) )
-    myId = -1;
-  else if ( w->inherits( "QMenuBar" ) )
-  {
-    QMenuBar* mb = (QMenuBar*)w;
-    mb->removeItem( myId );
-    myId = -1;
-  }
+  Use insert(), append() and remove() methods to create main menu.
+  Methods show(), hide() allow displaying/erasing of specified menu items.
 
-  return myId == -1;
-}
+  Actions can be grouped with help of group identificator. Inside the popup
+  or main menu bar menu items are ordered by the group identifier (ascending).
 
-QPopupMenu* QtxActionMenuMgr::MenuAction::popup() const
-{
-  return myPopup;
-}
+  Menu manager automatically optimizes the menu by removing extra separators,
+  hiding empty popup menus etc.
+*/
 
 /*!
-       Class: QtxActionMenuMgr
-       Level: Public
+  \brief Constructor.
+  \param p parent main window
 */
-
-
 QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p )
-: QtxActionMgr( p ),
-myMenu( p ? p->menuBar() : 0 )
+: QtxActionMgr( p ), 
+  myRoot( new MenuNode() ),
+  myMenu( p ? p->menuBar() : 0 )
 {
-  myRoot.id = -1;
-  myRoot.group = -1;
-
   if ( myMenu ) {
     connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
-    if ( myMenu->inherits( "QMenuBar" ) )
-      connect( myMenu, SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) );
   }
 }
 
+/*!
+  \brief Constructor.
+  \param mw menu widget
+  \param p parent object
+*/
 QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p )
-: QtxActionMgr( p ),
-myMenu( mw )
+: QtxActionMgr( p ), 
+  myRoot( new MenuNode() ),
+  myMenu( mw )
 {
-  myRoot.id = -1;
-  myRoot.group = -1;
-
-  if ( myMenu )
+  if ( myMenu ) {
     connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
+  }
 }
 
+/*!
+  \brief Destructor.
+*/
 QtxActionMenuMgr::~QtxActionMenuMgr()
 {
-  for ( NodeListIterator it( myRoot.children ); it.current() && myMenu; ++it )
+  for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
   {
-    QAction* a = itemAction( it.current()->id );
-    if ( !a )
-      a = menuAction( it.current()->id );
-
-    if ( a )
-      a->removeFrom( myMenu );
+    QPointer<QAction> a = itr.value();
+    delete a->menu();
+    delete a;
   }
 
-  for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
-    delete itr.data();
+  delete myRoot;
 }
 
+/*!
+  \brief Check if an action with \a actId identifier is visible to
+  the parent action with \a place identifier.
+  \param actId action ID
+  \param place some parent action ID
+  \return \c true if an action is visible to the parent
+  \sa setVisible()
+*/
 bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const
 {
   MenuNode* node = find( actId, place );
   return node && node->visible;
 }
 
+/*!
+  \brief Set action's visibility flag.
+  \param actId action ID
+  \param place some parent action ID
+  \param v new visibility state
+  \sa isVisible()
+*/
 void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v )
 {
   MenuNode* node = find( actId, place );
@@ -184,16 +180,59 @@ void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool
     node->visible = v;
 }
 
+/*!
+  \brief Insert action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu name: it can be a sequence of strings, separated by '|' symbol.
+  For example, "File|Edit" means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param id action ID
+  \param menus menu name
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx )
 {
-  return insert( id, QStringList::split( "|", menus ), group, idx );
+  return insert( id, menus.split( "|", QString::SkipEmptyParts ), group, idx );
 }
 
+/*!
+  \brief Insert action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu name: it can be a sequence of strings, separated by '|' symbol.
+  For example, "File|Edit" means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param a action
+  \param menus menu name
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx )
 {
-  return insert( a, QStringList::split( "|", menus ), group, idx );
+  return insert( a, menus.split( "|", QString::SkipEmptyParts ), group, idx );
 }
 
+/*!
+  \brief Insert action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu names list.
+  For example, string list consisting from two items "File" and "Edit"
+  means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param id action ID
+  \param menus menu names list
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx )
 {
   int pId = createMenu( menus, -1 );
@@ -203,6 +242,21 @@ int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int
   return insert( id, pId, group, idx );
 }
 
+/*!
+  \brief Insert action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu names list.
+  For example, string list consisting from two items "File" and "Edit"
+  means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param a action
+  \param menus menu names list
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx )
 {
   int pId = createMenu( menus, -1 );
@@ -212,142 +266,280 @@ int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int gr
   return insert( a, pId, group, idx );
 }
 
+/*!
+  \brief Insert action to the menu.
+  \param id action ID
+  \param pId parent menu action ID
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx )
 {
   if ( id == -1 )
     return -1;
 
-  MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
+  MenuNode* pNode = pId == -1 ? myRoot : find( pId );
   if ( !pNode )
     return -1;
 
-  MenuNode* node = new MenuNode( pNode );
-  node->id = id;
-  node->idx = idx;
-  node->group = group;
-
-  pNode->children.append( node );
+  MenuNode* node = new MenuNode( pNode, id, idx, group );
 
-  updateMenu( pNode, false );
+  triggerUpdate( pNode->id, false );
 
   return node->id;
 }
 
+/*!
+  \brief Insert action to the menu.
+  \param a action
+  \param pId parent menu action ID
+  \param group group ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
 int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx )
 {
   return insert( registerAction( a ), pId, group, idx );
 }
 
-int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int id, const int idx, const bool allowEmpty )
+/*!
+  \brief Create and insert menu item action to the menu.
+  \param title menu text
+  \param pId parent menu action ID
+  \param group group ID
+  \param id action ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
+int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group,
+                              const int id, const int idx,  QMenu* _menu)
 {
-  MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
+  MenuNode* pNode = pId == -1 ? myRoot : find( pId );
   if ( !pNode )
     return -1;
 
   MenuNode* eNode = id == -1 ? 0 : find( id );
 
   int fid = -1;
-  for ( NodeListIterator it( pNode->children ); it.current() && fid == -1; ++it )
+  for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end() && fid == -1; ++it )
   {
-    if ( myMenus.contains( it.current()->id ) &&
-         clearTitle( myMenus[it.current()->id]->menuText() ) == clearTitle( title ) )
-      fid = it.current()->id;
+    if ( myMenus.contains( (*it)->id ) &&
+         clearTitle( myMenus[(*it)->id]->text() ) == clearTitle( title ) && ((*it)->group == group || group == -1 ))
+      fid = (*it)->id;
   }
 
   if ( fid != -1 )
     return fid;
 
-  MenuAction* ma = new MenuAction( clearTitle( title ), title, this, allowEmpty );
-  connect( ma->popup(), SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) );
+  int gid = (id == -1 || eNode ) ? generateId() : id;
 
-  MenuNode* node = new MenuNode( pNode );
-  node->group = group;
-  node->idx = idx;
-  node->id = myMenus.insert( (id == -1 || eNode ) ? generateId() : id, ma ).key();
+  QMenu* menu;
+  if (_menu)
+    menu = _menu;
+  else
+    menu = new QMenu( 0 );
+  QAction* ma = menu->menuAction();
+  ma->setText( title );
 
-  pNode->children.append( node );
+  connect( ma->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
+  connect( ma->menu(), SIGNAL( aboutToHide() ), this, SLOT( onAboutToHide() ) );
 
-  updateMenu( pNode, false );
+  MenuNode* node = new MenuNode( pNode, myMenus.insert( gid, ma ).key(), idx, group );
+
+  triggerUpdate( pNode->id, false );
 
   return node->id;
 }
 
-int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx, const bool allowEmpty )
+/*!
+  \brief Create and insert menu item action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu name: it can be a sequence of strings, separated by '|' symbol.
+  For example, "File|Edit" means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param title menu text
+  \param menus menu name
+  \param group group ID
+  \param id action ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
+int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx )
 {
-  return insert( title, QStringList::split( "|", menus ), group, id, idx, allowEmpty );
+  return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx );
 }
 
-int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx, const bool allowEmpty )
+/*!
+  \brief Create and insert menu item action to the menu.
+
+  Insert an action to the named menu. The \a menus parameter represents 
+  the menu names list.
+  For example, string list consisting from two items "File" and "Edit"
+  means \c File->Edit submenu.
+  If submenu doesn't exist, it will be created.
+
+  \param title menu text
+  \param menus menu names list
+  \param group group ID
+  \param id action ID
+  \param idx menu index inside the menu group
+  \return action ID
+*/
+int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx )
 {
   int pId = createMenu( menus, -1 );
-  return insert( title, pId, group, id, idx, allowEmpty );
+  return insert( title, pId, group, id, idx );
 }
 
-int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id, const bool allowEmpty )
+/*!
+  \brief Create and add menu item action to the end of menu.
+  \param title menu text
+  \param pId parent menu action ID
+  \param group group ID
+  \param id action ID
+  \return action ID
+*/
+int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id )
 {
-  return insert( title, pId, group, id, allowEmpty );
+  return insert( title, pId, group, id );
 }
 
+/*!
+  \brief Create and add menu item action to the end of menu.
+  \param id action ID
+  \param pId parent menu action ID
+  \param group group ID
+  \return action ID
+*/
 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
 {
   return insert( id, pId, group );
 }
 
+/*!
+  \brief Create and add menu item action to the end of menu.
+  \param a action
+  \param pId parent menu action ID
+  \param group group ID
+  \return action ID
+*/
 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
 {
   return insert( a, pId, group );
 }
 
-int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id, const bool allowEmpty )
+/*!
+  \brief Create and add menu item action to the beginning of menu.
+  \param title menu text
+  \param pId parent menu action ID
+  \param group group ID
+  \param id action ID
+  \return action ID
+*/
+int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id )
 {
-  return insert( title, pId, group, id, 0, allowEmpty );
+  return insert( title, pId, group, id, 0 );
 }
 
+/*!
+  \brief Create and add menu item action to the beginning of menu.
+  \param id action ID
+  \param pId parent menu action ID
+  \param group group ID
+  \return action ID
+*/
 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
 {
   return insert( id, pId, group, 0 );
 }
 
+/*!
+  \brief Create and add menu item action to the beginning of menu.
+  \param a action
+  \param pId parent menu action ID
+  \param group group ID
+  \return action ID
+*/
 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
 {
   return insert( a, pId, group, 0 );
 }
 
+/*!
+  \brief Remove menu item with given \a id.
+  \param id menu action ID
+*/
 void QtxActionMenuMgr::remove( const int id )
 {
   removeMenu( id, 0 );
   update();
 }
 
+/*!
+  \brief Remove menu item with given \a id.
+  \param id menu action ID
+  \param pId parent menu action ID
+  \param group group ID
+*/
 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
 {
-  MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
+  MenuNode* pNode = pId == -1 ? myRoot : find( pId );
   if ( !pNode )
     return;
 
   NodeList delNodes;
-  for ( NodeListIterator it( pNode->children ); it.current(); ++it )
+  for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end(); ++it )
   {
-    if ( it.current()->id == id && ( it.current()->group == group || group == -1 ) )
-      delNodes.append( it.current() );
+    if ( (*it)->id == id && ( (*it)->group == group || group == -1 ) )
+      delNodes.append( *it );
   }
 
-  for ( NodeListIterator itr( delNodes ); itr.current(); ++itr )
-    pNode->children.remove( itr.current() );
+  QWidget* mW = menuWidget( pNode );
+  for ( NodeList::iterator itr = delNodes.begin(); itr != delNodes.end(); ++itr )
+  {
+    int id = (*itr)->id;
+    if( mW && menuAction( id ) )
+    {
+      mW->removeAction( menuAction( id ) );
+      myMenus.remove( id );
+    }
+    else if( mW && itemAction( id ) )
+      mW->removeAction( itemAction( id ) );
+    pNode->children.removeAll( *itr );
+  }
 
-  updateMenu( pNode, false );
+  triggerUpdate( pNode->id, false );
 }
 
+/*!
+  \brief Show menu item with given \a id.
+  \param id menu action ID
+  \sa hide()
+*/
 void QtxActionMenuMgr::show( const int id )
 {
   setShown( id, true );
 }
 
+/*!
+  \brief Hide menu item with given \a id.
+  \param id menu action ID
+  \sa show()
+*/
 void QtxActionMenuMgr::hide( const int id )
 {
   setShown( id, false );
 }
 
+/*!
+  \brief Get visibility status for menu item with given \a id.
+  \param id menu action ID
+  \return \c true if an item is shown
+  \sa setShown()
+*/
 bool QtxActionMenuMgr::isShown( const int id ) const
 {
   bool res = false;
@@ -357,56 +549,103 @@ bool QtxActionMenuMgr::isShown( const int id ) const
   return res;
 }
 
+/*!
+  \brief Set visibility status for menu item with given \a id.
+  \param id menu action ID
+  \param on new visibility status
+  \sa isShown()
+*/
 void QtxActionMenuMgr::setShown( const int id, const bool on )
 {
   NodeList aNodes;
   find( id, aNodes );
 
-  QMap<MenuNode*, int> updMap;
-  for ( NodeListIterator it( aNodes ); it.current(); ++it )
+  for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
   {
-    if ( it.current()->visible != on )
+    if ( (*it)->visible != on )
     {
-      it.current()->visible = on;
-      updMap.insert( it.current()->parent, 0 );
+      (*it)->visible = on;
+      triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot->id, false );
     }
   }
+}
+
+/*!
+  \brief Change menu title for the action with given \a id.
+  \param id menu action ID
+  \param title new menu title
+*/
+void QtxActionMenuMgr::change( const int id, const QString& title )
+{
+  QAction* a = menuAction( id );
+  if ( a )
+    a->setText( title );
+}
+
+/*!
+  \brief Called when the submenu is about to show.
+  
+  Emits the signal menuAboutToShow(QMenu*).
+*/
+void QtxActionMenuMgr::onAboutToShow()
+{
+  QMenu* m = ::qobject_cast<QMenu*>( sender() );
+  if ( m )
+    emit menuAboutToShow( m );
+}
 
-  for ( QMap<MenuNode*, int>::ConstIterator itr = updMap.begin(); itr != updMap.end(); ++itr )
-    updateMenu( itr.key(), false );
+/*!
+  \brief Called when the submenu is about to hide.
+  
+  Emits the signal menuAboutToHide(QMenu*).
+*/
+void QtxActionMenuMgr::onAboutToHide()
+{
+  QMenu* m = ::qobject_cast<QMenu*>( sender() );
+  if ( m )
+    emit menuAboutToHide( m );
 }
 
+/*!
+  \brief Called when the corresponding menu object is destroyed.
+
+  Clears internal pointer to menu to disable crashes.
+  
+  \param obj (menu) object being destroyed
+*/
 void QtxActionMenuMgr::onDestroyed( QObject* obj )
 {
   if ( myMenu == obj )
     myMenu = 0;
 }
 
-void QtxActionMenuMgr::onHighlighted( int id )
+
+/*!
+  \fn void QtxActionMenuMgr::menuAboutToShow( QMenu* m )
+  \brief Emitted when the menu is about to be shown.
+  \param m menu being shown
+*/
+
+/*!
+  \fn void QtxActionMenuMgr::menuAboutToHide( QMenu* m )
+  \brief Emitted when the menu is about to be hidden.
+  \param m menu being hidden
+*/
+
+/*!
+  \brief Get the menu widget.
+  \return menu widget (QMenuBar)
+*/
+QWidget* QtxActionMenuMgr::menuWidget() const
 {
-  const QObject* snd = sender();
-  int pid = 0, realId;
-  if ( myMenu && snd == myMenu )
-    pid = -1;
-  else {
-    for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr ) {
-      if ( itr.data()->popup() && itr.data()->popup() == snd )
-       pid = itr.key();
-    }
-  }
-  if ( pid ) {
-    realId = findId( id, pid );
-    if ( realId != -1 ) {
-      bool updatesEnabled = isUpdatesEnabled();
-      setUpdatesEnabled( false );
-      emit menuHighlighted( pid, realId );
-      setUpdatesEnabled( updatesEnabled );
-      updateMenu( find( realId ) );
-    }
-  }
+  return myMenu;
 }
 
-void QtxActionMenuMgr::setWidget( QWidget* mw )
+/*!
+  \brief Assign new menu widget to the menu manager.
+  \param mw new menu widget
+*/
+void QtxActionMenuMgr::setMenuWidget( QWidget* mw )
 {
   if ( myMenu == mw )
     return;
@@ -418,109 +657,178 @@ void QtxActionMenuMgr::setWidget( QWidget* mw )
 
   if ( myMenu )
     connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
+
+  triggerUpdate( -1, true );
 }
 
-QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int actId, const int pId, const bool rec ) const
+/*!
+  \brief Search menu node.
+  \param id menu action ID
+  \param pId parent menu item ID
+  \param rec if \c true perform recursive search
+  \return menu node or 0 if it is not found
+*/
+QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, const int pId, const bool rec ) const
 {
-  return find( actId, find( pId ), rec );
+  return find( id, find( pId ), rec );
 }
 
+/*!
+  \brief Search menu node.
+  \param id menu action ID
+  \param startNode start menu node (if 0, search from root node)
+  \param rec if \c true perform recursive search
+  \return menu node or 0 if it is not found
+*/
 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const
 {
   MenuNode* node = 0;
-  MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
-  for ( NodeListIterator it( start->children ); it.current() && !node; ++it )
+  MenuNode* start = startNode ? startNode : myRoot;
+  for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
   {
-    if ( it.current()->id == id )
-      node = it.current();
+    if ( (*it)->id == id )
+      node = *it;
     else if ( rec )
-      node = find( id, it.current(), rec );
+      node = find( id, *it, rec );
   }
   return node;
 }
 
+/*!
+  \brief Search recursively all menu nodes with given \a id.
+  \param id menu action ID
+  \param NodeList resulting list of menu nodes
+  \param startNode start menu node (if 0, search from root node)
+  \return \c true if at least one node is found
+*/
 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
 {
-  MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
-  for ( NodeListIterator it( start->children ); it.current(); ++it )
+  MenuNode* start = startNode ? startNode : myRoot;
+  for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
   {
-    if ( it.current()->id == id )
-      lst.prepend( it.current() );
+    MenuNode* node = *it;
+    if ( node->id == id )
+      lst.prepend( node );
 
-    find( id, lst, it.current() );
+    find( id, lst, node );
   }
   return !lst.isEmpty();
 }
 
+/*!
+  \brief Search menu node.
+  \param title menu item title
+  \param pId parent menu item ID
+  \param rec if \c true perform recursive search
+  \return menu node or 0 if it is not found
+*/
 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const
 {
   return find( title, find( pId ), rec );
 }
 
+/*!
+  \brief Search recursively all menu nodes with given \a title.
+  \param title menu item title
+  \param NodeList resulting list of menu nodes
+  \param startNode start menu node (if 0, search from root node)
+  \return \c true if at least one node is found
+*/
 bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const
 {
-  MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
-  for ( NodeListIterator it( start->children ); it.current(); ++it )
+  MenuNode* start = startNode ? startNode : myRoot;
+  for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
   {
-    QAction* a = itemAction( it.current()->id );
+    QAction* a = itemAction( (*it)->id );
     if ( !a )
-      a = menuAction( it.current()->id );
-    if ( a && clearTitle( a->menuText() ) == clearTitle( title ) )
-      lst.prepend( it.current() );
+      a = menuAction( (*it)->id );
+    if ( a && clearTitle( a->text() ) == clearTitle( title ) )
+      lst.prepend( *it );
 
-    find( title, lst, it.current() );
+    find( title, lst, *it );
   }
   return !lst.isEmpty();
 }
 
+/*!
+  \brief Search menu node.
+  \param title menu item title
+  \param startNode start menu node (if 0, search from root node)
+  \param rec if \c true perform recursive search
+  \return menu node or 0 if it is not found
+*/
 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const
 {
   MenuNode* node = 0;
-  MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
-  for ( NodeListIterator it( start->children ); it.current() && !node; ++it )
+  MenuNode* start = startNode ? startNode : myRoot;
+  for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
   {
-    QAction* a = itemAction( it.current()->id );
+    QAction* a = itemAction( (*it)->id );
     if ( !a )
-      a = menuAction( it.current()->id );
-    if ( a && clearTitle( a->menuText() ) == clearTitle( title ) )
-      node = it.current();
+      a = menuAction( (*it)->id );
+    if ( a && clearTitle( a->text() ) == clearTitle( title ) )
+      node = *it;
     if ( !node && rec )
-      node = find( title, it.current(), rec );
+      node = find( title, *it, rec );
   }
   return node;
 }
 
+/*!
+  \brief Find menu item by given ID (one-level only).
+  \param id menu action ID
+  \param pid parent meun item ID
+  \return id (>0) on success or -1 if menu item is not found
+*/
 int QtxActionMenuMgr::findId( const int id, const int pid ) const
 {
-  MenuNode* start = pid != -1 ? find( pid ) : (MenuNode*)&myRoot;
-  if ( start ) {
-    for ( NodeListIterator it( start->children ); it.current(); ++it ) {
-      if ( it.current()->id == id ) return id;
+  MenuNode* start = pid != -1 ? find( pid ) : myRoot;
+  if ( start )
+  {
+    for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
+    {
+      if ( (*it)->id == id )
+        return id;
     }
   }
   return -1;
 }
 
+/*!
+  \brief Removes menu node (with all its children).
+  \param id menu action ID
+  \param startNode parent menu node which search starts from (if 0, search starts from root)
+*/
 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
 {
-  MenuNode* start = startNode ? startNode : &myRoot;
-  for ( NodeListIterator it( start->children ); it.current(); ++it )
+  MenuNode* start = startNode ? startNode : myRoot;
+  for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
   {
-    if ( it.current()->id == id )
-      start->children.remove( it.current() );
+    if ( (*it)->id == id )
+      start->children.removeAll( *it );
     else
-      removeMenu( id, it.current() );
+      removeMenu( id, *it );
   }
 }
 
+/*!
+  \brief Get action by \a id.
+  \param id action ID
+  \return action or 0 if \a id is invalid
+*/
 QAction* QtxActionMenuMgr::itemAction( const int id ) const
 {
   return action( id );
 }
 
-QtxActionMenuMgr::MenuAction* QtxActionMenuMgr::menuAction( const int id ) const
+/*!
+  \brief Get submenu action by \a id.
+  \param id submenu ID
+  \return submenu action or 0 if action is not found
+*/
+QAction* QtxActionMenuMgr::menuAction( const int id ) const
 {
-  MenuAction* a = 0;
+  QAction* a = 0;
 
   if ( myMenus.contains( id ) )
     a = myMenus[id];
@@ -528,127 +836,227 @@ QtxActionMenuMgr::MenuAction* QtxActionMenuMgr::menuAction( const int id ) const
   return a;
 }
 
+/*!
+  \brief Get submenu action by \a id.
+  \param id submenu ID
+  \return submenu action or 0 if it is not found
+*/
+int QtxActionMenuMgr::menuActionId( QAction* a ) const
+{
+  int id = -1;
+  for ( MenuMap::ConstIterator itr = myMenus.begin(); itr != myMenus.end() && id == -1; ++itr )
+  {
+    if ( itr.value() == a )
+      id = itr.key();
+  }
+  return id;
+}
+
+/*!
+  \brief Update menu.
+
+  Does nothing if update is disabled.
+
+  \param startNode start menu item to be updated
+  \param rec if \c true, perform recursive update
+  \param updParent if \c true update also parent item (without recursion)
+
+  \sa isUpdatesEnabled() and setUpdatesEnabled()
+*/
 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
 {
   if ( !isUpdatesEnabled() )
     return;
 
-  MenuNode* node = startNode ? startNode : &myRoot;
+  MenuNode* node = startNode ? startNode : myRoot;
 
   QWidget* mw = menuWidget( node );
   if ( !mw )
     return;
 
-  bool filled = checkWidget( mw );
-
-  for ( NodeListIterator it1( node->children ); it1.current(); ++it1 )
+  // first remove all own actions and collect foreign ones
+  QMap< QAction*, QList<QAction*> > foreign;
+  QAction* a;
+  QAction* preva = 0;
+  QListIterator<QAction*> ait( mw->actions() ); ait.toBack();
+  while ( ait.hasPrevious() )
   {
-    QAction* a = itemAction( it1.current()->id );
-    if ( !a )
-      a = menuAction( it1.current()->id );
-
-    if ( a )
-      a->removeFrom( mw );
+    a = ait.previous();
+    if ( ownAction( a, node ) )
+    {
+      preva = a;
+      mw->removeAction( a );     // remove own actions
+    }
+    else
+    {
+      foreign[preva].prepend(a); // do not yet remove foreign actions
+    }
   }
+  // now only foreign actions should stay in the menu, thus remove them also
+  QMap< QAction*, QList<QAction*> >::Iterator formapit;
+  for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit )
+  {
+    QMutableListIterator<QAction*> foralit( formapit.value() );
+    while ( foralit.hasNext() )
+    {
+      a = foralit.next();
+      if ( !mw->actions().contains( a ) )
+        foralit.remove();
+    }
+  }
+  QList<QAction*> alist = mw->actions();
+  foreach( a, alist ) mw->removeAction( a );
 
-  if ( mw->inherits( "QMenuBar" ) )
-    ((QMenuBar*)mw)->clear();
-  else if ( mw->inherits( "QPopupMenu" ) )
-    ((QPopupMenu*)mw)->clear();
-
+  // collect all registered menus by group id
   QMap<int, NodeList> idMap;
-  for ( NodeListIterator it2( node->children ); it2.current(); ++it2 )
+  for ( NodeList::iterator it2 = node->children.begin(); it2 != node->children.end(); ++it2 )
   {
-    NodeList& lst = idMap[it2.current()->group];
-    int idx = it2.current()->idx;
-    if ( idx < 0 || idx >= lst.count() )
-      lst.append( it2.current() );
+    NodeList& lst = idMap[(*it2)->group];
+    int idx = (*it2)->idx;
+    if ( idx < 0 || idx >= (int)lst.count() )
+      lst.append( *it2 );
     else
-      lst.insert( idx, it2.current() );
+      lst.insert( idx, *it2 );
   }
 
   QIntList groups = idMap.keys();
-  qHeapSort( groups );
+  qSort( groups );
 
-  groups.remove( -1 );
+  groups.removeAll( -1 );
   groups.append( -1 );
 
+  // rebuild menu: 1. add all registered actions
   for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
   {
     if ( !idMap.contains( *gIt ) )
       continue;
 
     const NodeList& lst = idMap[*gIt];
-    for ( NodeListIterator iter( lst ); iter.current(); ++iter )
+    for ( NodeList::const_iterator iter = lst.begin(); iter != lst.end(); ++iter )
     {
-      MenuNode* par = iter.current()->parent;
-      if ( !isVisible( iter.current()->id, par ? par->id : -1 ) )
-       continue;
+      MenuNode* node = *iter;
+      if ( !node ) continue;
 
       if ( rec )
-        updateMenu( iter.current(), rec, false );
+        updateMenu( node, rec, false );
 
-      QAction* a = itemAction( iter.current()->id );
+      MenuNode* par = node->parent;
+      if ( !isVisible( node->id, par ? par->id : -1 ) )
+        continue;
+
+      bool isMenu = false;
+      QAction* a = itemAction( node->id );
       if ( !a )
-        a = menuAction( iter.current()->id );
-      if ( a ) {
-       QMenuData* md = dynamic_cast<QMenuData*>( mw );
-       int cnt = 0;
-       if ( md ) cnt = md->count();
-       a->addTo( mw );
-       if ( md && md->count() - cnt == 1 ) { //&& iter.current()->id > 0
-         int lid = md->idAt( cnt ); 
-         QMenuItem* mi = md->findItem( lid );
-         if ( mi && !mi->isSeparator() )
-           md->setId( cnt, iter.current()->id );
-       }
+      {
+        isMenu = true;
+        a = menuAction( node->id );
       }
+      if ( !a ) continue;
+
+      if ( !isMenu || !a->menu()->isEmpty() || node->emptyEnabled > 0 )
+        mw->addAction( a );
     }
   }
 
+  // rebuild menu: 2. insert back all foreign actions
+  for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit ) {
+    preva = formapit.key();
+    foreach( a, formapit.value() )
+      mw->insertAction( preva, a );
+  }
+
+  // remove extra separators
   simplifySeparators( mw );
 
-  if ( updParent && node->parent && filled != checkWidget( mw ) )
+  // update parent menu if necessary
+  if ( updParent && node->parent ) {
     updateMenu( node->parent, false );
+  }
 }
 
+/*!
+  \brief Internal update.
+  
+  Customizes the menu update processing.
+*/
 void QtxActionMenuMgr::internalUpdate()
 {
-  if ( isUpdatesEnabled() )
-    updateMenu();
+  if ( !isUpdatesEnabled() )
+    return;
+
+  updateMenu();
+  myUpdateIds.clear();
+}
+
+/*!
+  \brief Check if action belongs to the menu manager
+  \internal
+  \param a action being checked
+  \param node parent menu node
+  \return \c true if action belongs to the menu \a node
+*/
+bool QtxActionMenuMgr::ownAction( QAction* a, MenuNode* node ) const
+{
+  for ( NodeList::const_iterator iter = node->children.begin(); iter != node->children.end(); ++iter )
+  {
+    QAction* mya = itemAction( (*iter)->id );
+    if ( !mya )
+      mya = menuAction( (*iter)->id );
+    if ( mya && mya == a )
+      return true;
+  }
+  return false;
 }
 
+/*!
+  \brief Check if menu widget has any actions.
+  \param wid widget to be checked
+  \return \c true if widget contains action(s)
+*/
 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
 {
   if ( !wid )
     return false;
 
-  QMenuData* md = 0;
-  if ( wid->inherits( "QPopupMenu" ) )
-    md = (QPopupMenu*)wid;
-  else if ( wid->inherits( "QMenuBar" ) )
-    md = (QMenuBar*)wid;
-
-  return md->count();
+  bool res = false;
+  QList<QAction*> lst = wid->actions();
+  for ( QList<QAction*>::const_iterator it = lst.begin(); it != lst.end() && !res; ++it ) {
+    res = !(*it)->isSeparator() && (*it)->isVisible();
+  }
+  return res;
 }
 
-QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node) const
+/*!
+  \brief Get menu widget for the given \a node.
+  \param node menu node
+  \return popup menu or main menu corresponding to the menu node
+  (or 0 if it is not found)
+*/
+QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node ) const
 {
-  if ( !node || node == &myRoot )
+  if ( !node || node == myRoot )
      return myMenu;
 
   if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
     return 0;
 
-  return myMenus[node->id]->popup();
+  return myMenus[node->id]->menu();
 }
 
+/*!
+  \brief Remove extra separators from menu widget.
+  \param wid menu widget to be processed
+*/
 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
 {
-  if ( wid && wid->inherits( "QPopupMenu" ) )
-    Qtx::simplifySeparators( (QPopupMenu*)wid, false );
+  Qtx::simplifySeparators( wid, false );
 }
 
+/*!
+  \brief Remove special symbols (&) from string to get clear menu title.
+  \param txt string to be processed
+  \return clear title
+*/
 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
 {
   QString res = txt;
@@ -662,6 +1070,12 @@ QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
   return res;
 }
 
+/*!
+  \brief Create and inserts menu item recursively.
+  \param lst list of menu names
+  \param pId parent menu item ID
+  \return created menu item ID (last in the chain)
+*/
 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
 {
   if ( lst.isEmpty() )
@@ -669,46 +1083,204 @@ int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
 
   QStringList sl( lst );
 
-  QString title = sl.last().stripWhiteSpace();
-  sl.remove( sl.fromLast() );
+  QString title = sl.last().trimmed();
+  sl.removeLast();
 
   int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
 
   return insert( title, parentId, -1 );
 }
 
+/*!
+  \brief Load actions description from the file.
+  \param fname file name
+  \param r action reader
+  \return \c true on success and \c false on error
+*/
 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
 {
   MenuCreator cr( &r, this );
   return r.read( fname, cr );
 }
 
-bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid ) const
+/*!
+  \brief Check if the parent menu contains menu item with given \a title.
+  \param title menu title
+  \param pid parent menu item ID
+  \return \c true if parent menu item contains such child item
+*/
+bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid, const bool rec ) const
+{
+  return (bool)find( title, pid, rec );
+}
+
+/*!
+  \brief Check if the parent menu contains menu item with given \a id.
+  \param id menu item ID
+  \param pid parent menu item ID
+  \return \c true if parent menu item contains such child item
+*/
+bool QtxActionMenuMgr::containsMenu( const int id, const int pid, const bool rec ) const
+{
+  return (bool)find( id, pid, rec );
+}
+
+/*!
+  \brief Get menu by the specified identifier.
+  \param id menu item ID
+  \return menu pointer or 0 if menu is not found
+*/
+QMenu* QtxActionMenuMgr::findMenu( const int id ) const
+{
+  QMenu* m = 0;
+  QAction* a = menuAction( id );
+  if ( a )
+    m = a->menu();
+  return m;
+}
+
+/*!
+  \brief Get menu by the title.
+  \param title menu text
+  \param pid parent menu item ID (to start search)
+  \param rec if \c true, perform recursive update
+  \return menu pointer or 0 if menu is not found
+*/
+QMenu* QtxActionMenuMgr::findMenu( const QString& title, const int pid, const bool rec ) const
 {
-  return (bool)find( title, pid, false );
+  QMenu* m = 0;
+  MenuNode* node = find( title, pid, rec );
+  if ( node )
+  {
+    QAction* a = menuAction( node->id );
+    if ( a )
+      m = a->menu();
+  }
+  return m;
 }
 
-bool QtxActionMenuMgr::containsMenu( const int id, const int pid ) const
+/*!
+  \brief Check if empty menu is enabled
+  \param id menu item ID
+  \return \c true if empty menu is enabled
+*/
+bool QtxActionMenuMgr::isEmptyEnabled( const int id ) const
 {
-  return (bool)find( id, pid, false );
+  MenuNode* node = find( id );
+  if ( node && menuAction( id ) )
+    return node->emptyEnabled > 0;
+  
+  return false;
 }
 
 /*!
-       Class: QtxActionMenuMgr::MenuCreator
-       Level: Public
+  \brief Enable/disable empty menu
+  \param id menu item ID
+  \param enable if \c true, empty menu will be enabled, otherwise empty menu will be disabled
 */
+void QtxActionMenuMgr::setEmptyEnabled( const int id, const bool enable )
+{
+  MenuNode* node = find( id );
+  if ( node && menuAction( id ) ) {
+    int old = node->emptyEnabled;
+    node->emptyEnabled += enable ? 1 : -1;
+    if ( ( old <= 0 && enable ) || ( old > 0 && !enable ) ) // update menu only if enabled state has been changed
+      updateMenu( node, true, true );
+  }
+}
 
-QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r,
-                                            QtxActionMenuMgr* mgr )
+/*!
+  \brief Perform delayed menu update.
+  \param id menu item ID
+  \param rec if \c true, perform recursive update
+*/
+void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec )
+{
+  bool isRec = rec;
+  if ( myUpdateIds.contains( id ) )
+    isRec = isRec || myUpdateIds[ id ];
+  myUpdateIds.insert( id, isRec );
+
+  QtxActionMgr::triggerUpdate();
+}
+
+/*!
+  \brief Called when action is changed.
+
+  Schedule delayed update for parent menu of changed action.
+*/
+void QtxActionMenuMgr::actionChanged( int id )
+{
+  NodeList aNodes;
+  find( id, aNodes );
+
+  for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
+  {
+    MenuNode* node = *it;
+    if ( node->visible ) {
+      triggerUpdate( node->parent ? node->parent->id : myRoot->id, false );
+    }
+  }
+}
+
+/*!
+  \brief Called when delayed content update is performed.
+
+  Customizes the content update operation.
+*/
+void QtxActionMenuMgr::updateContent()
+{
+  // Warning: For correct updating it is necessary to update the most enclosed submenu in first turn
+  //          because not updated empty submenu will be skipped. Now the submenus are iterated in
+  //          ascending order according to their identifiers. For a submenus with automatically generated 
+  //          identifiers this will work correctly since the uppermost submenus have the biggest number
+  //          (identifiers are generated by decrementing 1 starting from -1). In general, if any submenu
+  //          have positive identifiers this method might not work correctly. In this case it would be
+  //          necessary to improve this method and to add preliminary sorting a submenus by depth of an 
+  //          enclosure.
+  for ( QMap<int, bool>::const_iterator it = myUpdateIds.constBegin(); it != myUpdateIds.constEnd(); ++it )
+  {
+    MenuNode* node = it.key() == -1 ? myRoot : find( it.key() );
+    if ( node )
+      updateMenu( node, it.value() );
+  }
+  myUpdateIds.clear();
+}
+
+/*!
+  \class QtxActionMenuMgr::MenuCreator
+  \brief Menu actions creator.
+
+  Used by Reader to create actions by reading descriptions from the file
+  and fill in the action manager with the actions.
+*/
+
+/*!
+  \brief Constructor.
+  \param r menu actions reader
+  \param mgr menu manager
+*/
+QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r, QtxActionMenuMgr* mgr )
 : QtxActionMgr::Creator( r ),
   myMgr( mgr )
 {
 }
 
+/*!
+  \brief Destructor.
+*/
 QtxActionMenuMgr::MenuCreator::~MenuCreator()
 {
 }
 
+/*!
+  \brief Create and append to the action manager a new action.
+  \param tag item tag name
+  \param subMenu \c true if this item is submenu
+  \param attr attributes map
+  \param pId parent action ID
+  \return menu action ID
+*/
 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
                                            const ItemAttributes& attr, const int pId )
 {
@@ -733,20 +1305,21 @@ int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMen
     res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
   else
   {
-    QPixmap pix; QIconSet set;
+    QIcon set;
+    QPixmap pix;
     QString name = strValue( attr, icon );
     if( !name.isEmpty() && loadPixmap( name, pix ) )
-      set = QIconSet( pix );
+      set = QIcon( pix );
 
     QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
-                                       strValue( attr, label ), 
+                                       strValue( attr, label ),
                                        QKeySequence( strValue( attr, accel ) ),
                                        myMgr );
     newAct->setToolTip( strValue( attr, tooltip ) );
     QString toggleact = strValue( attr, toggle );
-    newAct->setToggleAction( !toggleact.isEmpty() );
-    newAct->setOn( toggleact.lower()=="true" );
-        
+    newAct->setCheckable( !toggleact.isEmpty() );
+    newAct->setChecked( toggleact.toLower() == "true" );
+
     connect( newAct );
     int aid = myMgr->registerAction( newAct, actId );
     res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );