1 // Copyright (C) 2007-2016 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, or (at your option) any later version.
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
23 // File: QtxActionMenuMgr.cxx
24 // Author: Alexander SOLOVYOV, Sergey TELKOV
26 #include "QtxActionMenuMgr.h"
28 #include "QtxAction.h"
33 #include <QMainWindow>
36 \class QtxActionMenuMgr::MenuNode
37 \brief Represents a menu item inside main menu structure.
41 class QtxActionMenuMgr::MenuNode
45 MenuNode( MenuNode*, const int, const int, const int );
48 MenuNode* parent; //!< parent menu node
49 int id; //!< menu nodeID
50 int idx; //!< menu node index
51 int group; //!< menu group ID
52 bool visible; //!< visibility status
53 int emptyEnabled; //!< enable empty menu flag
54 NodeList children; //!< children menu nodes list
58 \brief Default constructor.
61 QtxActionMenuMgr::MenuNode::MenuNode()
62 : parent( 0 ), id( -1 ), idx( -1 ), group( -1 ), visible( true ), emptyEnabled( 0 )
69 \param p parent menu node
70 \param _id menu node ID
71 \param _idx menu node index
72 \param _group menu node group ID
74 QtxActionMenuMgr::MenuNode::MenuNode( MenuNode* p,
78 : parent( p ), id( _id ), idx( _idx ), group( _group ), visible( true ), emptyEnabled( 0 )
81 p->children.append( this );
88 QtxActionMenuMgr::MenuNode::~MenuNode()
90 for ( NodeList::iterator it = children.begin(); it != children.end(); ++it )
95 \class QtxActionMenuMgr
96 \brief Main menu actions manager.
98 Menu manager allows using of set of action for automatic generating of
99 application main menu and dynamic update of its contents.
101 Use insert(), append() and remove() methods to create main menu.
102 Methods show(), hide() allow displaying/erasing of specified menu items.
104 Actions can be grouped with help of group identificator. Inside the popup
105 or main menu bar menu items are ordered by the group identifier (ascending).
107 Menu manager automatically optimizes the menu by removing extra separators,
108 hiding empty popup menus etc.
113 \param p parent main window
115 QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p )
117 myRoot( new MenuNode() ),
118 myMenu( p ? p->menuBar() : 0 )
121 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
127 \param mw menu widget
128 \param p parent object
130 QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p )
132 myRoot( new MenuNode() ),
136 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
143 QtxActionMenuMgr::~QtxActionMenuMgr()
145 for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
147 QPointer<QAction> a = itr.value();
156 \brief Check if an action with \a actId identifier is visible to
157 the parent action with \a place identifier.
158 \param actId action ID
159 \param place some parent action ID
160 \return \c true if an action is visible to the parent
163 bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const
165 MenuNode* node = find( actId, place );
166 return node && node->visible;
170 \brief Set action's visibility flag.
171 \param actId action ID
172 \param place some parent action ID
173 \param v new visibility state
176 void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v )
178 MenuNode* node = find( actId, place );
184 \brief Insert action to the menu.
186 Insert an action to the named menu. The \a menus parameter represents
187 the menu name: it can be a sequence of strings, separated by '|' symbol.
188 For example, "File|Edit" means \c File->Edit submenu.
189 If submenu doesn't exist, it will be created.
192 \param menus menu name
193 \param group group ID
194 \param idx menu index inside the menu group
197 int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx )
199 return insert( id, menus.split( "|", QString::SkipEmptyParts ), group, idx );
203 \brief Insert action to the menu.
205 Insert an action to the named menu. The \a menus parameter represents
206 the menu name: it can be a sequence of strings, separated by '|' symbol.
207 For example, "File|Edit" means \c File->Edit submenu.
208 If submenu doesn't exist, it will be created.
211 \param menus menu name
212 \param group group ID
213 \param idx menu index inside the menu group
216 int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx )
218 return insert( a, menus.split( "|", QString::SkipEmptyParts ), group, idx );
222 \brief Insert action to the menu.
224 Insert an action to the named menu. The \a menus parameter represents
226 For example, string list consisting from two items "File" and "Edit"
227 means \c File->Edit submenu.
228 If submenu doesn't exist, it will be created.
231 \param menus menu names list
232 \param group group ID
233 \param idx menu index inside the menu group
236 int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx )
238 int pId = createMenu( menus, -1 );
242 return insert( id, pId, group, idx );
246 \brief Insert action to the menu.
248 Insert an action to the named menu. The \a menus parameter represents
250 For example, string list consisting from two items "File" and "Edit"
251 means \c File->Edit submenu.
252 If submenu doesn't exist, it will be created.
255 \param menus menu names list
256 \param group group ID
257 \param idx menu index inside the menu group
260 int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx )
262 int pId = createMenu( menus, -1 );
266 return insert( a, pId, group, idx );
270 \brief Insert action to the menu.
272 \param pId parent menu action ID
273 \param group group ID
274 \param idx menu index inside the menu group
277 int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx )
282 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
286 MenuNode* node = new MenuNode( pNode, id, idx, group );
288 triggerUpdate( pNode->id, false );
294 \brief Insert action to the menu.
296 \param pId parent menu action ID
297 \param group group ID
298 \param idx menu index inside the menu group
301 int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx )
303 return insert( registerAction( a ), pId, group, idx );
307 \brief Create and insert menu item action to the menu.
308 \param title menu text
309 \param pId parent menu action ID
310 \param group group ID
312 \param idx menu index inside the menu group
315 int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group,
316 const int id, const int idx, QMenu* _menu)
318 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
322 MenuNode* eNode = id == -1 ? 0 : find( id );
325 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end() && fid == -1; ++it )
327 if ( myMenus.contains( (*it)->id ) &&
328 clearTitle( myMenus[(*it)->id]->text() ) == clearTitle( title ) )
335 int gid = (id == -1 || eNode ) ? generateId() : id;
341 menu = new QMenu( 0 );
342 QAction* ma = menu->menuAction();
343 ma->setText( title );
345 connect( ma->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
346 connect( ma->menu(), SIGNAL( aboutToHide() ), this, SLOT( onAboutToHide() ) );
348 MenuNode* node = new MenuNode( pNode, myMenus.insert( gid, ma ).key(), idx, group );
350 triggerUpdate( pNode->id, false );
356 \brief Create and insert menu item action to the menu.
358 Insert an action to the named menu. The \a menus parameter represents
359 the menu name: it can be a sequence of strings, separated by '|' symbol.
360 For example, "File|Edit" means \c File->Edit submenu.
361 If submenu doesn't exist, it will be created.
363 \param title menu text
364 \param menus menu name
365 \param group group ID
367 \param idx menu index inside the menu group
370 int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx )
372 return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx );
376 \brief Create and insert menu item action to the menu.
378 Insert an action to the named menu. The \a menus parameter represents
380 For example, string list consisting from two items "File" and "Edit"
381 means \c File->Edit submenu.
382 If submenu doesn't exist, it will be created.
384 \param title menu text
385 \param menus menu names list
386 \param group group ID
388 \param idx menu index inside the menu group
391 int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx )
393 int pId = createMenu( menus, -1 );
394 return insert( title, pId, group, id, idx );
398 \brief Create and add menu item action to the end of menu.
399 \param title menu text
400 \param pId parent menu action ID
401 \param group group ID
405 int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id )
407 return insert( title, pId, group, id );
411 \brief Create and add menu item action to the end of menu.
413 \param pId parent menu action ID
414 \param group group ID
417 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
419 return insert( id, pId, group );
423 \brief Create and add menu item action to the end of menu.
425 \param pId parent menu action ID
426 \param group group ID
429 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
431 return insert( a, pId, group );
435 \brief Create and add menu item action to the beginning of menu.
436 \param title menu text
437 \param pId parent menu action ID
438 \param group group ID
442 int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id )
444 return insert( title, pId, group, id, 0 );
448 \brief Create and add menu item action to the beginning of menu.
450 \param pId parent menu action ID
451 \param group group ID
454 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
456 return insert( id, pId, group, 0 );
460 \brief Create and add menu item action to the beginning of menu.
462 \param pId parent menu action ID
463 \param group group ID
466 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
468 return insert( a, pId, group, 0 );
472 \brief Remove menu item with given \a id.
473 \param id menu action ID
475 void QtxActionMenuMgr::remove( const int id )
482 \brief Remove menu item with given \a id.
483 \param id menu action ID
484 \param pId parent menu action ID
485 \param group group ID
487 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
489 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
494 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end(); ++it )
496 if ( (*it)->id == id && ( (*it)->group == group || group == -1 ) )
497 delNodes.append( *it );
500 QWidget* mW = menuWidget( pNode );
501 for ( NodeList::iterator itr = delNodes.begin(); itr != delNodes.end(); ++itr )
504 if( mW && menuAction( id ) )
506 mW->removeAction( menuAction( id ) );
507 myMenus.remove( id );
509 else if( mW && itemAction( id ) )
510 mW->removeAction( itemAction( id ) );
511 pNode->children.removeAll( *itr );
514 triggerUpdate( pNode->id, false );
518 \brief Show menu item with given \a id.
519 \param id menu action ID
522 void QtxActionMenuMgr::show( const int id )
524 setShown( id, true );
528 \brief Hide menu item with given \a id.
529 \param id menu action ID
532 void QtxActionMenuMgr::hide( const int id )
534 setShown( id, false );
538 \brief Get visibility status for menu item with given \a id.
539 \param id menu action ID
540 \return \c true if an item is shown
543 bool QtxActionMenuMgr::isShown( const int id ) const
546 MenuNode* node = find( id );
553 \brief Set visibility status for menu item with given \a id.
554 \param id menu action ID
555 \param on new visibility status
558 void QtxActionMenuMgr::setShown( const int id, const bool on )
563 for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
565 if ( (*it)->visible != on )
568 triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot->id, false );
574 \brief Change menu title for the action with given \a id.
575 \param id menu action ID
576 \param title new menu title
578 void QtxActionMenuMgr::change( const int id, const QString& title )
580 QAction* a = menuAction( id );
586 \brief Called when the submenu is about to show.
588 Emits the signal menuAboutToShow(QMenu*).
590 void QtxActionMenuMgr::onAboutToShow()
592 QMenu* m = ::qobject_cast<QMenu*>( sender() );
594 emit menuAboutToShow( m );
598 \brief Called when the submenu is about to hide.
600 Emits the signal menuAboutToHide(QMenu*).
602 void QtxActionMenuMgr::onAboutToHide()
604 QMenu* m = ::qobject_cast<QMenu*>( sender() );
606 emit menuAboutToHide( m );
610 \brief Called when the corresponding menu object is destroyed.
612 Clears internal pointer to menu to disable crashes.
614 \param obj (menu) object being destroyed
616 void QtxActionMenuMgr::onDestroyed( QObject* obj )
624 \fn void QtxActionMenuMgr::menuAboutToShow( QMenu* m )
625 \brief Emitted when the menu is about to be shown.
626 \param m menu being shown
630 \fn void QtxActionMenuMgr::menuAboutToHide( QMenu* m )
631 \brief Emitted when the menu is about to be hidden.
632 \param m menu being hidden
636 \brief Get the menu widget.
637 \return menu widget (QMenuBar)
639 QWidget* QtxActionMenuMgr::menuWidget() const
645 \brief Assign new menu widget to the menu manager.
646 \param mw new menu widget
648 void QtxActionMenuMgr::setMenuWidget( QWidget* mw )
654 disconnect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
659 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
661 triggerUpdate( -1, true );
665 \brief Search menu node.
666 \param id menu action ID
667 \param pId parent menu item ID
668 \param rec if \c true perform recursive search
669 \return menu node or 0 if it is not found
671 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, const int pId, const bool rec ) const
673 return find( id, find( pId ), rec );
677 \brief Search menu node.
678 \param id menu action ID
679 \param startNode start menu node (if 0, search from root node)
680 \param rec if \c true perform recursive search
681 \return menu node or 0 if it is not found
683 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const
686 MenuNode* start = startNode ? startNode : myRoot;
687 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
689 if ( (*it)->id == id )
692 node = find( id, *it, rec );
698 \brief Search recursively all menu nodes with given \a id.
699 \param id menu action ID
700 \param NodeList resulting list of menu nodes
701 \param startNode start menu node (if 0, search from root node)
702 \return \c true if at least one node is found
704 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
706 MenuNode* start = startNode ? startNode : myRoot;
707 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
709 MenuNode* node = *it;
710 if ( node->id == id )
713 find( id, lst, node );
715 return !lst.isEmpty();
719 \brief Search menu node.
720 \param title menu item title
721 \param pId parent menu item ID
722 \param rec if \c true perform recursive search
723 \return menu node or 0 if it is not found
725 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const
727 return find( title, find( pId ), rec );
731 \brief Search recursively all menu nodes with given \a title.
732 \param title menu item title
733 \param NodeList resulting list of menu nodes
734 \param startNode start menu node (if 0, search from root node)
735 \return \c true if at least one node is found
737 bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const
739 MenuNode* start = startNode ? startNode : myRoot;
740 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
742 QAction* a = itemAction( (*it)->id );
744 a = menuAction( (*it)->id );
745 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
748 find( title, lst, *it );
750 return !lst.isEmpty();
754 \brief Search menu node.
755 \param title menu item title
756 \param startNode start menu node (if 0, search from root node)
757 \param rec if \c true perform recursive search
758 \return menu node or 0 if it is not found
760 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const
763 MenuNode* start = startNode ? startNode : myRoot;
764 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
766 QAction* a = itemAction( (*it)->id );
768 a = menuAction( (*it)->id );
769 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
772 node = find( title, *it, rec );
778 \brief Find menu item by given ID (one-level only).
779 \param id menu action ID
780 \param pid parent meun item ID
781 \return id (>0) on success or -1 if menu item is not found
783 int QtxActionMenuMgr::findId( const int id, const int pid ) const
785 MenuNode* start = pid != -1 ? find( pid ) : myRoot;
788 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
790 if ( (*it)->id == id )
798 \brief Removes menu node (with all its children).
799 \param id menu action ID
800 \param startNode parent menu node which search starts from (if 0, search starts from root)
802 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
804 MenuNode* start = startNode ? startNode : myRoot;
805 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
807 if ( (*it)->id == id )
808 start->children.removeAll( *it );
810 removeMenu( id, *it );
815 \brief Get action by \a id.
817 \return action or 0 if \a id is invalid
819 QAction* QtxActionMenuMgr::itemAction( const int id ) const
825 \brief Get submenu action by \a id.
827 \return submenu action or 0 if action is not found
829 QAction* QtxActionMenuMgr::menuAction( const int id ) const
833 if ( myMenus.contains( id ) )
840 \brief Get submenu action by \a id.
842 \return submenu action or 0 if it is not found
844 int QtxActionMenuMgr::menuActionId( QAction* a ) const
847 for ( MenuMap::ConstIterator itr = myMenus.begin(); itr != myMenus.end() && id == -1; ++itr )
849 if ( itr.value() == a )
858 Does nothing if update is disabled.
860 \param startNode start menu item to be updated
861 \param rec if \c true, perform recursive update
862 \param updParent if \c true update also parent item (without recursion)
864 \sa isUpdatesEnabled() and setUpdatesEnabled()
866 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
868 if ( !isUpdatesEnabled() )
871 MenuNode* node = startNode ? startNode : myRoot;
873 QWidget* mw = menuWidget( node );
877 // first remove all own actions and collect foreign ones
878 QMap< QAction*, QList<QAction*> > foreign;
881 QListIterator<QAction*> ait( mw->actions() ); ait.toBack();
882 while ( ait.hasPrevious() )
885 if ( ownAction( a, node ) )
888 mw->removeAction( a ); // remove own actions
892 foreign[preva].prepend(a); // do not yet remove foreign actions
895 // now only foreign actions should stay in the menu, thus remove them also
896 QMap< QAction*, QList<QAction*> >::Iterator formapit;
897 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit )
899 QMutableListIterator<QAction*> foralit( formapit.value() );
900 while ( foralit.hasNext() )
903 if ( !mw->actions().contains( a ) )
907 QList<QAction*> alist = mw->actions();
908 foreach( a, alist ) mw->removeAction( a );
910 // collect all registered menus by group id
911 QMap<int, NodeList> idMap;
912 for ( NodeList::iterator it2 = node->children.begin(); it2 != node->children.end(); ++it2 )
914 NodeList& lst = idMap[(*it2)->group];
915 int idx = (*it2)->idx;
916 if ( idx < 0 || idx >= (int)lst.count() )
919 lst.insert( idx, *it2 );
922 QIntList groups = idMap.keys();
925 groups.removeAll( -1 );
928 // rebuild menu: 1. add all registered actions
929 for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
931 if ( !idMap.contains( *gIt ) )
934 const NodeList& lst = idMap[*gIt];
935 for ( NodeList::const_iterator iter = lst.begin(); iter != lst.end(); ++iter )
937 MenuNode* node = *iter;
938 if ( !node ) continue;
941 updateMenu( node, rec, false );
943 MenuNode* par = node->parent;
944 if ( !isVisible( node->id, par ? par->id : -1 ) )
948 QAction* a = itemAction( node->id );
952 a = menuAction( node->id );
956 if ( !isMenu || !a->menu()->isEmpty() || node->emptyEnabled > 0 )
961 // rebuild menu: 2. insert back all foreign actions
962 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit ) {
963 preva = formapit.key();
964 foreach( a, formapit.value() )
965 mw->insertAction( preva, a );
968 // remove extra separators
969 simplifySeparators( mw );
971 // update parent menu if necessary
972 if ( updParent && node->parent ) {
973 updateMenu( node->parent, false );
978 \brief Internal update.
980 Customizes the menu update processing.
982 void QtxActionMenuMgr::internalUpdate()
984 if ( !isUpdatesEnabled() )
992 \brief Check if action belongs to the menu manager
994 \param a action being checked
995 \param node parent menu node
996 \return \c true if action belongs to the menu \a node
998 bool QtxActionMenuMgr::ownAction( QAction* a, MenuNode* node ) const
1000 for ( NodeList::const_iterator iter = node->children.begin(); iter != node->children.end(); ++iter )
1002 QAction* mya = itemAction( (*iter)->id );
1004 mya = menuAction( (*iter)->id );
1005 if ( mya && mya == a )
1012 \brief Check if menu widget has any actions.
1013 \param wid widget to be checked
1014 \return \c true if widget contains action(s)
1016 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
1022 QList<QAction*> lst = wid->actions();
1023 for ( QList<QAction*>::const_iterator it = lst.begin(); it != lst.end() && !res; ++it ) {
1024 res = !(*it)->isSeparator() && (*it)->isVisible();
1030 \brief Get menu widget for the given \a node.
1031 \param node menu node
1032 \return popup menu or main menu corresponding to the menu node
1033 (or 0 if it is not found)
1035 QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node ) const
1037 if ( !node || node == myRoot )
1040 if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
1043 return myMenus[node->id]->menu();
1047 \brief Remove extra separators from menu widget.
1048 \param wid menu widget to be processed
1050 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
1052 Qtx::simplifySeparators( wid, false );
1056 \brief Remove special symbols (&) from string to get clear menu title.
1057 \param txt string to be processed
1060 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
1064 for ( int i = 0; i < (int)res.length(); i++ )
1066 if ( res.at( i ) == '&' )
1067 res.remove( i--, 1 );
1074 \brief Create and inserts menu item recursively.
1075 \param lst list of menu names
1076 \param pId parent menu item ID
1077 \return created menu item ID (last in the chain)
1079 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
1081 if ( lst.isEmpty() )
1084 QStringList sl( lst );
1086 QString title = sl.last().trimmed();
1089 int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
1091 return insert( title, parentId, -1 );
1095 \brief Load actions description from the file.
1096 \param fname file name
1097 \param r action reader
1098 \return \c true on success and \c false on error
1100 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
1102 MenuCreator cr( &r, this );
1103 return r.read( fname, cr );
1107 \brief Check if the parent menu contains menu item with given \a title.
1108 \param title menu title
1109 \param pid parent menu item ID
1110 \return \c true if parent menu item contains such child item
1112 bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid, const bool rec ) const
1114 return (bool)find( title, pid, rec );
1118 \brief Check if the parent menu contains menu item with given \a id.
1119 \param id menu item ID
1120 \param pid parent menu item ID
1121 \return \c true if parent menu item contains such child item
1123 bool QtxActionMenuMgr::containsMenu( const int id, const int pid, const bool rec ) const
1125 return (bool)find( id, pid, rec );
1129 \brief Get menu by the specified identifier.
1130 \param id menu item ID
1131 \return menu pointer or 0 if menu is not found
1133 QMenu* QtxActionMenuMgr::findMenu( const int id ) const
1136 QAction* a = menuAction( id );
1143 \brief Get menu by the title.
1144 \param title menu text
1145 \param pid parent menu item ID (to start search)
1146 \param rec if \c true, perform recursive update
1147 \return menu pointer or 0 if menu is not found
1149 QMenu* QtxActionMenuMgr::findMenu( const QString& title, const int pid, const bool rec ) const
1152 MenuNode* node = find( title, pid, rec );
1155 QAction* a = menuAction( node->id );
1163 \brief Check if empty menu is enabled
1164 \param id menu item ID
1165 \return \c true if empty menu is enabled
1167 bool QtxActionMenuMgr::isEmptyEnabled( const int id ) const
1169 MenuNode* node = find( id );
1170 if ( node && menuAction( id ) )
1171 return node->emptyEnabled > 0;
1177 \brief Enable/disable empty menu
1178 \param id menu item ID
1179 \param enable if \c true, empty menu will be enabled, otherwise empty menu will be disabled
1181 void QtxActionMenuMgr::setEmptyEnabled( const int id, const bool enable )
1183 MenuNode* node = find( id );
1184 if ( node && menuAction( id ) ) {
1185 int old = node->emptyEnabled;
1186 node->emptyEnabled += enable ? 1 : -1;
1187 if ( ( old <= 0 && enable ) || ( old > 0 && !enable ) ) // update menu only if enabled state has been changed
1188 updateMenu( node, true, true );
1193 \brief Perform delayed menu update.
1194 \param id menu item ID
1195 \param rec if \c true, perform recursive update
1197 void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec )
1200 if ( myUpdateIds.contains( id ) )
1201 isRec = isRec || myUpdateIds[ id ];
1202 myUpdateIds.insert( id, isRec );
1204 QtxActionMgr::triggerUpdate();
1208 \brief Called when action is changed.
1210 Schedule delayed update for parent menu of changed action.
1212 void QtxActionMenuMgr::actionChanged( int id )
1217 for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
1219 MenuNode* node = *it;
1220 if ( node->visible ) {
1221 triggerUpdate( node->parent ? node->parent->id : myRoot->id, false );
1227 \brief Called when delayed content update is performed.
1229 Customizes the content update operation.
1231 void QtxActionMenuMgr::updateContent()
1233 // Warning: For correct updating it is necessary to update the most enclosed submenu in first turn
1234 // because not updated empty submenu will be skipped. Now the submenus are iterated in
1235 // ascending order according to their identifiers. For a submenus with automatically generated
1236 // identifiers this will work correctly since the uppermost submenus have the biggest number
1237 // (identifiers are generated by decrementing 1 starting from -1). In general, if any submenu
1238 // have positive identifiers this method might not work correctly. In this case it would be
1239 // necessary to improve this method and to add preliminary sorting a submenus by depth of an
1241 for ( QMap<int, bool>::const_iterator it = myUpdateIds.constBegin(); it != myUpdateIds.constEnd(); ++it )
1243 MenuNode* node = it.key() == -1 ? myRoot : find( it.key() );
1245 updateMenu( node, it.value() );
1247 myUpdateIds.clear();
1251 \class QtxActionMenuMgr::MenuCreator
1252 \brief Menu actions creator.
1254 Used by Reader to create actions by reading descriptions from the file
1255 and fill in the action manager with the actions.
1260 \param r menu actions reader
1261 \param mgr menu manager
1263 QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r, QtxActionMenuMgr* mgr )
1264 : QtxActionMgr::Creator( r ),
1272 QtxActionMenuMgr::MenuCreator::~MenuCreator()
1277 \brief Create and append to the action manager a new action.
1278 \param tag item tag name
1279 \param subMenu \c true if this item is submenu
1280 \param attr attributes map
1281 \param pId parent action ID
1282 \return menu action ID
1284 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
1285 const ItemAttributes& attr, const int pId )
1287 if( !myMgr || !reader() )
1290 QString label = reader()->option( "label", "label" ),
1291 id = reader()->option( "id", "id" ),
1292 pos = reader()->option( "pos", "pos" ),
1293 group = reader()->option( "group", "group" ),
1294 tooltip = reader()->option( "tooltip", "tooltip" ),
1295 sep = reader()->option( "separator", "separator" ),
1296 accel = reader()->option( "accel", "accel" ),
1297 icon = reader()->option( "icon", "icon" ),
1298 toggle = reader()->option( "toggle", "toggle" );
1300 int res = -1, actId = intValue( attr, id, -1 );
1303 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1305 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1310 QString name = strValue( attr, icon );
1311 if( !name.isEmpty() && loadPixmap( name, pix ) )
1314 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
1315 strValue( attr, label ),
1316 QKeySequence( strValue( attr, accel ) ),
1318 newAct->setToolTip( strValue( attr, tooltip ) );
1319 QString toggleact = strValue( attr, toggle );
1320 newAct->setCheckable( !toggleact.isEmpty() );
1321 newAct->setChecked( toggleact.toLower() == "true" );
1324 int aid = myMgr->registerAction( newAct, actId );
1325 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );