1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File: QtxActionMenuMgr.cxx
23 // Author: Alexander SOLOVYOV, Sergey TELKOV
25 #include "QtxActionMenuMgr.h"
27 #include "QtxAction.h"
32 #include <QMainWindow>
35 \class QtxActionMenuMgr::MenuNode
36 \brief Represents a menu item inside main menu structure.
40 class QtxActionMenuMgr::MenuNode
44 MenuNode( MenuNode*, const int, const int, const int );
47 MenuNode* parent; //!< parent menu node
48 int id; //!< menu nodeID
49 int idx; //!< menu node index
50 int group; //!< menu group ID
51 bool visible; //!< visibility status
52 int emptyEnabled; //!< enable empty menu flag
53 NodeList children; //!< children menu nodes list
57 \brief Default constructor.
60 QtxActionMenuMgr::MenuNode::MenuNode()
61 : parent( 0 ), id( -1 ), idx( -1 ), group( -1 ), visible( true ), emptyEnabled( 0 )
68 \param p parent menu node
69 \param _id menu node ID
70 \param _idx menu node index
71 \param _group menu node group ID
73 QtxActionMenuMgr::MenuNode::MenuNode( MenuNode* p,
77 : parent( p ), id( _id ), idx( _idx ), group( _group ), visible( true ), emptyEnabled( 0 )
80 p->children.append( this );
87 QtxActionMenuMgr::MenuNode::~MenuNode()
89 for ( NodeList::iterator it = children.begin(); it != children.end(); ++it )
94 \class QtxActionMenuMgr
95 \brief Main menu actions manager.
97 Menu manager allows using of set of action for automatic generating of
98 application main menu and dynamic update of its contents.
100 Use insert(), append() and remove() methods to create main menu.
101 Methods show(), hide() allow displaying/erasing of specified menu items.
103 Actions can be grouped with help of group identificator. Inside the popup
104 or main menu bar menu items are ordered by the group identifier (ascending).
106 Menu manager automatically optimizes the menu by removing extra separators,
107 hiding empty popup menus etc.
112 \param p parent main window
114 QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p )
116 myRoot( new MenuNode() ),
117 myMenu( p ? p->menuBar() : 0 )
120 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
126 \param mw menu widget
127 \param p parent object
129 QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p )
131 myRoot( new MenuNode() ),
135 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
142 QtxActionMenuMgr::~QtxActionMenuMgr()
144 for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
146 QPointer<QAction> a = itr.value();
155 \brief Check if an action with \a actId identifier is visible to
156 the parent action with \a place identifier.
157 \param actId action ID
158 \param place some parent action ID
159 \return \c true if an action is visible to the parent
162 bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const
164 MenuNode* node = find( actId, place );
165 return node && node->visible;
169 \brief Set action's visibility flag.
170 \param actId action ID
171 \param place some parent action ID
172 \param v new visibility state
175 void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v )
177 MenuNode* node = find( actId, place );
183 \brief Insert action to the menu.
185 Insert an action to the named menu. The \a menus parameter represents
186 the menu name: it can be a sequence of strings, separated by '|' symbol.
187 For example, "File|Edit" means \c File->Edit submenu.
188 If submenu doesn't exist, it will be created.
191 \param menus menu name
192 \param group group ID
193 \param idx menu index inside the menu group
196 int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx )
198 return insert( id, menus.split( "|", QString::SkipEmptyParts ), group, idx );
202 \brief Insert action to the menu.
204 Insert an action to the named menu. The \a menus parameter represents
205 the menu name: it can be a sequence of strings, separated by '|' symbol.
206 For example, "File|Edit" means \c File->Edit submenu.
207 If submenu doesn't exist, it will be created.
210 \param menus menu name
211 \param group group ID
212 \param idx menu index inside the menu group
215 int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx )
217 return insert( a, menus.split( "|", QString::SkipEmptyParts ), group, idx );
221 \brief Insert action to the menu.
223 Insert an action to the named menu. The \a menus parameter represents
225 For example, string list consisting from two items "File" and "Edit"
226 means \c File->Edit submenu.
227 If submenu doesn't exist, it will be created.
230 \param menus menu names list
231 \param group group ID
232 \param idx menu index inside the menu group
235 int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx )
237 int pId = createMenu( menus, -1 );
241 return insert( id, pId, group, idx );
245 \brief Insert action to the menu.
247 Insert an action to the named menu. The \a menus parameter represents
249 For example, string list consisting from two items "File" and "Edit"
250 means \c File->Edit submenu.
251 If submenu doesn't exist, it will be created.
254 \param menus menu names list
255 \param group group ID
256 \param idx menu index inside the menu group
259 int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx )
261 int pId = createMenu( menus, -1 );
265 return insert( a, pId, group, idx );
269 \brief Insert action to the menu.
271 \param pId parent menu action ID
272 \param group group ID
273 \param idx menu index inside the menu group
276 int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx )
281 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
285 MenuNode* node = new MenuNode( pNode, id, idx, group );
287 triggerUpdate( pNode->id, false );
293 \brief Insert action to the menu.
295 \param pId parent menu action ID
296 \param group group ID
297 \param idx menu index inside the menu group
300 int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx )
302 return insert( registerAction( a ), pId, group, idx );
306 \brief Create and insert menu item action to the menu.
307 \param title menu text
308 \param pId parent menu action ID
309 \param group group ID
311 \param idx menu index inside the menu group
314 int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int id, const int idx )
316 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
320 MenuNode* eNode = id == -1 ? 0 : find( id );
323 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end() && fid == -1; ++it )
325 if ( myMenus.contains( (*it)->id ) &&
326 clearTitle( myMenus[(*it)->id]->text() ) == clearTitle( title ) )
333 int gid = (id == -1 || eNode ) ? generateId() : id;
335 QMenu* menu = new QMenu( 0 );
336 QAction* ma = menu->menuAction();
337 ma->setText( title );
339 connect( ma->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
340 connect( ma->menu(), SIGNAL( aboutToHide() ), this, SLOT( onAboutToHide() ) );
342 MenuNode* node = new MenuNode( pNode, myMenus.insert( gid, ma ).key(), idx, group );
344 triggerUpdate( pNode->id, false );
350 \brief Create and insert menu item action to the menu.
352 Insert an action to the named menu. The \a menus parameter represents
353 the menu name: it can be a sequence of strings, separated by '|' symbol.
354 For example, "File|Edit" means \c File->Edit submenu.
355 If submenu doesn't exist, it will be created.
357 \param title menu text
358 \param menus menu name
359 \param group group ID
361 \param idx menu index inside the menu group
364 int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx )
366 return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx );
370 \brief Create and insert menu item action to the menu.
372 Insert an action to the named menu. The \a menus parameter represents
374 For example, string list consisting from two items "File" and "Edit"
375 means \c File->Edit submenu.
376 If submenu doesn't exist, it will be created.
378 \param title menu text
379 \param menus menu names list
380 \param group group ID
382 \param idx menu index inside the menu group
385 int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx )
387 int pId = createMenu( menus, -1 );
388 return insert( title, pId, group, id, idx );
392 \brief Create and add menu item action to the end of menu.
393 \param title menu text
394 \param pId parent menu action ID
395 \param group group ID
399 int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id )
401 return insert( title, pId, group, id );
405 \brief Create and add menu item action to the end of menu.
407 \param pId parent menu action ID
408 \param group group ID
411 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
413 return insert( id, pId, group );
417 \brief Create and add menu item action to the end of menu.
419 \param pId parent menu action ID
420 \param group group ID
423 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
425 return insert( a, pId, group );
429 \brief Create and add menu item action to the beginning of menu.
430 \param title menu text
431 \param pId parent menu action ID
432 \param group group ID
436 int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id )
438 return insert( title, pId, group, id, 0 );
442 \brief Create and add menu item action to the beginning of menu.
444 \param pId parent menu action ID
445 \param group group ID
448 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
450 return insert( id, pId, group, 0 );
454 \brief Create and add menu item action to the beginning of menu.
456 \param pId parent menu action ID
457 \param group group ID
460 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
462 return insert( a, pId, group, 0 );
466 \brief Remove menu item with given \a id.
467 \param id menu action ID
469 void QtxActionMenuMgr::remove( const int id )
476 \brief Remove menu item with given \a id.
477 \param id menu action ID
478 \param pId parent menu action ID
479 \param group group ID
481 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
483 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
488 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end(); ++it )
490 if ( (*it)->id == id && ( (*it)->group == group || group == -1 ) )
491 delNodes.append( *it );
494 for ( NodeList::iterator itr = delNodes.begin(); itr != delNodes.end(); ++itr )
495 pNode->children.removeAll( *itr );
497 triggerUpdate( pNode->id, false );
501 \brief Show menu item with given \a id.
502 \param id menu action ID
505 void QtxActionMenuMgr::show( const int id )
507 setShown( id, true );
511 \brief Hide menu item with given \a id.
512 \param id menu action ID
515 void QtxActionMenuMgr::hide( const int id )
517 setShown( id, false );
521 \brief Get visibility status for menu item with given \a id.
522 \param id menu action ID
523 \return \c true if an item is shown
526 bool QtxActionMenuMgr::isShown( const int id ) const
529 MenuNode* node = find( id );
536 \brief Set visibility status for menu item with given \a id.
537 \param id menu action ID
538 \param on new visibility status
541 void QtxActionMenuMgr::setShown( const int id, const bool on )
546 for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
548 if ( (*it)->visible != on )
551 triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot->id, false );
557 \brief Change menu title for the action with given \a id.
558 \param id menu action ID
559 \param title new menu title
561 void QtxActionMenuMgr::change( const int id, const QString& title )
563 QAction* a = menuAction( id );
569 \brief Called when the submenu is about to show.
571 Emits the signal menuAboutToShow(QMenu*).
573 void QtxActionMenuMgr::onAboutToShow()
575 QMenu* m = ::qobject_cast<QMenu*>( sender() );
577 emit menuAboutToShow( m );
581 \brief Called when the submenu is about to hide.
583 Emits the signal menuAboutToHide(QMenu*).
585 void QtxActionMenuMgr::onAboutToHide()
587 QMenu* m = ::qobject_cast<QMenu*>( sender() );
589 emit menuAboutToHide( m );
593 \brief Called when the corresponding menu object is destroyed.
595 Clears internal pointer to menu to disable crashes.
597 \param obj (menu) object being destroyed
599 void QtxActionMenuMgr::onDestroyed( QObject* obj )
607 \fn void QtxActionMenuMgr::menuAboutToShow( QMenu* m )
608 \brief Emitted when the menu is about to be shown.
609 \param m menu being shown
613 \fn void QtxActionMenuMgr::menuAboutToHide( QMenu* m )
614 \brief Emitted when the menu is about to be hidden.
615 \param m menu being hidden
619 \brief Get the menu widget.
620 \return menu widget (QMenuBar)
622 QWidget* QtxActionMenuMgr::menuWidget() const
628 \brief Assign new menu widget to the menu manager.
629 \param mw new menu widget
631 void QtxActionMenuMgr::setMenuWidget( QWidget* mw )
637 disconnect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
642 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
644 triggerUpdate( -1, true );
648 \brief Search menu node.
649 \param id menu action ID
650 \param pId parent menu item ID
651 \param rec if \c true perform recursive search
652 \return menu node or 0 if it is not found
654 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, const int pId, const bool rec ) const
656 return find( id, find( pId ), rec );
660 \brief Search menu node.
661 \param id menu action ID
662 \param startNode start menu node (if 0, search from root node)
663 \param rec if \c true perform recursive search
664 \return menu node or 0 if it is not found
666 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const
669 MenuNode* start = startNode ? startNode : myRoot;
670 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
672 if ( (*it)->id == id )
675 node = find( id, *it, rec );
681 \brief Search recursively all menu nodes with given \a id.
682 \param id menu action ID
683 \param NodeList resulting list of menu nodes
684 \param startNode start menu node (if 0, search from root node)
685 \return \c true if at least one node is found
687 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
689 MenuNode* start = startNode ? startNode : myRoot;
690 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
692 MenuNode* node = *it;
693 if ( node->id == id )
696 find( id, lst, node );
698 return !lst.isEmpty();
702 \brief Search menu node.
703 \param title menu item title
704 \param pId parent menu item ID
705 \param rec if \c true perform recursive search
706 \return menu node or 0 if it is not found
708 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const
710 return find( title, find( pId ), rec );
714 \brief Search recursively all menu nodes with given \a title.
715 \param title menu item title
716 \param NodeList resulting list of menu nodes
717 \param startNode start menu node (if 0, search from root node)
718 \return \c true if at least one node is found
720 bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const
722 MenuNode* start = startNode ? startNode : myRoot;
723 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
725 QAction* a = itemAction( (*it)->id );
727 a = menuAction( (*it)->id );
728 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
731 find( title, lst, *it );
733 return !lst.isEmpty();
737 \brief Search menu node.
738 \param title menu item title
739 \param startNode start menu node (if 0, search from root node)
740 \param rec if \c true perform recursive search
741 \return menu node or 0 if it is not found
743 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const
746 MenuNode* start = startNode ? startNode : myRoot;
747 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
749 QAction* a = itemAction( (*it)->id );
751 a = menuAction( (*it)->id );
752 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
755 node = find( title, *it, rec );
761 \brief Find menu item by given ID (one-level only).
762 \param id menu action ID
763 \param pid parent meun item ID
764 \return id (>0) on success or -1 if menu item is not found
766 int QtxActionMenuMgr::findId( const int id, const int pid ) const
768 MenuNode* start = pid != -1 ? find( pid ) : myRoot;
771 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
773 if ( (*it)->id == id )
781 \brief Removes menu node (with all its children).
782 \param id menu action ID
783 \param startNode parent menu node which search starts from (if 0, search starts from root)
785 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
787 MenuNode* start = startNode ? startNode : myRoot;
788 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
790 if ( (*it)->id == id )
791 start->children.removeAll( *it );
793 removeMenu( id, *it );
798 \brief Get action by \a id.
800 \return action or 0 if \a id is invalid
802 QAction* QtxActionMenuMgr::itemAction( const int id ) const
808 \brief Get submenu action by \a id.
810 \return submenu action or 0 if action is not found
812 QAction* QtxActionMenuMgr::menuAction( const int id ) const
816 if ( myMenus.contains( id ) )
823 \brief Get submenu action by \a id.
825 \return submenu action or 0 if it is not found
827 int QtxActionMenuMgr::menuActionId( QAction* a ) const
830 for ( MenuMap::ConstIterator itr = myMenus.begin(); itr != myMenus.end() && id == -1; ++itr )
832 if ( itr.value() == a )
841 Does nothing if update is disabled.
843 \param startNode start menu item to be updated
844 \param rec if \c true, perform recursive update
845 \param updParent if \c true update also parent item (without recursion)
847 \sa isUpdatesEnabled() and setUpdatesEnabled()
849 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
851 if ( !isUpdatesEnabled() )
854 MenuNode* node = startNode ? startNode : myRoot;
856 QWidget* mw = menuWidget( node );
860 bool filled = checkWidget( mw );
862 // first remove all own actions and collect foreign ones
863 QMap< QAction*, QList<QAction*> > foreign;
866 QListIterator<QAction*> ait( mw->actions() ); ait.toBack();
867 while ( ait.hasPrevious() )
870 if ( ownAction( a, node ) )
873 mw->removeAction( a ); // remove own actions
877 foreign[preva].prepend(a); // do not yet remove foreign actions
880 // now only foreign actions should stay in the menu, thus remove them also
881 QMap< QAction*, QList<QAction*> >::Iterator formapit;
882 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit )
884 QMutableListIterator<QAction*> foralit( formapit.value() );
885 while ( foralit.hasNext() )
888 if ( !mw->actions().contains( a ) )
892 QList<QAction*> alist = mw->actions();
893 foreach( a, alist ) mw->removeAction( a );
895 // collect all registered menus by group id
896 QMap<int, NodeList> idMap;
897 for ( NodeList::iterator it2 = node->children.begin(); it2 != node->children.end(); ++it2 )
899 NodeList& lst = idMap[(*it2)->group];
900 int idx = (*it2)->idx;
901 if ( idx < 0 || idx >= (int)lst.count() )
904 lst.insert( idx, *it2 );
907 QIntList groups = idMap.keys();
910 groups.removeAll( -1 );
913 // rebuild menu: 1. add all registered actions
914 for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
916 if ( !idMap.contains( *gIt ) )
919 const NodeList& lst = idMap[*gIt];
920 for ( NodeList::const_iterator iter = lst.begin(); iter != lst.end(); ++iter )
922 MenuNode* node = *iter;
923 if ( !node ) continue;
926 updateMenu( node, rec, false );
928 MenuNode* par = node->parent;
929 if ( !isVisible( node->id, par ? par->id : -1 ) )
933 QAction* a = itemAction( node->id );
937 a = menuAction( node->id );
941 if ( !isMenu || !a->menu()->isEmpty() || node->emptyEnabled > 0 )
946 // rebuild menu: 2. insert back all foreign actions
947 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit ) {
948 preva = formapit.key();
949 foreach( a, formapit.value() )
950 mw->insertAction( preva, a );
953 // remove extra separators
954 simplifySeparators( mw );
956 // update parent menu if necessary
957 if ( updParent && node->parent && filled != checkWidget( mw ) )
958 updateMenu( node->parent, false );
962 \brief Internal update.
964 Customizes the menu update processing.
966 void QtxActionMenuMgr::internalUpdate()
968 if ( !isUpdatesEnabled() )
976 \brief Check if action belongs to the menu manager
978 \param a action being checked
979 \param node parent menu node
980 \return \c true if action belongs to the menu \a node
982 bool QtxActionMenuMgr::ownAction( QAction* a, MenuNode* node ) const
984 for ( NodeList::const_iterator iter = node->children.begin(); iter != node->children.end(); ++iter )
986 QAction* mya = itemAction( (*iter)->id );
987 if ( !mya ) mya = menuAction( (*iter)->id );
988 if ( mya && mya == a ) return true;
994 \brief Check if menu widget has any actions.
995 \param wid widget to be checked
996 \return \c true if widget contains action(s)
998 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
1003 return !wid->actions().isEmpty();
1007 \brief Get menu widget for the given \a node.
1008 \param node menu node
1009 \return popup menu or main menu corresponding to the menu node
1010 (or 0 if it is not found)
1012 QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node ) const
1014 if ( !node || node == myRoot )
1017 if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
1020 return myMenus[node->id]->menu();
1024 \brief Remove extra separators from menu widget.
1025 \param wid menu widget to be processed
1027 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
1029 Qtx::simplifySeparators( wid, false );
1033 \brief Remove special symbols (&) from string to get clear menu title.
1034 \param txt string to be processed
1037 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
1041 for ( int i = 0; i < (int)res.length(); i++ )
1043 if ( res.at( i ) == '&' )
1044 res.remove( i--, 1 );
1051 \brief Create and inserts menu item recursively.
1052 \param lst list of menu names
1053 \param pId parent menu item ID
1054 \return created menu item ID (last in the chain)
1056 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
1058 if ( lst.isEmpty() )
1061 QStringList sl( lst );
1063 QString title = sl.last().trimmed();
1066 int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
1068 return insert( title, parentId, -1 );
1072 \brief Load actions description from the file.
1073 \param fname file name
1074 \param r action reader
1075 \return \c true on success and \c false on error
1077 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
1079 MenuCreator cr( &r, this );
1080 return r.read( fname, cr );
1084 \brief Check if the parent menu contains menu item with given \a title.
1085 \param title menu title
1086 \param pid parent menu item ID
1087 \return \c true if parent menu item contains such child item
1089 bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid, const bool rec ) const
1091 return (bool)find( title, pid, rec );
1095 \brief Check if the parent menu contains menu item with given \a id.
1096 \param id menu item ID
1097 \param pid parent menu item ID
1098 \return \c true if parent menu item contains such child item
1100 bool QtxActionMenuMgr::containsMenu( const int id, const int pid, const bool rec ) const
1102 return (bool)find( id, pid, rec );
1106 \brief Get menu by the specified identifier.
1107 \param id menu item ID
1108 \return menu pointer or 0 if menu is not found
1110 QMenu* QtxActionMenuMgr::findMenu( const int id ) const
1113 QAction* a = menuAction( id );
1120 \brief Get menu by the title.
1121 \param title menu text
1122 \param pid parent menu item ID (to start search)
1123 \param rec if \c true, perform recursive update
1124 \return menu pointer or 0 if menu is not found
1126 QMenu* QtxActionMenuMgr::findMenu( const QString& title, const int pid, const bool rec ) const
1129 MenuNode* node = find( title, pid, rec );
1132 QAction* a = menuAction( node->id );
1140 \brief Check if empty menu is enabled
1141 \param id menu item ID
1142 \return \c true if empty menu is enabled
1144 bool QtxActionMenuMgr::isEmptyEnabled( const int id ) const
1146 MenuNode* node = find( id );
1147 if ( node && menuAction( id ) )
1148 return node->emptyEnabled > 0;
1154 \brief Enable/disable empty menu
1155 \param id menu item ID
1156 \param enable if \c true, empty menu will be enabled, otherwise empty menu will be disabled
1158 void QtxActionMenuMgr::setEmptyEnabled( const int id, const bool enable )
1160 MenuNode* node = find( id );
1161 if ( node && menuAction( id ) ) {
1162 int old = node->emptyEnabled;
1163 node->emptyEnabled += enable ? 1 : -1;
1164 if ( old <= 0 && enable || old > 0 && !enable ) // update menu only if enabled state has been changed
1165 updateMenu( node, true, true );
1170 \brief Perform delayed menu update.
1171 \param id menu item ID
1172 \param rec if \c true, perform recursive update
1174 void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec )
1177 if ( myUpdateIds.contains( id ) )
1178 isRec = isRec || myUpdateIds[ id ];
1179 myUpdateIds.insert( id, isRec );
1181 QtxActionMgr::triggerUpdate();
1185 \brief Called when delayed content update is performed.
1187 Customizes the content update operation.
1189 void QtxActionMenuMgr::updateContent()
1191 // Warning: For correct updating it is necessary to update the most enclosed submenu in first turn
1192 // because not updated empty submenu will be skipped. Now the submenus are iterated in
1193 // ascending order according to their identifiers. For a submenus with automatically generated
1194 // identifiers this will work correctly since the uppermost submenus have the biggest number
1195 // (identifiers are generated by decrementing 1 starting from -1). In general, if any submenu
1196 // have positive identifiers this method might not work correctly. In this case it would be
1197 // necessary to improve this method and to add preliminary sorting a submenus by depth of an
1199 for ( QMap<int, bool>::const_iterator it = myUpdateIds.constBegin(); it != myUpdateIds.constEnd(); ++it )
1201 MenuNode* node = it.key() == -1 ? myRoot : find( it.key() );
1203 updateMenu( node, it.value() );
1205 myUpdateIds.clear();
1209 \class QtxActionMenuMgr::MenuCreator
1210 \brief Menu actions creator.
1212 Used by Reader to create actions by reading descriptions from the file
1213 and fill in the action manager with the actions.
1218 \param r menu actions reader
1219 \param mgr menu manager
1221 QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r, QtxActionMenuMgr* mgr )
1222 : QtxActionMgr::Creator( r ),
1230 QtxActionMenuMgr::MenuCreator::~MenuCreator()
1235 \brief Create and append to the action manager a new action.
1236 \param tag item tag name
1237 \param subMenu \c true if this item is submenu
1238 \param attr attributes map
1239 \param pId parent action ID
1240 \return menu action ID
1242 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
1243 const ItemAttributes& attr, const int pId )
1245 if( !myMgr || !reader() )
1248 QString label = reader()->option( "label", "label" ),
1249 id = reader()->option( "id", "id" ),
1250 pos = reader()->option( "pos", "pos" ),
1251 group = reader()->option( "group", "group" ),
1252 tooltip = reader()->option( "tooltip", "tooltip" ),
1253 sep = reader()->option( "separator", "separator" ),
1254 accel = reader()->option( "accel", "accel" ),
1255 icon = reader()->option( "icon", "icon" ),
1256 toggle = reader()->option( "toggle", "toggle" );
1258 int res = -1, actId = intValue( attr, id, -1 );
1261 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1263 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1268 QString name = strValue( attr, icon );
1269 if( !name.isEmpty() && loadPixmap( name, pix ) )
1272 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
1273 strValue( attr, label ),
1274 QKeySequence( strValue( attr, accel ) ),
1276 newAct->setToolTip( strValue( attr, tooltip ) );
1277 QString toggleact = strValue( attr, toggle );
1278 newAct->setCheckable( !toggleact.isEmpty() );
1279 newAct->setChecked( toggleact.toLower() == "true" );
1282 int aid = myMgr->registerAction( newAct, actId );
1283 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );