1 // Copyright (C) 2007-2015 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: QtxActionMgr.cxx
24 // Author: Alexander SOLOVYOV, Sergey TELKOV
27 #include "QtxActionMgr.h"
28 #include "QtxAction.h"
32 #include <QDomDocument>
34 #include <QCoreApplication>
37 typedef QList< QPointer<QAction> > qtx_actionlist;
38 static qtx_actionlist qtx_separator_actions;
41 \brief Clean all cashed separator actions.
44 void qtxSeparatorActionCleanup()
46 for ( qtx_actionlist::iterator it = qtx_separator_actions.begin(); it != qtx_separator_actions.end(); ++it )
54 \class QtxActionMgr::SeparatorAction
55 \brief Separator action class.
59 class QtxActionMgr::SeparatorAction : public QAction
62 SeparatorAction( QObject* = 0 );
63 virtual ~SeparatorAction();
69 \param parent parent object
71 QtxActionMgr::SeparatorAction::SeparatorAction( QObject* parent )
80 QtxActionMgr::SeparatorAction::~SeparatorAction()
86 \brief Manages a set of actions accessible by unique identifier.
88 Base class for menu, toolbar actions containers and popup menu creators.
90 Actions are registered in the manager with the registerAction() method
91 and unregistered from it with the unRegisterAction() method.
93 Functions action() and actionId() allow getting action by its identifier
94 and vice versa. Method contains() returns \c true if the action with
95 the specified identifier is already registered.
97 To get total number of the registered actions can be retrieved by
98 the method count(). Function isEmpty() returns \c true if manager does not
99 contains any actions. The list of all actions identifiers can be retrieved
100 with the idList() function.
102 The method separator() allows creating a separator action which can be
103 used in the menus or toolbars to separate logical groups of actions.
105 To enable/disable any action by its identifier, use setEnabled() method.
110 \param parent parent object
112 QtxActionMgr::QtxActionMgr( QObject* parent )
122 QtxActionMgr::~QtxActionMgr()
127 \brief Register an action in the internal map.
129 If \a userId is less than 0, the identifier for the action
130 is generated automatically. If action with given \a userId
131 is already registered, it will be re-registered.
133 \param a action to be registered
134 \param userId action ID
135 \return action ID (the same as userId or generated one)
136 \sa unRegisterAction()
138 int QtxActionMgr::registerAction( QAction* a, const int userId )
143 int theId = userId < 0 ? generateId() : userId;
145 if ( contains( theId ) )
146 unRegisterAction( theId );
148 int cur = actionId( a );
154 unRegisterAction( cur );
157 myActions.insert( theId, a );
163 \brief Unregister action from internal map.
167 void QtxActionMgr::unRegisterAction( const int id )
170 myActions.remove( id );
174 \brief Get action by specified identifier.
176 \return action (or 0 if \a id is invalid)
179 QAction* QtxActionMgr::action( const int id ) const
181 if ( contains( id ) )
182 return myActions[ id ];
188 \brief Get action identifier.
190 \return action ID (or -1 if action is not found)
193 int QtxActionMgr::actionId( const QAction* a ) const
199 for ( ActionMap::ConstIterator it = myActions.begin(); it != myActions.end() && theId == -1; ++it )
201 if ( it.value() == a )
209 \brief Check if an action with given \a id is registered in the action manager.
211 \return \c true if internal map contains action with such identifier
213 bool QtxActionMgr::contains( const int id ) const
215 return myActions.contains( id );
219 \brief Get total number of registered actions.
220 \return number of actions in the internal map
223 int QtxActionMgr::count() const
225 return myActions.count();
229 \brief Check if there are no actions registered in the action manager.
230 \return \c true if internal map is empty
233 bool QtxActionMgr::isEmpty() const
235 return myActions.isEmpty();
239 \brief Get all registered actions identifiers.
240 \return list of actions identifiers
242 QIntList QtxActionMgr::idList() const
244 return myActions.keys();
248 \brief Check if update is enabled.
249 \return \c true if update is enabled
250 \sa setUpdatesEnabled(), update()
252 bool QtxActionMgr::isUpdatesEnabled() const
258 \brief Enable/disable update operation.
260 \sa isUpdatesEnabled(), update()
262 void QtxActionMgr::setUpdatesEnabled( const bool upd )
268 \brief Check if an action with \a actId identifier is visible to
269 the parent action with \a place identifier.
271 This method can be redefined in subclasses.
272 Base implementatin always returns \c true.
274 \param actId action ID
275 \param place some parent action ID
276 \return \c true if an action is visible to the parent
279 bool QtxActionMgr::isVisible( const int /*actId*/, const int /*place*/ ) const
285 \brief Set action's visibility flag.
287 This method can be redefined in subclasses.
288 Base implementatin does nothing.
290 \param actId action ID
291 \param place some parent action ID
292 \param v new visibility state
295 void QtxActionMgr::setVisible( const int /*actId*/, const int /*place*/, const bool /*v*/ )
300 \brief Update actions.
302 Calls virtual function internalUpdate to update the contents.
303 Does nothing if update is disabled.
305 \sa setUpdatesEnabled(), isUpdatesEnabled(), internalUpdate()
307 void QtxActionMgr::update()
309 if ( !isUpdatesEnabled() )
318 \brief Internal update.
320 This method is called by update() function and can be redefined
321 in subclasses to customize update operation. Base implementation
324 void QtxActionMgr::internalUpdate()
329 \brief Generate unique action identifier.
332 int QtxActionMgr::generateId() const
339 \brief Check is action with given \a id is enabled.
341 \return \c true if action is enabled
343 bool QtxActionMgr::isEnabled( const int id ) const
345 QAction* a = action( id );
347 return a->isEnabled();
353 Enable/disable action with given \a id.
355 \param enable new state
357 void QtxActionMgr::setEnabled( const int id, const bool enable )
359 QAction* a = action( id );
361 a->setEnabled( enable );
365 \brief Create new separator action.
367 If \a own is \c true, then the caller is responsible for the action
368 destroying. If \a own is \c false, new separator action will be owned by the
369 action manager which will destroy it on application exit.
371 \param own ownership flag
372 \return new separator action
374 QAction* QtxActionMgr::separator( const bool own )
377 return new SeparatorAction();
379 if ( qtx_separator_actions.isEmpty() )
380 qAddPostRoutine( qtxSeparatorActionCleanup );
382 SeparatorAction* a = new SeparatorAction();
383 qtx_separator_actions.append( a );
389 \brief Perform delayed update.
391 Does nothing if update is disabled.
392 \sa isUpdatesEnabled(), setUpdatesEnabled(), update()
394 void QtxActionMgr::triggerUpdate()
396 if ( !isUpdatesEnabled() )
401 myUpdTimer = new QTimer( this );
402 myUpdTimer->setSingleShot( true );
403 connect( myUpdTimer, SIGNAL( timeout() ), this, SLOT( onUpdateContent() ) );
406 // add timer event to event list
407 myUpdTimer->start( 0 );
411 \brief Internal content update operation.
413 Called automatically by onUpdateContent() when the delayed update
414 is triggered. Base implementation does nothing.
416 \sa triggerUpdate(), onUpdateContent()
418 void QtxActionMgr::updateContent()
423 \brief Called when delayed update is performed (via timer event).
425 Calls virtual method updateContent() which can be redefined in the
426 subclasses to customize the content update operation.
428 void QtxActionMgr::onUpdateContent()
434 \class QtxActionMgr::Reader
435 \brief Generic actions description files reader class.
437 This class is used to read files of some format to create actions
438 and fill an action manager with the actions automatically.
444 QtxActionMgr::Reader::Reader()
451 QtxActionMgr::Reader::~Reader()
456 \brief Get the list of options.
459 QStringList QtxActionMgr::Reader::options() const
461 return myOptions.keys();
465 \brief Get option value.
467 If there is no such option the default value (\a def) is returned.
469 \param name option name
470 \param def default option value
473 QString QtxActionMgr::Reader::option( const QString& name, const QString& def ) const
475 if( myOptions.contains( name ) )
476 return myOptions[ name ];
482 \brief Set option value.
483 \param name option name
484 \param value new option value
486 void QtxActionMgr::Reader::setOption( const QString& name, const QString& value )
488 myOptions[ name ] = value;
492 \fn bool QtxActionMgr::Reader::read( const QString& fname, Creator& cr ) const
493 \brief Read the file and fill and action manager with actions
494 by using help actions creator.
496 This method should be redefined in the subclasses.
498 \param fname XML file name
499 \param cr actions creator
500 \return \c true on success and \c false in case of error
504 \class QtxActionMgr::XMLReader
505 \brief XML file reader.
507 This class is used to read files of XML format to create
508 actions and fill an action manager with actions automatically.
513 \param root root XML tag name
514 \param item menu item XML tag name
515 \param dir resources directory (containing icons, etc)
517 QtxActionMgr::XMLReader::XMLReader( const QString& root,
522 setOption( QString( "root_tag" ), root );
523 setOption( QString( "menu_item" ), item );
524 setOption( QString( "icons_dir" ), dir );
525 setOption( QString( "id" ), QString( "item-id" ) );
526 setOption( QString( "pos" ), QString( "pos-id" ) );
527 setOption( QString( "group" ), QString( "group-id" ) );
528 setOption( QString( "label" ), QString( "label-id" ) );
529 setOption( QString( "tooltip" ), QString( "tooltip-id" ) );
530 setOption( QString( "accel" ), QString( "accel-id" ) );
531 setOption( QString( "separator" ), QString( "separator" ) );
532 setOption( QString( "icon" ), QString( "icon-id" ) );
533 setOption( QString( "toggle" ), QString( "toggle-id" ) );
539 QtxActionMgr::XMLReader::~XMLReader()
544 \brief Read the file and fill and action manager with actions
545 by using actions creator.
546 \param fname XML file name
547 \param cr actions creator
548 \return \c true on success and \c false in case of error
550 bool QtxActionMgr::XMLReader::read( const QString& fname, Creator& cr ) const
557 if ( !file.open( QFile::ReadOnly ) )
562 res = doc.setContent( &file );
568 QString root = option( "root_tag" );
569 for( QDomNode cur = doc.documentElement(); !cur.isNull(); )
571 if( cur.isElement() && isNodeSimilar( cur, root ) )
573 else if( cur.hasChildNodes() )
575 cur = cur.firstChild();
579 while( !cur.isNull() && cur.nextSibling().isNull() )
580 cur = cur.parentNode();
582 cur = cur.nextSibling();
591 \brief Read XML mode and create an item if requied.
592 \param parent_node parent XML file node
593 \param parent_id parent action ID
594 \param cr actions creator
596 void QtxActionMgr::XMLReader::read( const QDomNode& parent_node,
600 if( parent_node.isNull() )
603 QStringList items = option( "menu_item" ).split( "|", QString::SkipEmptyParts );
605 const QDomNodeList& children = parent_node.childNodes();
606 for( int i=0, n=children.count(); i<n; i++ )
608 QDomNode node = children.item( i );
609 //QString n = node.nodeName();
610 if( node.isElement() /*&& node.hasAttributes()*/ &&
611 ( items.contains( node.nodeName() ) || node.nodeName()==option( "separator" ) ) )
613 QDomNamedNodeMap map = node.attributes();
614 ItemAttributes attrs;
616 for( int i=0, n=map.count(); i<n; i++ )
617 if( map.item( i ).isAttr() )
619 QDomAttr a = map.item( i ).toAttr();
620 attrs.insert( a.name(), a.value() );
623 int newId = cr.append( node.nodeName(), node.hasChildNodes(), attrs, parent_id );
624 if( node.hasChildNodes() )
625 read( node, newId, cr );
631 \brief Check node name correspondance to some pattern.
632 \param node XML file node
633 \param pattern node name pattern
634 \return \c true if node satisfies pattern
636 bool QtxActionMgr::XMLReader::isNodeSimilar( const QDomNode& node,
637 const QString& pattern ) const
639 if( node.nodeName()==pattern )
644 temp.setContent( pattern, true, &mes );
646 const QDomNamedNodeMap &temp_map = temp.documentElement().attributes(),
647 &cur_map = node.attributes();
648 bool ok = temp_map.count()>0;
649 for( int i=0, n=temp_map.count(); i<n && ok; i++ )
651 QDomAttr a = temp_map.item( i ).toAttr(),
652 b = cur_map.namedItem( a.name() ).toAttr();
653 ok = !b.isNull() && a.name()==b.name() && a.value()==b.value();
660 \class QtxActionMgr::Creator
661 \brief Generic actions creator class.
663 Used by Reader to create actions and fill in the action
664 manager with the actions.
668 \brief Get integer attribute value from the attribute map.
670 Returns default value (\a def) if the attribute is not found.
672 \param attrs attributes map
673 \param name attribute name
674 \param def default attribute value
675 \return attribute value
677 int QtxActionMgr::Creator::intValue( const ItemAttributes& attrs,
678 const QString& name, int def )
680 if( attrs.contains( name ) )
683 int res = attrs[ name ].toInt( &ok );
691 \brief Get string attribute value from the attribute map.
693 Returns default value (\a def) if the attribute is not found.
695 \param attrs attributes map
696 \param name attribute name
697 \param def default attribute value
698 \return attribute value
700 QString QtxActionMgr::Creator::strValue( const ItemAttributes& attrs,
704 if( attrs.contains( name ) )
705 return attrs[ name ];
712 \param r action reader
714 QtxActionMgr::Creator::Creator( QtxActionMgr::Reader* r )
722 QtxActionMgr::Creator::~Creator()
727 \brief Get actions reader.
728 \return actions reader
730 QtxActionMgr::Reader* QtxActionMgr::Creator::reader() const
736 \brief Connect action to some specific slot(s).
738 This method can be redefined in subclasses.
739 Base implementation does nothing.
743 void QtxActionMgr::Creator::connect( QAction* /*a*/ ) const
748 \brief Load pixmap from the file.
749 \param fname file name
750 \param pix used to return pixmap
751 \return \c true if pixmap is loaded successfully and \c false in case of error
753 bool QtxActionMgr::Creator::loadPixmap( const QString& fname, QPixmap& pix ) const
758 QStringList dirlist = reader()->option( "icons_dir", "." ).split( ";", QString::SkipEmptyParts );
759 QStringList::const_iterator anIt = dirlist.begin(),
760 aLast = dirlist.end();
762 for( ; anIt!=aLast && !res; anIt++ )
763 res = pix.load( Qtx::addSlash( *anIt ) + fname );
769 \fn int QtxActionMgr::Creator::append( const QString& tag,
771 const ItemAttributes& attr,
773 \brief Create (and probably append to the action manager) new action.
775 This method should be redefined in the subclasses.
777 \param tag item tag name
778 \param subMenu \c true if this item is submenu
779 \param attr attributes map
780 \param pId parent action ID
781 \return item (for example action) ID