1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/
19 // File: QtxActionMenuMgr.cxx
20 // Author: Alexander SOLOVYEV, Sergey TELKOV
22 #include "QtxActionMenuMgr.h"
24 #include "QtxAction.h"
28 #include <qpopupmenu.h>
29 #include <qwidgetlist.h>
30 #include <qobjectlist.h>
31 #include <qmainwindow.h>
36 Class: QtxActionMenuMgr::MenuAction
40 class QtxActionMenuMgr::MenuAction : public QtxAction
43 MenuAction( const QString&, const QString&, QObject*, const bool = false );
44 virtual ~MenuAction();
46 virtual bool addTo( QWidget* );
48 virtual bool removeFrom( QWidget* );
50 QPopupMenu* popup() const;
58 QtxActionMenuMgr::MenuAction::MenuAction( const QString& text,
59 const QString& menuText,
61 const bool allowEmpty )
62 : QtxAction( text, menuText, 0, parent ),
65 myEmptyEnabled( allowEmpty )
67 myPopup = new QPopupMenu();
70 QtxActionMenuMgr::MenuAction::~MenuAction()
75 bool QtxActionMenuMgr::MenuAction::addTo( QWidget* w )
77 if ( myId != -1 || !w )
80 if ( !w->inherits( "QPopupMenu" ) && !w->inherits( "QMenuBar" ) )
86 if ( !myEmptyEnabled && !myPopup->count() )
89 if ( w->inherits( "QPopupMenu" ) && QAction::addTo( w ) )
91 QPopupMenu* pm = (QPopupMenu*)w;
92 myId = pm->idAt( pm->count() - 1 );
93 setPopup( pm, myId, myPopup );
95 else if ( w->inherits( "QMenuBar" ) )
97 QMenuBar* mb = (QMenuBar*)w;
98 myId = iconSet().isNull() ? mb->insertItem( menuText(), myPopup ) :
99 mb->insertItem( iconSet(), menuText(), myPopup );
100 mb->setItemEnabled( myId, isEnabled() );
108 bool QtxActionMenuMgr::MenuAction::removeFrom( QWidget* w )
110 if ( w->inherits( "QPopupMenu" ) && QAction::removeFrom( w ) )
112 else if ( w->inherits( "QMenuBar" ) )
114 QMenuBar* mb = (QMenuBar*)w;
115 mb->removeItem( myId );
122 QPopupMenu* QtxActionMenuMgr::MenuAction::popup() const
128 Class: QtxActionMenuMgr
133 QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p )
135 myMenu( p ? p->menuBar() : 0 )
141 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
142 if ( myMenu->inherits( "QMenuBar" ) )
143 connect( myMenu, SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) );
147 QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p )
155 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
158 QtxActionMenuMgr::~QtxActionMenuMgr()
160 for ( NodeListIterator it( myRoot.children ); it.current() && myMenu; ++it )
162 QAction* a = itemAction( it.current()->id );
164 a = menuAction( it.current()->id );
167 a->removeFrom( myMenu );
170 for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
174 bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const
176 MenuNode* node = find( actId, place );
177 return node && node->visible;
180 void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v )
182 MenuNode* node = find( actId, place );
187 int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx )
189 return insert( id, QStringList::split( "|", menus ), group, idx );
192 int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx )
194 return insert( a, QStringList::split( "|", menus ), group, idx );
197 int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx )
199 int pId = createMenu( menus, -1 );
203 return insert( id, pId, group, idx );
206 int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx )
208 int pId = createMenu( menus, -1 );
212 return insert( a, pId, group, idx );
215 int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx )
220 MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
224 MenuNode* node = new MenuNode( pNode );
229 pNode->children.append( node );
231 updateMenu( pNode, false );
236 int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx )
238 return insert( registerAction( a ), pId, group, idx );
241 int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int id, const int idx, const bool allowEmpty )
243 MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
247 MenuNode* eNode = id == -1 ? 0 : find( id );
250 for ( NodeListIterator it( pNode->children ); it.current() && fid == -1; ++it )
252 if ( myMenus.contains( it.current()->id ) &&
253 clearTitle( myMenus[it.current()->id]->menuText() ) == clearTitle( title ) )
254 fid = it.current()->id;
260 MenuAction* ma = new MenuAction( clearTitle( title ), title, this, allowEmpty );
261 connect( ma->popup(), SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) );
263 MenuNode* node = new MenuNode( pNode );
266 node->id = myMenus.insert( (id == -1 || eNode ) ? generateId() : id, ma ).key();
268 pNode->children.append( node );
270 updateMenu( pNode, false );
275 int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx, const bool allowEmpty )
277 return insert( title, QStringList::split( "|", menus ), group, id, idx, allowEmpty );
280 int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx, const bool allowEmpty )
282 int pId = createMenu( menus, -1 );
283 return insert( title, pId, group, id, idx, allowEmpty );
286 int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id, const bool allowEmpty )
288 return insert( title, pId, group, id, allowEmpty );
291 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
293 return insert( id, pId, group );
296 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
298 return insert( a, pId, group );
301 int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id, const bool allowEmpty )
303 return insert( title, pId, group, id, 0, allowEmpty );
306 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
308 return insert( id, pId, group, 0 );
311 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
313 return insert( a, pId, group, 0 );
316 void QtxActionMenuMgr::remove( const int id )
322 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
324 MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
329 for ( NodeListIterator it( pNode->children ); it.current(); ++it )
331 if ( it.current()->id == id && ( it.current()->group == group || group == -1 ) )
332 delNodes.append( it.current() );
335 for ( NodeListIterator itr( delNodes ); itr.current(); ++itr )
336 pNode->children.remove( itr.current() );
338 updateMenu( pNode, false );
341 void QtxActionMenuMgr::show( const int id )
343 setShown( id, true );
346 void QtxActionMenuMgr::hide( const int id )
348 setShown( id, false );
351 bool QtxActionMenuMgr::isShown( const int id ) const
354 MenuNode* node = find( id );
360 void QtxActionMenuMgr::setShown( const int id, const bool on )
365 QMap<MenuNode*, int> updMap;
366 for ( NodeListIterator it( aNodes ); it.current(); ++it )
368 if ( it.current()->visible != on )
370 it.current()->visible = on;
371 updMap.insert( it.current()->parent, 0 );
375 for ( QMap<MenuNode*, int>::ConstIterator itr = updMap.begin(); itr != updMap.end(); ++itr )
376 updateMenu( itr.key(), false );
379 void QtxActionMenuMgr::onDestroyed( QObject* obj )
385 void QtxActionMenuMgr::onHighlighted( int id )
387 const QObject* snd = sender();
389 if ( myMenu && snd == myMenu )
392 for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr ) {
393 if ( itr.data()->popup() && itr.data()->popup() == snd )
398 realId = findId( id, pid );
399 if ( realId != -1 ) {
400 bool updatesEnabled = isUpdatesEnabled();
401 setUpdatesEnabled( false );
402 emit menuHighlighted( pid, realId );
403 setUpdatesEnabled( updatesEnabled );
404 updateMenu( find( realId ) );
409 void QtxActionMenuMgr::setWidget( QWidget* mw )
415 disconnect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
420 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
423 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int actId, const int pId, const bool rec ) const
425 return find( actId, find( pId ), rec );
428 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const
431 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
432 for ( NodeListIterator it( start->children ); it.current() && !node; ++it )
434 if ( it.current()->id == id )
437 node = find( id, it.current(), rec );
442 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
444 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
445 for ( NodeListIterator it( start->children ); it.current(); ++it )
447 if ( it.current()->id == id )
448 lst.prepend( it.current() );
450 find( id, lst, it.current() );
452 return !lst.isEmpty();
455 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const
457 return find( title, find( pId ), rec );
460 bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const
462 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
463 for ( NodeListIterator it( start->children ); it.current(); ++it )
465 QAction* a = itemAction( it.current()->id );
467 a = menuAction( it.current()->id );
468 if ( a && clearTitle( a->menuText() ) == clearTitle( title ) )
469 lst.prepend( it.current() );
471 find( title, lst, it.current() );
473 return !lst.isEmpty();
476 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const
479 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
480 for ( NodeListIterator it( start->children ); it.current() && !node; ++it )
482 QAction* a = itemAction( it.current()->id );
484 a = menuAction( it.current()->id );
485 if ( a && clearTitle( a->menuText() ) == clearTitle( title ) )
488 node = find( title, it.current(), rec );
493 int QtxActionMenuMgr::findId( const int id, const int pid ) const
495 MenuNode* start = pid != -1 ? find( pid ) : (MenuNode*)&myRoot;
497 for ( NodeListIterator it( start->children ); it.current(); ++it ) {
498 if ( it.current()->id == id ) return id;
504 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
506 MenuNode* start = startNode ? startNode : &myRoot;
507 for ( NodeListIterator it( start->children ); it.current(); ++it )
509 if ( it.current()->id == id )
510 start->children.remove( it.current() );
512 removeMenu( id, it.current() );
516 QAction* QtxActionMenuMgr::itemAction( const int id ) const
521 QtxActionMenuMgr::MenuAction* QtxActionMenuMgr::menuAction( const int id ) const
525 if ( myMenus.contains( id ) )
531 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
533 if ( !isUpdatesEnabled() )
536 MenuNode* node = startNode ? startNode : &myRoot;
538 QWidget* mw = menuWidget( node );
542 bool filled = checkWidget( mw );
544 for ( NodeListIterator it1( node->children ); it1.current(); ++it1 )
546 QAction* a = itemAction( it1.current()->id );
548 a = menuAction( it1.current()->id );
554 if ( mw->inherits( "QMenuBar" ) )
555 ((QMenuBar*)mw)->clear();
556 else if ( mw->inherits( "QPopupMenu" ) )
557 ((QPopupMenu*)mw)->clear();
559 QMap<int, NodeList> idMap;
560 for ( NodeListIterator it2( node->children ); it2.current(); ++it2 )
562 NodeList& lst = idMap[it2.current()->group];
563 int idx = it2.current()->idx;
564 if ( idx < 0 || idx >= lst.count() )
565 lst.append( it2.current() );
567 lst.insert( idx, it2.current() );
570 QIntList groups = idMap.keys();
576 for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
578 if ( !idMap.contains( *gIt ) )
581 const NodeList& lst = idMap[*gIt];
582 for ( NodeListIterator iter( lst ); iter.current(); ++iter )
584 MenuNode* par = iter.current()->parent;
585 if ( !isVisible( iter.current()->id, par ? par->id : -1 ) )
589 updateMenu( iter.current(), rec, false );
591 QAction* a = itemAction( iter.current()->id );
593 a = menuAction( iter.current()->id );
595 QMenuData* md = dynamic_cast<QMenuData*>( mw );
597 if ( md ) cnt = md->count();
599 if ( md && md->count() - cnt == 1 ) { //&& iter.current()->id > 0
600 int lid = md->idAt( cnt );
601 QMenuItem* mi = md->findItem( lid );
602 if ( mi && !mi->isSeparator() )
603 md->setId( cnt, iter.current()->id );
609 simplifySeparators( mw );
611 if ( updParent && node->parent && filled != checkWidget( mw ) )
612 updateMenu( node->parent, false );
615 void QtxActionMenuMgr::internalUpdate()
617 if ( isUpdatesEnabled() )
621 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
627 if ( wid->inherits( "QPopupMenu" ) )
628 md = (QPopupMenu*)wid;
629 else if ( wid->inherits( "QMenuBar" ) )
635 QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node) const
637 if ( !node || node == &myRoot )
640 if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
643 return myMenus[node->id]->popup();
646 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
648 if ( wid && wid->inherits( "QPopupMenu" ) )
649 Qtx::simplifySeparators( (QPopupMenu*)wid, false );
652 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
656 for ( int i = 0; i < (int)res.length(); i++ )
658 if ( res.at( i ) == '&' )
659 res.remove( i--, 1 );
665 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
670 QStringList sl( lst );
672 QString title = sl.last().stripWhiteSpace();
673 sl.remove( sl.fromLast() );
675 int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
677 return insert( title, parentId, -1 );
680 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
682 MenuCreator cr( &r, this );
683 return r.read( fname, cr );
686 bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid ) const
688 return (bool)find( title, pid, false );
691 bool QtxActionMenuMgr::containsMenu( const int id, const int pid ) const
693 return (bool)find( id, pid, false );
697 Class: QtxActionMenuMgr::MenuCreator
701 QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r,
702 QtxActionMenuMgr* mgr )
703 : QtxActionMgr::Creator( r ),
708 QtxActionMenuMgr::MenuCreator::~MenuCreator()
712 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
713 const ItemAttributes& attr, const int pId )
715 if( !myMgr || !reader() )
718 QString label = reader()->option( "label", "label" ),
719 id = reader()->option( "id", "id" ),
720 pos = reader()->option( "pos", "pos" ),
721 group = reader()->option( "group", "group" ),
722 tooltip = reader()->option( "tooltip", "tooltip" ),
723 sep = reader()->option( "separator", "separator" ),
724 accel = reader()->option( "accel", "accel" ),
725 icon = reader()->option( "icon", "icon" ),
726 toggle = reader()->option( "toggle", "toggle" );
728 int res = -1, actId = intValue( attr, id, -1 );
731 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
733 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
736 QPixmap pix; QIconSet set;
737 QString name = strValue( attr, icon );
738 if( !name.isEmpty() && loadPixmap( name, pix ) )
739 set = QIconSet( pix );
741 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
742 strValue( attr, label ),
743 QKeySequence( strValue( attr, accel ) ),
745 newAct->setToolTip( strValue( attr, tooltip ) );
746 QString toggleact = strValue( attr, toggle );
747 newAct->setToggleAction( !toggleact.isEmpty() );
748 newAct->setOn( toggleact.lower()=="true" );
751 int aid = myMgr->registerAction( newAct, actId );
752 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );