1 // Copyright (C) 2007-2023 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 );
159 connect( a, SIGNAL( changed() ), this, SLOT( onActionChanged() ) );
165 \brief Unregister action from internal map.
169 void QtxActionMgr::unRegisterAction( const int id )
171 if ( contains( id ) ) {
172 disconnect( myActions[id], SIGNAL( changed() ),
173 this, SLOT( onActionChanged() ) );
174 myActions.remove( id );
179 \brief Get action by specified identifier.
181 \return action (or 0 if \a id is invalid)
184 QAction* QtxActionMgr::action( const int id ) const
186 if ( contains( id ) )
187 return myActions[ id ];
193 \brief Get action identifier.
195 \return action ID (or -1 if action is not found)
198 int QtxActionMgr::actionId( const QAction* a ) const
204 for ( ActionMap::ConstIterator it = myActions.begin(); it != myActions.end() && theId == -1; ++it )
206 if ( it.value() == a )
214 \brief Check if an action with given \a id is registered in the action manager.
216 \return \c true if internal map contains action with such identifier
218 bool QtxActionMgr::contains( const int id ) const
220 return myActions.contains( id );
224 \brief Get total number of registered actions.
225 \return number of actions in the internal map
228 int QtxActionMgr::count() const
230 return myActions.count();
234 \brief Check if there are no actions registered in the action manager.
235 \return \c true if internal map is empty
238 bool QtxActionMgr::isEmpty() const
240 return myActions.isEmpty();
244 \brief Get all registered actions identifiers.
245 \return list of actions identifiers
247 QIntList QtxActionMgr::idList() const
249 return myActions.keys();
253 \brief Check if update is enabled.
254 \return \c true if update is enabled
255 \sa setUpdatesEnabled(), update()
257 bool QtxActionMgr::isUpdatesEnabled() const
263 \brief Enable/disable update operation.
265 \sa isUpdatesEnabled(), update()
267 void QtxActionMgr::setUpdatesEnabled( const bool upd )
273 \brief Check if an action with \a actId identifier is visible to
274 the parent action with \a place identifier.
276 This method can be redefined in subclasses.
277 Base implementatin always returns \c true.
279 \param actId action ID
280 \param place some parent action ID
281 \return \c true if an action is visible to the parent
284 bool QtxActionMgr::isVisible( const int /*actId*/, const int /*place*/ ) const
290 \brief Set action's visibility flag.
292 This method can be redefined in subclasses.
293 Base implementatin does nothing.
295 \param actId action ID
296 \param place some parent action ID
297 \param v new visibility state
300 void QtxActionMgr::setVisible( const int /*actId*/, const int /*place*/, const bool /*v*/ )
305 \brief Update actions.
307 Calls virtual function internalUpdate to update the contents.
308 Does nothing if update is disabled.
310 \sa setUpdatesEnabled(), isUpdatesEnabled(), internalUpdate()
312 void QtxActionMgr::update()
314 if ( !isUpdatesEnabled() )
323 \brief Internal update.
325 This method is called by update() function and can be redefined
326 in subclasses to customize update operation. Base implementation
329 void QtxActionMgr::internalUpdate()
334 \brief Generate unique action identifier.
337 int QtxActionMgr::generateId() const
344 \brief Check is action with given \a id is enabled.
346 \return \c true if action is enabled
348 bool QtxActionMgr::isEnabled( const int id ) const
350 QAction* a = action( id );
352 return a->isEnabled();
358 Enable/disable action with given \a id.
360 \param enable new state
362 void QtxActionMgr::setEnabled( const int id, const bool enable )
364 QAction* a = action( id );
366 a->setEnabled( enable );
370 \brief Create new separator action.
372 If \a own is \c true, then the caller is responsible for the action
373 destroying. If \a own is \c false, new separator action will be owned by the
374 action manager which will destroy it on application exit.
376 \param own ownership flag
377 \return new separator action
379 QAction* QtxActionMgr::separator( const bool own )
382 return new SeparatorAction();
384 if ( qtx_separator_actions.isEmpty() )
385 qAddPostRoutine( qtxSeparatorActionCleanup );
387 SeparatorAction* a = new SeparatorAction();
388 qtx_separator_actions.append( a );
394 \brief Perform delayed update.
396 Does nothing if update is disabled.
397 \sa isUpdatesEnabled(), setUpdatesEnabled(), update()
399 void QtxActionMgr::triggerUpdate()
401 if ( !isUpdatesEnabled() )
406 myUpdTimer = new QTimer( this );
407 myUpdTimer->setSingleShot( true );
408 connect( myUpdTimer, SIGNAL( timeout() ), this, SLOT( onUpdateContent() ) );
411 // add timer event to event list
412 myUpdTimer->start( 0 );
416 \brief Internal content update operation.
418 Called automatically by onUpdateContent() when the delayed update
419 is triggered. Base implementation does nothing.
421 \sa triggerUpdate(), onUpdateContent()
423 void QtxActionMgr::updateContent()
428 \brief Internal action changing response operation.
430 void QtxActionMgr::actionChanged( int )
435 \brief Called when delayed update is performed (via timer event).
437 Calls virtual method updateContent() which can be redefined in the
438 subclasses to customize the content update operation.
440 void QtxActionMgr::onUpdateContent()
446 \brief Called when one of the registered actions changed.
448 Calls virtual method actionChanged() which can be redefined in the
449 subclasses to customize reaction on this.
451 void QtxActionMgr::onActionChanged()
453 QAction* a = ::qobject_cast<QAction*>( sender() );
455 int id = actionId( a );
461 \class QtxActionMgr::Reader
462 \brief Generic actions description files reader class.
464 This class is used to read files of some format to create actions
465 and fill an action manager with the actions automatically.
471 QtxActionMgr::Reader::Reader()
478 QtxActionMgr::Reader::~Reader()
483 \brief Get the list of options.
486 QStringList QtxActionMgr::Reader::options() const
488 return myOptions.keys();
492 \brief Get option value.
494 If there is no such option the default value (\a def) is returned.
496 \param name option name
497 \param def default option value
500 QString QtxActionMgr::Reader::option( const QString& name, const QString& def ) const
502 if( myOptions.contains( name ) )
503 return myOptions[ name ];
509 \brief Set option value.
510 \param name option name
511 \param value new option value
513 void QtxActionMgr::Reader::setOption( const QString& name, const QString& value )
515 myOptions[ name ] = value;
519 \fn bool QtxActionMgr::Reader::read( const QString& fname, Creator& cr ) const
520 \brief Read the file and fill and action manager with actions
521 by using help actions creator.
523 This method should be redefined in the subclasses.
525 \param fname XML file name
526 \param cr actions creator
527 \return \c true on success and \c false in case of error
531 \class QtxActionMgr::XMLReader
532 \brief XML file reader.
534 This class is used to read files of XML format to create
535 actions and fill an action manager with actions automatically.
540 \param root root XML tag name
541 \param item menu item XML tag name
542 \param dir resources directory (containing icons, etc)
544 QtxActionMgr::XMLReader::XMLReader( const QString& root,
549 setOption( QString( "root_tag" ), root );
550 setOption( QString( "menu_item" ), item );
551 setOption( QString( "icons_dir" ), dir );
552 setOption( QString( "id" ), QString( "item-id" ) );
553 setOption( QString( "pos" ), QString( "pos-id" ) );
554 setOption( QString( "group" ), QString( "group-id" ) );
555 setOption( QString( "label" ), QString( "label-id" ) );
556 setOption( QString( "tooltip" ), QString( "tooltip-id" ) );
557 setOption( QString( "accel" ), QString( "accel-id" ) );
558 setOption( QString( "separator" ), QString( "separator" ) );
559 setOption( QString( "icon" ), QString( "icon-id" ) );
560 setOption( QString( "toggle" ), QString( "toggle-id" ) );
566 QtxActionMgr::XMLReader::~XMLReader()
571 \brief Read the file and fill and action manager with actions
572 by using actions creator.
573 \param fname XML file name
574 \param cr actions creator
575 \return \c true on success and \c false in case of error
577 bool QtxActionMgr::XMLReader::read( const QString& fname, Creator& cr ) const
584 if ( !file.open( QFile::ReadOnly ) )
589 res = doc.setContent( &file );
595 QString root = option( "root_tag" );
596 for( QDomNode cur = doc.documentElement(); !cur.isNull(); )
598 if( cur.isElement() && isNodeSimilar( cur, root ) )
600 else if( cur.hasChildNodes() )
602 cur = cur.firstChild();
606 while( !cur.isNull() && cur.nextSibling().isNull() )
607 cur = cur.parentNode();
609 cur = cur.nextSibling();
618 \brief Read XML mode and create an item if requied.
619 \param parent_node parent XML file node
620 \param parent_id parent action ID
621 \param cr actions creator
623 void QtxActionMgr::XMLReader::read( const QDomNode& parent_node,
627 if( parent_node.isNull() )
630 QStringList items = option( "menu_item" ).split( "|", QString::SkipEmptyParts );
632 const QDomNodeList& children = parent_node.childNodes();
633 for( int i=0, n=children.count(); i<n; i++ )
635 QDomNode node = children.item( i );
636 //QString n = node.nodeName();
637 if( node.isElement() /*&& node.hasAttributes()*/ &&
638 ( items.contains( node.nodeName() ) || node.nodeName()==option( "separator" ) ) )
640 QDomNamedNodeMap map = node.attributes();
641 ItemAttributes attrs;
643 for( int i=0, n=map.count(); i<n; i++ )
644 if( map.item( i ).isAttr() )
646 QDomAttr a = map.item( i ).toAttr();
647 attrs.insert( a.name(), a.value() );
650 int newId = cr.append( node.nodeName(), node.hasChildNodes(), attrs, parent_id );
651 if( node.hasChildNodes() )
652 read( node, newId, cr );
658 \brief Check node name correspondance to some pattern.
659 \param node XML file node
660 \param pattern node name pattern
661 \return \c true if node satisfies pattern
663 bool QtxActionMgr::XMLReader::isNodeSimilar( const QDomNode& node,
664 const QString& pattern ) const
666 if( node.nodeName()==pattern )
671 temp.setContent( pattern, true, &mes );
673 const QDomNamedNodeMap &temp_map = temp.documentElement().attributes(),
674 &cur_map = node.attributes();
675 bool ok = temp_map.count()>0;
676 for( int i=0, n=temp_map.count(); i<n && ok; i++ )
678 QDomAttr a = temp_map.item( i ).toAttr(),
679 b = cur_map.namedItem( a.name() ).toAttr();
680 ok = !b.isNull() && a.name()==b.name() && a.value()==b.value();
687 \class QtxActionMgr::Creator
688 \brief Generic actions creator class.
690 Used by Reader to create actions and fill in the action
691 manager with the actions.
695 \brief Get integer attribute value from the attribute map.
697 Returns default value (\a def) if the attribute is not found.
699 \param attrs attributes map
700 \param name attribute name
701 \param def default attribute value
702 \return attribute value
704 int QtxActionMgr::Creator::intValue( const ItemAttributes& attrs,
705 const QString& name, int def )
707 if( attrs.contains( name ) )
710 int res = attrs[ name ].toInt( &ok );
718 \brief Get string attribute value from the attribute map.
720 Returns default value (\a def) if the attribute is not found.
722 \param attrs attributes map
723 \param name attribute name
724 \param def default attribute value
725 \return attribute value
727 QString QtxActionMgr::Creator::strValue( const ItemAttributes& attrs,
731 if( attrs.contains( name ) )
732 return attrs[ name ];
739 \param r action reader
741 QtxActionMgr::Creator::Creator( QtxActionMgr::Reader* r )
749 QtxActionMgr::Creator::~Creator()
754 \brief Get actions reader.
755 \return actions reader
757 QtxActionMgr::Reader* QtxActionMgr::Creator::reader() const
763 \brief Connect action to some specific slot(s).
765 This method can be redefined in subclasses.
766 Base implementation does nothing.
770 void QtxActionMgr::Creator::connect( QAction* /*a*/ ) const
775 \brief Load pixmap from the file.
776 \param fname file name
777 \param pix used to return pixmap
778 \return \c true if pixmap is loaded successfully and \c false in case of error
780 bool QtxActionMgr::Creator::loadPixmap( const QString& fname, QPixmap& pix ) const
785 QStringList dirlist = reader()->option( "icons_dir", "." ).split( ";", QString::SkipEmptyParts );
786 QStringList::const_iterator anIt = dirlist.begin(),
787 aLast = dirlist.end();
789 for( ; anIt!=aLast && !res; anIt++ )
790 res = pix.load( Qtx::addSlash( *anIt ) + fname );
796 \fn int QtxActionMgr::Creator::append( const QString& tag,
798 const ItemAttributes& attr,
800 \brief Create (and probably append to the action manager) new action.
802 This method should be redefined in the subclasses.
804 \param tag item tag name
805 \param subMenu \c true if this item is submenu
806 \param attr attributes map
807 \param pId parent action ID
808 \return item (for example action) ID