1 // File: QtxActionMenuMgr.cxx
2 // Author: Alexander SOLOVYEV, Sergey TELKOV
4 #include "QtxActionMenuMgr.h"
10 #include <qpopupmenu.h>
11 #include <qwidgetlist.h>
12 #include <qobjectlist.h>
13 #include <qmainwindow.h>
18 Class: QtxActionMenuMgr::MenuAction
22 class QtxActionMenuMgr::MenuAction : public QtxAction
25 MenuAction( const QString&, const QString&, QObject* );
26 virtual ~MenuAction();
28 virtual bool addTo( QWidget* );
30 virtual bool removeFrom( QWidget* );
32 QPopupMenu* popup() const;
39 QtxActionMenuMgr::MenuAction::MenuAction( const QString& text, const QString& menuText, QObject* parent )
40 : QtxAction( text, menuText, 0, parent ),
44 myPopup = new QPopupMenu();
47 QtxActionMenuMgr::MenuAction::~MenuAction()
52 bool QtxActionMenuMgr::MenuAction::addTo( QWidget* w )
54 if ( myId != -1 || !w )
57 if ( !w->inherits( "QPopupMenu" ) && !w->inherits( "QMenuBar" ) )
60 if ( w->inherits( "QPopupMenu" ) && QAction::addTo( w ) )
62 QPopupMenu* pm = (QPopupMenu*)w;
63 myId = pm->idAt( pm->count() - 1 );
64 setPopup( pm, myId, myPopup );
66 else if ( w->inherits( "QMenuBar" ) )
68 QMenuBar* mb = (QMenuBar*)w;
69 myId = iconSet().isNull() ? mb->insertItem( menuText(), myPopup ) :
70 mb->insertItem( iconSet(), menuText(), myPopup );
71 mb->setItemEnabled( myId, isEnabled() );
79 bool QtxActionMenuMgr::MenuAction::removeFrom( QWidget* w )
81 if ( w->inherits( "QPopupMenu" ) && QAction::removeFrom( w ) )
83 else if ( w->inherits( "QMenuBar" ) )
85 QMenuBar* mb = (QMenuBar*)w;
86 mb->removeItem( myId );
93 QPopupMenu* QtxActionMenuMgr::MenuAction::popup() const
99 Class: QtxActionMenuMgr
104 QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p )
106 myMenu( p ? p->menuBar() : 0 )
112 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
115 QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p )
123 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
126 QtxActionMenuMgr::~QtxActionMenuMgr()
128 for ( NodeListIterator it( myRoot.children ); it.current(); ++it )
130 QAction* a = itemAction( it.current()->id );
132 a = menuAction( it.current()->id );
135 a->removeFrom( myMenu );
138 for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr )
142 bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const
144 MenuNode* node = find( actId, place );
145 return node && node->visible;
148 void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v )
150 MenuNode* node = find( actId, place );
155 int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx )
157 return insert( id, QStringList::split( "|", menus ), group, idx );
160 int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx )
162 return insert( a, QStringList::split( "|", menus ), group, idx );
165 int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx )
167 int pId = createMenu( menus, -1 );
171 return insert( id, pId, group, idx );
174 int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx )
176 int pId = createMenu( menus, -1 );
180 return insert( a, pId, group, idx );
183 int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx )
188 MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
192 MenuNode* node = new MenuNode( pNode );
196 if ( idx < 0 || idx >= (int)pNode->children.count() )
197 pNode->children.append( node );
199 pNode->children.insert( idx, node );
201 updateMenu( pNode, false );
206 int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx )
208 return insert( registerAction( a ), pId, group, idx );
211 int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int idx )
213 MenuNode* pNode = pId == -1 ? &myRoot : find( pId );
218 for ( NodeListIterator it( pNode->children ); it.current() && id == -1; ++it )
220 if ( myMenus.contains( it.current()->id ) &&
221 clearTitle( myMenus[it.current()->id]->menuText() ) == clearTitle( title ) )
222 id = it.current()->id;
228 MenuAction* ma = new MenuAction( clearTitle( title ), title, this );
230 MenuNode* node = new MenuNode( pNode );
232 node->id = myMenus.insert( generateId(), ma ).key();
234 if ( idx < 0 || idx >= (int)pNode->children.count() )
235 pNode->children.append( node );
237 pNode->children.insert( idx, node );
239 updateMenu( pNode, false );
244 int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int idx )
246 return insert( title, QStringList::split( "|", menus ), group, idx );
249 int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int idx )
251 int pId = createMenu( menus, -1 );
252 return insert( title, pId, group, idx );
255 int QtxActionMenuMgr::append( const QString& title, const int pId, const int group )
257 return insert( title, pId, group );
260 int QtxActionMenuMgr::append( const int id, const int pId, const int group )
262 return insert( id, pId, group );
265 int QtxActionMenuMgr::append( QAction* a, const int pId, const int group )
267 return insert( a, pId, group );
270 int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group )
272 return insert( title, pId, group, 0 );
275 int QtxActionMenuMgr::prepend( const int id, const int pId, const int group )
277 return insert( id, pId, group, 0 );
280 int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group )
282 return insert( a, pId, group, 0 );
285 void QtxActionMenuMgr::remove( const int id )
291 void QtxActionMenuMgr::remove( const int id, const int pId, const int group )
293 MenuNode* pNode = find( pId );
298 for ( NodeListIterator it( pNode->children ); it.current(); ++it )
300 if ( it.current()->id == id && ( it.current()->group == group || group == -1 ) )
301 delNodes.append( it.current() );
304 for ( NodeListIterator itr( delNodes ); itr.current(); ++itr )
305 pNode->children.remove( itr.current() );
307 updateMenu( pNode, false );
310 void QtxActionMenuMgr::show( const int id )
312 setShown( id, true );
315 void QtxActionMenuMgr::hide( const int id )
317 setShown( id, false );
320 bool QtxActionMenuMgr::isShown( const int id ) const
323 MenuNode* node = find( id );
329 void QtxActionMenuMgr::setShown( const int id, const bool on )
334 QMap<MenuNode*, int> updMap;
335 for ( NodeListIterator it( aNodes ); it.current(); ++it )
337 if ( it.current()->visible != on )
339 it.current()->visible = on;
340 updMap.insert( it.current()->parent, 0 );
344 for ( QMap<MenuNode*, int>::ConstIterator itr = updMap.begin(); itr != updMap.end(); ++itr )
345 updateMenu( itr.key(), false );
348 void QtxActionMenuMgr::onDestroyed( QObject* obj )
354 void QtxActionMenuMgr::setWidget( QWidget* mw )
360 disconnect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
365 connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
368 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int actId, const int pId ) const
370 return find( actId, find( pId ) );
373 QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode ) const
376 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
377 for ( NodeListIterator it( start->children ); it.current() && !node; ++it )
379 if ( it.current()->id == id )
382 node = find( id, it.current() );
387 bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const
389 MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot;
390 for ( NodeListIterator it( start->children ); it.current(); ++it )
392 if ( it.current()->id == id )
393 lst.prepend( it.current() );
395 find( id, lst, it.current() );
397 return !lst.isEmpty();
400 void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode )
402 MenuNode* start = startNode ? startNode : &myRoot;
403 for ( NodeListIterator it( start->children ); it.current(); ++it )
405 if ( it.current()->id == id )
406 start->children.remove( it.current() );
408 removeMenu( id, it.current() );
412 QAction* QtxActionMenuMgr::itemAction( const int id ) const
417 QtxActionMenuMgr::MenuAction* QtxActionMenuMgr::menuAction( const int id ) const
421 if ( myMenus.contains( id ) )
427 void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent )
429 if ( !isUpdatesEnabled() )
432 MenuNode* node = startNode ? startNode : &myRoot;
434 QWidget* mw = menuWidget( node );
438 bool filled = checkWidget( mw );
440 for ( NodeListIterator it1( node->children ); it1.current(); ++it1 )
442 QAction* a = itemAction( it1.current()->id );
444 a = menuAction( it1.current()->id );
450 if ( node != &myRoot )
452 if ( mw->inherits( "QMenuBar" ) )
453 ((QMenuBar*)mw)->clear();
454 else if ( mw->inherits( "QPopupMenu" ) )
455 ((QPopupMenu*)mw)->clear();
458 QMap<int, NodeList> idMap;
459 for ( NodeListIterator it2( node->children ); it2.current(); ++it2 )
461 MenuNode* par = it2.current()->parent;
462 if ( isVisible( it2.current()->id, par ? par->id : -1 ) )
464 NodeList& lst = idMap[it2.current()->group];
465 lst.append( it2.current() );
469 QIntList groups = idMap.keys();
475 for ( QIntList::const_iterator gIt = groups.begin(); gIt != groups.end(); ++gIt )
477 if ( !idMap.contains( *gIt ) )
480 const NodeList& lst = idMap[*gIt];
481 for ( NodeListIterator iter( lst ); iter.current(); ++iter )
484 updateMenu( iter.current(), rec, false );
486 QAction* a = itemAction( iter.current()->id );
491 MenuAction* ma = menuAction( iter.current()->id );
492 if ( ma && ma->popup() && ma->popup()->count() )
498 simplifySeparators( mw );
500 if ( updParent && node->parent && filled != checkWidget( mw ) )
501 updateMenu( node->parent, false );
504 void QtxActionMenuMgr::internalUpdate()
506 if ( isUpdatesEnabled() )
510 bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const
516 if ( wid->inherits( "QPopupMenu" ) )
517 md = (QPopupMenu*)wid;
518 else if ( wid->inherits( "QMenuBar" ) )
524 QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node) const
526 if ( !node || node == &myRoot )
529 if ( !myMenus.contains( node->id ) || !myMenus[node->id] )
532 return myMenus[node->id]->popup();
535 void QtxActionMenuMgr::simplifySeparators( QWidget* wid )
537 if ( wid && wid->inherits( "QPopupMenu" ) )
538 Qtx::simplifySeparators( (QPopupMenu*)wid, false );
541 QString QtxActionMenuMgr::clearTitle( const QString& txt ) const
545 for ( int i = 0; i < (int)res.length(); i++ )
547 if ( res.at( i ) == '&' )
548 res.remove( i--, 1 );
554 int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId )
559 QStringList sl( lst );
561 QString title = sl.last().stripWhiteSpace();
562 sl.remove( sl.fromLast() );
564 int parentId = sl.isEmpty() ? pId : createMenu( sl, pId );
566 return insert( title, parentId, -1 );
569 bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r )
571 MenuCreator cr( &r, this );
572 return r.read( fname, cr );
577 Class: QtxActionMenuMgr::MenuCreator
581 QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r,
582 QtxActionMenuMgr* mgr )
583 : QtxActionMgr::Creator( r ),
588 QtxActionMenuMgr::MenuCreator::~MenuCreator()
592 int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu,
593 const ItemAttributes& attr, const int pId )
595 if( !myMgr || !reader() )
598 QString label = reader()->option( "label", "label" ),
599 id = reader()->option( "id", "id" ),
600 pos = reader()->option( "pos", "pos" ),
601 group = reader()->option( "group", "group" ),
602 tooltip = reader()->option( "tooltip", "tooltip" ),
603 sep = reader()->option( "separator", "separator" ),
604 accel = reader()->option( "accel", "accel" ),
605 icon = reader()->option( "icon", "icon" ),
606 toggle = reader()->option( "toggle", "toggle" );
608 int res = -1, actId = intValue( attr, id, -1 );
611 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
613 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
616 QPixmap pix; QIconSet set;
617 QString name = strValue( attr, icon );
618 if( !name.isEmpty() && loadPixmap( name, pix ) )
619 set = QIconSet( pix );
621 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set,
622 strValue( attr, label ),
623 QKeySequence( strValue( attr, accel ) ),
625 newAct->setToolTip( strValue( attr, tooltip ) );
626 QString toggleact = strValue( attr, toggle );
627 newAct->setToggleAction( !toggleact.isEmpty() );
628 newAct->setOn( toggleact.lower()=="true" );
631 int aid = myMgr->registerAction( newAct, actId );
632 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );