1 // Copyright (C) 2007-2014 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, const int id, const int idx )
317 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
321 MenuNode* eNode = id == -1 ? 0 : find( id );
324 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end() && fid == -1; ++it )
326 if ( myMenus.contains( (*it)->id ) &&
327 clearTitle( myMenus[(*it)->id]->text() ) == clearTitle( title ) )
334 int gid = (id == -1 || eNode ) ? generateId() : id;
336 QMenu* menu = new QMenu( 0 );
337 QAction* ma = menu->menuAction();
338 ma->setText( title );
340 connect( ma->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
341 connect( ma->menu(), SIGNAL( aboutToHide() ), this, SLOT( onAboutToHide() ) );
343 MenuNode* node = new MenuNode( pNode, myMenus.insert( gid, ma ).key(), idx, group );
345 triggerUpdate( pNode->id, false );
351 \brief Create and insert menu item action to the menu.
353 Insert an action to the named menu. The \a menus parameter represents
354 the menu name: it can be a sequence of strings, separated by '|' symbol.
355 For example, "File|Edit" means \c File->Edit submenu.
356 If submenu doesn't exist, it will be created.
358 \param title menu text
359 \param menus menu name
360 \param group group ID
362 \param idx menu index inside the menu group
365 int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx )
367 return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx );
371 \brief Create and insert menu item action to the menu.
373 Insert an action to the named menu. The \a menus parameter represents
375 For example, string list consisting from two items "File" and "Edit"
376 means \c File->Edit submenu.
377 If submenu doesn't exist, it will be created.
379 \param title menu text
380 \param menus menu names list
381 \param group group ID
383 \param idx menu index inside the menu group
386 int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx )
388 int pId = createMenu( menus, -1 );
389 return insert( title, pId, group, id, idx );
393 \brief Create and add menu item action to the end of menu.
394 \param title menu text
395 \param pId parent menu action ID
396 \param group group ID
400 int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id )
402 return insert( title, pId, group, id );
406 \brief Create and add menu item action to the end of menu.
408 \param pId parent menu action ID
409 \param group group ID
412 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
414 return insert( id, pId, group );
418 \brief Create and add menu item action to the end of menu.
420 \param pId parent menu action ID
421 \param group group ID
424 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
426 return insert( a, pId, group );
430 \brief Create and add menu item action to the beginning of menu.
431 \param title menu text
432 \param pId parent menu action ID
433 \param group group ID
437 int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id )
439 return insert( title, pId, group, id, 0 );
443 \brief Create and add menu item action to the beginning of menu.
445 \param pId parent menu action ID
446 \param group group ID
449 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
451 return insert( id, pId, group, 0 );
455 \brief Create and add menu item action to the beginning of menu.
457 \param pId parent menu action ID
458 \param group group ID
461 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
463 return insert( a, pId, group, 0 );
467 \brief Remove menu item with given \a id.
468 \param id menu action ID
470 void QtxActionMenuMgr::remove( const int id )
477 \brief Remove menu item with given \a id.
478 \param id menu action ID
479 \param pId parent menu action ID
480 \param group group ID
482 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
484 MenuNode* pNode = pId == -1 ? myRoot : find( pId );
489 for ( NodeList::iterator it = pNode->children.begin(); it != pNode->children.end(); ++it )
491 if ( (*it)->id == id && ( (*it)->group == group || group == -1 ) )
492 delNodes.append( *it );
495 QWidget* mW = menuWidget( pNode );
496 for ( NodeList::iterator itr = delNodes.begin(); itr != delNodes.end(); ++itr )
499 if( mW && menuAction( id ) )
501 mW->removeAction( menuAction( id ) );
502 myMenus.remove( id );
504 else if( mW && itemAction( id ) )
505 mW->removeAction( itemAction( id ) );
506 pNode->children.removeAll( *itr );
509 triggerUpdate( pNode->id, false );
513 \brief Show menu item with given \a id.
514 \param id menu action ID
517 void QtxActionMenuMgr::show( const int id )
519 setShown( id, true );
523 \brief Hide menu item with given \a id.
524 \param id menu action ID
527 void QtxActionMenuMgr::hide( const int id )
529 setShown( id, false );
533 \brief Get visibility status for menu item with given \a id.
534 \param id menu action ID
535 \return \c true if an item is shown
538 bool QtxActionMenuMgr::isShown( const int id ) const
541 MenuNode* node = find( id );
548 \brief Set visibility status for menu item with given \a id.
549 \param id menu action ID
550 \param on new visibility status
553 void QtxActionMenuMgr::setShown( const int id, const bool on )
558 for ( NodeList::iterator it = aNodes.begin(); it != aNodes.end(); ++it )
560 if ( (*it)->visible != on )
563 triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot->id, false );
569 \brief Change menu title for the action with given \a id.
570 \param id menu action ID
571 \param title new menu title
573 void QtxActionMenuMgr::change( const int id, const QString& title )
575 QAction* a = menuAction( id );
581 \brief Called when the submenu is about to show.
583 Emits the signal menuAboutToShow(QMenu*).
585 void QtxActionMenuMgr::onAboutToShow()
587 QMenu* m = ::qobject_cast<QMenu*>( sender() );
589 emit menuAboutToShow( m );
593 \brief Called when the submenu is about to hide.
595 Emits the signal menuAboutToHide(QMenu*).
597 void QtxActionMenuMgr::onAboutToHide()
599 QMenu* m = ::qobject_cast<QMenu*>( sender() );
601 emit menuAboutToHide( m );
605 \brief Called when the corresponding menu object is destroyed.
607 Clears internal pointer to menu to disable crashes.
609 \param obj (menu) object being destroyed
611 void QtxActionMenuMgr::onDestroyed( QObject* obj )
619 \fn void QtxActionMenuMgr::menuAboutToShow( QMenu* m )
620 \brief Emitted when the menu is about to be shown.
621 \param m menu being shown
625 \fn void QtxActionMenuMgr::menuAboutToHide( QMenu* m )
626 \brief Emitted when the menu is about to be hidden.
627 \param m menu being hidden
631 \brief Get the menu widget.
632 \return menu widget (QMenuBar)
634 QWidget* QtxActionMenuMgr::menuWidget() const
640 \brief Assign new menu widget to the menu manager.
641 \param mw new menu widget
643 void QtxActionMenuMgr::setMenuWidget( QWidget* mw )
649 disconnect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
654 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
656 triggerUpdate( -1, true );
660 \brief Search menu node.
661 \param id menu action ID
662 \param pId parent menu item ID
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, const int pId, const bool rec ) const
668 return find( id, find( pId ), rec );
672 \brief Search menu node.
673 \param id menu action ID
674 \param startNode start menu node (if 0, search from root node)
675 \param rec if \c true perform recursive search
676 \return menu node or 0 if it is not found
678 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const
681 MenuNode* start = startNode ? startNode : myRoot;
682 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
684 if ( (*it)->id == id )
687 node = find( id, *it, rec );
693 \brief Search recursively all menu nodes with given \a id.
694 \param id menu action ID
695 \param NodeList resulting list of menu nodes
696 \param startNode start menu node (if 0, search from root node)
697 \return \c true if at least one node is found
699 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
701 MenuNode* start = startNode ? startNode : myRoot;
702 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
704 MenuNode* node = *it;
705 if ( node->id == id )
708 find( id, lst, node );
710 return !lst.isEmpty();
714 \brief Search menu node.
715 \param title menu item title
716 \param pId parent menu item ID
717 \param rec if \c true perform recursive search
718 \return menu node or 0 if it is not found
720 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const
722 return find( title, find( pId ), rec );
726 \brief Search recursively all menu nodes with given \a title.
727 \param title menu item title
728 \param NodeList resulting list of menu nodes
729 \param startNode start menu node (if 0, search from root node)
730 \return \c true if at least one node is found
732 bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const
734 MenuNode* start = startNode ? startNode : myRoot;
735 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
737 QAction* a = itemAction( (*it)->id );
739 a = menuAction( (*it)->id );
740 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
743 find( title, lst, *it );
745 return !lst.isEmpty();
749 \brief Search menu node.
750 \param title menu item title
751 \param startNode start menu node (if 0, search from root node)
752 \param rec if \c true perform recursive search
753 \return menu node or 0 if it is not found
755 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const
758 MenuNode* start = startNode ? startNode : myRoot;
759 for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it )
761 QAction* a = itemAction( (*it)->id );
763 a = menuAction( (*it)->id );
764 if ( a && clearTitle( a->text() ) == clearTitle( title ) )
767 node = find( title, *it, rec );
773 \brief Find menu item by given ID (one-level only).
774 \param id menu action ID
775 \param pid parent meun item ID
776 \return id (>0) on success or -1 if menu item is not found
778 int QtxActionMenuMgr::findId( const int id, const int pid ) const
780 MenuNode* start = pid != -1 ? find( pid ) : myRoot;
783 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
785 if ( (*it)->id == id )
793 \brief Removes menu node (with all its children).
794 \param id menu action ID
795 \param startNode parent menu node which search starts from (if 0, search starts from root)
797 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
799 MenuNode* start = startNode ? startNode : myRoot;
800 for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it )
802 if ( (*it)->id == id )
803 start->children.removeAll( *it );
805 removeMenu( id, *it );
810 \brief Get action by \a id.
812 \return action or 0 if \a id is invalid
814 QAction* QtxActionMenuMgr::itemAction( const int id ) const
820 \brief Get submenu action by \a id.
822 \return submenu action or 0 if action is not found
824 QAction* QtxActionMenuMgr::menuAction( const int id ) const
828 if ( myMenus.contains( id ) )
835 \brief Get submenu action by \a id.
837 \return submenu action or 0 if it is not found
839 int QtxActionMenuMgr::menuActionId( QAction* a ) const
842 for ( MenuMap::ConstIterator itr = myMenus.begin(); itr != myMenus.end() && id == -1; ++itr )
844 if ( itr.value() == a )
853 Does nothing if update is disabled.
855 \param startNode start menu item to be updated
856 \param rec if \c true, perform recursive update
857 \param updParent if \c true update also parent item (without recursion)
859 \sa isUpdatesEnabled() and setUpdatesEnabled()
861 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
863 if ( !isUpdatesEnabled() )
866 MenuNode* node = startNode ? startNode : myRoot;
868 QWidget* mw = menuWidget( node );
872 bool filled = checkWidget( mw );
874 // first remove all own actions and collect foreign ones
875 QMap< QAction*, QList<QAction*> > foreign;
878 QListIterator<QAction*> ait( mw->actions() ); ait.toBack();
879 while ( ait.hasPrevious() )
882 if ( ownAction( a, node ) )
885 mw->removeAction( a ); // remove own actions
889 foreign[preva].prepend(a); // do not yet remove foreign actions
892 // now only foreign actions should stay in the menu, thus remove them also
893 QMap< QAction*, QList<QAction*> >::Iterator formapit;
894 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit )
896 QMutableListIterator<QAction*> foralit( formapit.value() );
897 while ( foralit.hasNext() )
900 if ( !mw->actions().contains( a ) )
904 QList<QAction*> alist = mw->actions();
905 foreach( a, alist ) mw->removeAction( a );
907 // collect all registered menus by group id
908 QMap<int, NodeList> idMap;
909 for ( NodeList::iterator it2 = node->children.begin(); it2 != node->children.end(); ++it2 )
911 NodeList& lst = idMap[(*it2)->group];
912 int idx = (*it2)->idx;
913 if ( idx < 0 || idx >= (int)lst.count() )
916 lst.insert( idx, *it2 );
919 QIntList groups = idMap.keys();
922 groups.removeAll( -1 );
925 // rebuild menu: 1. add all registered actions
926 for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
928 if ( !idMap.contains( *gIt ) )
931 const NodeList& lst = idMap[*gIt];
932 for ( NodeList::const_iterator iter = lst.begin(); iter != lst.end(); ++iter )
934 MenuNode* node = *iter;
935 if ( !node ) continue;
938 updateMenu( node, rec, false );
940 MenuNode* par = node->parent;
941 if ( !isVisible( node->id, par ? par->id : -1 ) )
945 QAction* a = itemAction( node->id );
949 a = menuAction( node->id );
953 if ( !isMenu || !a->menu()->isEmpty() || node->emptyEnabled > 0 )
958 // rebuild menu: 2. insert back all foreign actions
959 for( formapit = foreign.begin(); formapit != foreign.end(); ++formapit ) {
960 preva = formapit.key();
961 foreach( a, formapit.value() )
962 mw->insertAction( preva, a );
965 // remove extra separators
966 simplifySeparators( mw );
968 // update parent menu if necessary
969 if ( updParent && node->parent && filled != checkWidget( mw ) )
970 updateMenu( node->parent, false );
974 \brief Internal update.
976 Customizes the menu update processing.
978 void QtxActionMenuMgr::internalUpdate()
980 if ( !isUpdatesEnabled() )
988 \brief Check if action belongs to the menu manager
990 \param a action being checked
991 \param node parent menu node
992 \return \c true if action belongs to the menu \a node
994 bool QtxActionMenuMgr::ownAction( QAction* a, MenuNode* node ) const
996 for ( NodeList::const_iterator iter = node->children.begin(); iter != node->children.end(); ++iter )
998 QAction* mya = itemAction( (*iter)->id );
1000 mya = menuAction( (*iter)->id );
1001 if ( mya && mya == a )
1008 \brief Check if menu widget has any actions.
1009 \param wid widget to be checked
1010 \return \c true if widget contains action(s)
1012 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
1017 return !wid->actions().isEmpty();
1021 \brief Get menu widget for the given \a node.
1022 \param node menu node
1023 \return popup menu or main menu corresponding to the menu node
1024 (or 0 if it is not found)
1026 QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node ) const
1028 if ( !node || node == myRoot )
1031 if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
1034 return myMenus[node->id]->menu();
1038 \brief Remove extra separators from menu widget.
1039 \param wid menu widget to be processed
1041 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
1043 Qtx::simplifySeparators( wid, false );
1047 \brief Remove special symbols (&) from string to get clear menu title.
1048 \param txt string to be processed
1051 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
1055 for ( int i = 0; i < (int)res.length(); i++ )
1057 if ( res.at( i ) == '&' )
1058 res.remove( i--, 1 );
1065 \brief Create and inserts menu item recursively.
1066 \param lst list of menu names
1067 \param pId parent menu item ID
1068 \return created menu item ID (last in the chain)
1070 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
1072 if ( lst.isEmpty() )
1075 QStringList sl( lst );
1077 QString title = sl.last().trimmed();
1080 int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
1082 return insert( title, parentId, -1 );
1086 \brief Load actions description from the file.
1087 \param fname file name
1088 \param r action reader
1089 \return \c true on success and \c false on error
1091 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
1093 MenuCreator cr( &r, this );
1094 return r.read( fname, cr );
1098 \brief Check if the parent menu contains menu item with given \a title.
1099 \param title menu title
1100 \param pid parent menu item ID
1101 \return \c true if parent menu item contains such child item
1103 bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid, const bool rec ) const
1105 return (bool)find( title, pid, rec );
1109 \brief Check if the parent menu contains menu item with given \a id.
1110 \param id menu item ID
1111 \param pid parent menu item ID
1112 \return \c true if parent menu item contains such child item
1114 bool QtxActionMenuMgr::containsMenu( const int id, const int pid, const bool rec ) const
1116 return (bool)find( id, pid, rec );
1120 \brief Get menu by the specified identifier.
1121 \param id menu item ID
1122 \return menu pointer or 0 if menu is not found
1124 QMenu* QtxActionMenuMgr::findMenu( const int id ) const
1127 QAction* a = menuAction( id );
1134 \brief Get menu by the title.
1135 \param title menu text
1136 \param pid parent menu item ID (to start search)
1137 \param rec if \c true, perform recursive update
1138 \return menu pointer or 0 if menu is not found
1140 QMenu* QtxActionMenuMgr::findMenu( const QString& title, const int pid, const bool rec ) const
1143 MenuNode* node = find( title, pid, rec );
1146 QAction* a = menuAction( node->id );
1154 \brief Check if empty menu is enabled
1155 \param id menu item ID
1156 \return \c true if empty menu is enabled
1158 bool QtxActionMenuMgr::isEmptyEnabled( const int id ) const
1160 MenuNode* node = find( id );
1161 if ( node && menuAction( id ) )
1162 return node->emptyEnabled > 0;
1168 \brief Enable/disable empty menu
1169 \param id menu item ID
1170 \param enable if \c true, empty menu will be enabled, otherwise empty menu will be disabled
1172 void QtxActionMenuMgr::setEmptyEnabled( const int id, const bool enable )
1174 MenuNode* node = find( id );
1175 if ( node && menuAction( id ) ) {
1176 int old = node->emptyEnabled;
1177 node->emptyEnabled += enable ? 1 : -1;
1178 if ( ( old <= 0 && enable ) || ( old > 0 && !enable ) ) // update menu only if enabled state has been changed
1179 updateMenu( node, true, true );
1184 \brief Perform delayed menu update.
1185 \param id menu item ID
1186 \param rec if \c true, perform recursive update
1188 void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec )
1191 if ( myUpdateIds.contains( id ) )
1192 isRec = isRec || myUpdateIds[ id ];
1193 myUpdateIds.insert( id, isRec );
1195 QtxActionMgr::triggerUpdate();
1199 \brief Called when delayed content update is performed.
1201 Customizes the content update operation.
1203 void QtxActionMenuMgr::updateContent()
1205 // Warning: For correct updating it is necessary to update the most enclosed submenu in first turn
1206 // because not updated empty submenu will be skipped. Now the submenus are iterated in
1207 // ascending order according to their identifiers. For a submenus with automatically generated
1208 // identifiers this will work correctly since the uppermost submenus have the biggest number
1209 // (identifiers are generated by decrementing 1 starting from -1). In general, if any submenu
1210 // have positive identifiers this method might not work correctly. In this case it would be
1211 // necessary to improve this method and to add preliminary sorting a submenus by depth of an
1213 for ( QMap<int, bool>::const_iterator it = myUpdateIds.constBegin(); it != myUpdateIds.constEnd(); ++it )
1215 MenuNode* node = it.key() == -1 ? myRoot : find( it.key() );
1217 updateMenu( node, it.value() );
1219 myUpdateIds.clear();
1223 \class QtxActionMenuMgr::MenuCreator
1224 \brief Menu actions creator.
1226 Used by Reader to create actions by reading descriptions from the file
1227 and fill in the action manager with the actions.
1232 \param r menu actions reader
1233 \param mgr menu manager
1235 QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r, QtxActionMenuMgr* mgr )
1236 : QtxActionMgr::Creator( r ),
1244 QtxActionMenuMgr::MenuCreator::~MenuCreator()
1249 \brief Create and append to the action manager a new action.
1250 \param tag item tag name
1251 \param subMenu \c true if this item is submenu
1252 \param attr attributes map
1253 \param pId parent action ID
1254 \return menu action ID
1256 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
1257 const ItemAttributes& attr, const int pId )
1259 if( !myMgr || !reader() )
1262 QString label = reader()->option( "label", "label" ),
1263 id = reader()->option( "id", "id" ),
1264 pos = reader()->option( "pos", "pos" ),
1265 group = reader()->option( "group", "group" ),
1266 tooltip = reader()->option( "tooltip", "tooltip" ),
1267 sep = reader()->option( "separator", "separator" ),
1268 accel = reader()->option( "accel", "accel" ),
1269 icon = reader()->option( "icon", "icon" ),
1270 toggle = reader()->option( "toggle", "toggle" );
1272 int res = -1, actId = intValue( attr, id, -1 );
1275 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1277 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
1282 QString name = strValue( attr, icon );
1283 if( !name.isEmpty() && loadPixmap( name, pix ) )
1286 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
1287 strValue( attr, label ),
1288 QKeySequence( strValue( attr, accel ) ),
1290 newAct->setToolTip( strValue( attr, tooltip ) );
1291 QString toggleact = strValue( attr, toggle );
1292 newAct->setCheckable( !toggleact.isEmpty() );
1293 newAct->setChecked( toggleact.toLower() == "true" );
1296 int aid = myMgr->registerAction( newAct, actId );
1297 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );