1 // Copyright (C) 2007-2022 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: QtxPopupMgr.cxx
24 // Author: Alexander SOLOVYOV, Sergey TELKOV
26 #include "QtxPopupMgr.h"
27 #include "QtxAction.h"
28 #include "QtxEvalExpr.h"
33 bool operator<( const QList<QVariant>& v1, const QList<QVariant>& v2 )
35 QList<QVariant>::const_iterator anIt1 = v1.begin(), aLast1 = v1.end(),
36 anIt2 = v2.begin(), aLast2 = v2.end();
37 for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ )
39 if ( (*anIt1) != (*anIt2) )
40 return (*anIt1) < (*anIt2);
42 return anIt1 == aLast1 && anIt2 != aLast2;
46 \class QtxPopupMgr::PopupCreator
48 \brief Popup menu actions creator.
50 Used by Reader to create actions by reading descriptions from the file
51 and fill in the action manager with the actions.
54 class QtxPopupMgr::PopupCreator : public QtxActionMgr::Creator
57 PopupCreator( QtxActionMgr::Reader*, QtxPopupMgr* );
58 virtual ~PopupCreator();
60 virtual int append( const QString&, const bool,
61 const ItemAttributes&, const int );
63 virtual QString rule( const ItemAttributes&,
64 const QtxPopupMgr::RuleType = VisibleRule ) const;
72 \param r menu action reader
73 \param mgr popup menu manager
75 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
77 : QtxActionMgr::Creator( r ),
85 QtxPopupMgr::PopupCreator::~PopupCreator()
90 \brief Create and append new action to the action manager.
91 \param tag item tag name
92 \param subMenu \c true if this item is submenu
93 \param attr attributes map
94 \param pId parent action ID
95 \return menu action ID
97 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
98 const ItemAttributes& attr, const int pId )
100 if ( !myMgr || !reader() )
103 QString label = reader()->option( "label", "label" ),
104 id = reader()->option( "id", "id" ),
105 pos = reader()->option( "pos", "pos" ),
106 group = reader()->option( "group", "group" ),
107 tooltip = reader()->option( "tooltip", "tooltip" ),
108 sep = reader()->option( "separator", "separator" ),
109 accel = reader()->option( "accel", "accel" ),
110 icon = reader()->option( "icon", "icon" ),
111 toggle = reader()->option( "toggle", "toggle" );
113 QtxActionMenuMgr* mgr = myMgr;
115 int res = -1, actId = intValue( attr, id, -1 );;
117 res = mgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
118 else if ( tag == sep )
119 res = mgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
124 QString name = strValue( attr, icon );
125 if( !name.isEmpty() )
127 if ( loadPixmap( name, pix ) )
131 QString actLabel = strValue( attr, label );
132 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
133 QKeySequence( strValue( attr, accel ) ),
135 newAct->setToolTip( strValue( attr, tooltip ) );
136 QString toggleact = strValue( attr, toggle );
137 bool isToggle = !toggleact.isEmpty();
138 newAct->setCheckable( isToggle );
139 newAct->setChecked( toggleact.toLower() == "true" );
142 int aid = mgr->registerAction( newAct, actId );
143 QString arule = rule( attr, QtxPopupMgr::VisibleRule );
144 if ( !arule.isEmpty() )
145 myMgr->setRule( newAct, arule, QtxPopupMgr::VisibleRule );
146 arule = rule( attr, QtxPopupMgr::EnableRule );
147 if ( !arule.isEmpty() )
148 myMgr->setRule( newAct, arule, QtxPopupMgr::EnableRule );
149 arule = rule( attr, QtxPopupMgr::ToggleRule );
150 if ( isToggle && !arule.isEmpty() )
151 myMgr->setRule( newAct, arule, QtxPopupMgr::ToggleRule );
152 res = mgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
159 \brief Get the rule for the menu item.
161 Default implementation returns empty rule.
163 \param attr attributes map
164 \param ruleType rule type (QtxPopupMgr::RuleType)
165 \return rule for the menu item corresponding to the rule type
167 QString QtxPopupMgr::PopupCreator::rule( const ItemAttributes& /*attr*/,
168 const QtxPopupMgr::RuleType /*ruleType*/ ) const
175 \brief Popup menu manager.
177 Menu manager allows using of set of action for automatic generating of
178 application context popup menu by reuquest and dynamic update of its
181 Use insert() methods to add menu items to the popup menu.
183 The visibility, enable and toggle state of the menu item is controlled
184 by the syntaxic rules, which can be set with setRule() methods.
185 The rules are parsed automatically with help of QtxEvalParser class.
187 QtxPopupSelection class is used as back-end for getting value of each
188 parameter found in the rule by the expression parser.
189 Use setSelection() and selection() to set/get the selection instance
190 for the popup menu manager.
192 Popup menu manager automatically optimizes the menu by removing
193 extra separators, hiding empty popup submenus etc.
198 \param object parent object
200 QtxPopupMgr::QtxPopupMgr( QObject* parent )
201 : QtxActionMenuMgr( 0, parent ),
208 \param popup popup menu
209 \param object parent object
211 QtxPopupMgr::QtxPopupMgr( QMenu* popup, QObject* parent )
212 : QtxActionMenuMgr( popup, parent ),
220 QtxPopupMgr::~QtxPopupMgr()
225 \brief Get popup menu.
228 QMenu* QtxPopupMgr::menu() const
230 return ::qobject_cast<QMenu*>( menuWidget() );
234 \brief Get popup menu.
235 \param menu popup menu
237 void QtxPopupMgr::setMenu( QMenu* menu )
239 setMenuWidget( menu );
243 \brief Get selection.
244 \return current selection object
246 QtxPopupSelection* QtxPopupMgr::selection() const
252 \brief Set selection.
253 \param sel new selection object
255 void QtxPopupMgr::setSelection( QtxPopupSelection* sel )
257 if ( mySelection == sel )
265 mySelection->setParent( this );
266 mySelection->setPopupMgr( this );
269 connect( mySelection, SIGNAL( destroyed( QObject* ) ),
270 this, SLOT( onSelectionDestroyed( QObject* ) ) );
272 QtxActionMgr::triggerUpdate();
276 \brief Register an action and return its identifier.
278 If \a id is less than 0, the identifier for the action is generated automatically.
279 If action with given \a id is already registered, it will be re-registered.
280 If required \a id is already in use, new identifier is generatied; in this case
281 returning value will different from required one.
283 \param act action to be registered
285 \param rule syntax rule
286 \param ruleType rule type (QtxPopupMgr::RuleType)
287 \return action ID (the same as \a id or generated one)
289 int QtxPopupMgr::registerAction( QAction* act, const int id, const QString& rule, const QtxPopupMgr::RuleType ruleType )
291 int _id = QtxActionMenuMgr::registerAction( act, id );
292 setRule( act, rule, ruleType );
297 \brief Unregister action from internal map.
300 void QtxPopupMgr::unRegisterAction( const int id )
302 QAction* a = action( id );
303 if ( myRules.contains( a ) )
305 for ( ExprMap::iterator it = myRules[a].begin(); it != myRules[a].end(); ++it )
312 QtxActionMenuMgr::unRegisterAction( id );
316 \brief Insert action to the popup menu manager.
318 \param pId parent menu action ID
319 \param rule syntax rule
320 \param ruleType rule type (QtxPopupMgr::RuleType)
323 int QtxPopupMgr::insertAction( const int id, const int pId, const QString& rule, const RuleType ruleType )
325 int res = QtxActionMenuMgr::insert( id, pId, -1 );
326 setRule( action( id ), rule, ruleType );
331 \brief Insert action to the popup menu manager.
333 \param pId parent menu action ID
334 \param rule syntax rule
335 \param ruleType rule type (QtxPopupMgr::RuleType)
338 int QtxPopupMgr::insertAction( QAction* a, const int pId, const QString& rule, const RuleType ruleType )
340 int res = QtxActionMenuMgr::insert( a, pId, -1 );
341 setRule( a, rule, ruleType );
346 \return true if action has rule of given type
350 bool QtxPopupMgr::hasRule( QAction* a, const RuleType t ) const
352 return a ? expression( a, t, false )!=0 : false;
356 \return true if action with given id has rule of given type
357 \param id - action id
360 bool QtxPopupMgr::hasRule( const int id, const RuleType t ) const
362 return hasRule( action( id ), t );
366 \brief Get rule of type \a type for the action \a a.
368 \param ruleType rule type (QtxPopupMgr::RuleType)
369 \return rule of required type
371 QString QtxPopupMgr::rule( QAction* a, const RuleType ruleType ) const
374 QtxEvalExpr* expr = expression( a, ruleType );
376 rule = expr->expression();
381 \brief Get rule of type \a type for the action \a id.
383 \param ruleType rule type (QtxPopupMgr::RuleType)
384 \return rule of required type
386 QString QtxPopupMgr::rule( const int id, const RuleType ruleType ) const
388 return rule( action( id ), ruleType );
392 \brief Set rule of type \a type for the action \a a.
395 \param ruleType rule type (QtxPopupMgr::RuleType)
396 \return rule of required type
398 void QtxPopupMgr::setRule( QAction* a, const QString& rule, const RuleType ruleType )
403 QtxEvalExpr* expr = expression( a, ruleType, true );
405 expr->setExpression( rule );
409 \brief Set rule of type \a type for the action \a id.
412 \param ruleType rule type (QtxPopupMgr::RuleType)
413 \return rule of required type
415 void QtxPopupMgr::setRule( const int id, const QString& rule, const RuleType ruleType )
417 setRule( action( id ), rule, ruleType );
421 \brief Calculate an expression.
422 \param p expression parser
423 \return \c true if parser has finished work without errors
425 bool QtxPopupMgr::result( QtxEvalParser* p ) const
430 QVariant vv = p->calculate();
431 res = p->error() == QtxEvalExpr::OK &&
432 ( ( vv.type() == QVariant::Int && vv.toInt() != 0 ) ||
433 ( vv.type() == QVariant::Bool && vv.toBool() ) );
439 \brief Fill the parser with parameters of the expression.
441 The values of the parameters are given from the selection object
444 \param p expression parser
445 \param returning list of parameters names which are not retrieved from the selection
448 void QtxPopupMgr::setParameters( QtxEvalParser* p, QStringList& specific ) const
450 if ( !p || !mySelection )
453 QStringList params = p->parameters();
454 for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
456 QVariant v = parameter( *it );
458 p->setParameter( *it, v );
460 specific.append( *it );
465 \brief Check the rule for the action.
467 \param ruleType rule type (QtxPopupMgr::RuleType)
468 \return \c true if current selection satisfies the action rule
470 bool QtxPopupMgr::isSatisfied( QAction* act, const RuleType ruleType ) const
475 QtxEvalExpr* exp = expression( act, ruleType );
481 QtxEvalParser* p = exp->parser();
483 QStringList specific;
484 p->clearParameters();
485 setParameters( p, specific );
487 QMap<QList<QVariant>, int> aCorteges;
488 if ( !specific.isEmpty() )
493 for ( int i = 0; i < mySelection->count() && !res; i++ )
496 for ( QStringList::const_iterator anIt1 = specific.begin(); anIt1 != specific.end(); ++anIt1 )
497 c.append( parameter( *anIt1, i ) );
498 aCorteges.insert( c, 0 );
500 for ( QMap<QList<QVariant>, int>::const_iterator anIt = aCorteges.begin(); anIt != aCorteges.end(); ++anIt )
502 const QList<QVariant>& aCortege = anIt.key();
503 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
504 QList<QVariant>::const_iterator anIt2 = aCortege.begin();
505 for ( ; anIt1 != aLast1; anIt1++, anIt2++ )
506 p->setParameter( *anIt1, *anIt2 );
507 res = res || result( p );
520 \brief Check if the menu item is visible.
522 \param place some parent action ID
523 \return \c true if the action is visible
525 bool QtxPopupMgr::isVisible( const int id, const int place ) const
527 return QtxActionMenuMgr::isVisible( id, place ) && ( !hasRule( id ) || isSatisfied( action( id ) ) );
531 \brief Perform internal update of the popup menu according
532 to the current selection.
534 void QtxPopupMgr::internalUpdate()
538 for ( RuleMap::iterator it = myRules.begin(); it != myRules.end(); ++it )
540 ExprMap& map = it.value();
541 if ( it.key()->isCheckable() && map.contains( ToggleRule ) &&
542 !map[ToggleRule]->expression().isEmpty() )
543 it.key()->setChecked( isSatisfied( it.key(), ToggleRule ) );
546 QtxActionMenuMgr::internalUpdate();
552 \brief Update popup according to the current selection.
554 void QtxPopupMgr::updateMenu()
560 \brief Get an syntax expression for the action according to the specified rule type.
562 \param ruleType rule type (QtxPopupMgr::RuleType)
563 \param create if \c true an expression does not exist, create it
564 \return syntax expression
566 QtxEvalExpr* QtxPopupMgr::expression( QAction* a, const RuleType ruleType, const bool create ) const
568 QtxEvalExpr* res = 0;
570 QtxPopupMgr* that = (QtxPopupMgr*)this;
571 RuleMap& ruleMap = that->myRules;
572 if ( !ruleMap.contains( a ) && create )
573 ruleMap.insert( a, ExprMap() );
575 if ( ruleMap.contains( a ) )
577 ExprMap& exprMap = ruleMap[a];
578 if ( exprMap.contains( ruleType ) )
579 res = exprMap[ruleType];
581 exprMap.insert( ruleType, res = new QtxEvalExpr() );
588 \brief Load actions description from the file.
589 \param fname file name
590 \param r action reader
591 \return \c true on success and \c false on error
593 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
595 PopupCreator cr( &r, this );
596 return r.read( fname, cr );
600 \brief Get the specified parameter value.
601 \param name parameter name
602 \param idx additional index used when used parameters with same names
603 \return parameter value
606 QVariant QtxPopupMgr::parameter( const QString& name, const int idx ) const
609 QString cacheName = name + ( idx >= 0 ? QString( "_%1" ).arg( idx ) : QString() );
610 if ( myCache.contains( cacheName ) )
611 val = myCache[cacheName];
615 val = idx < 0 ? selection()->parameter( name ) :
616 selection()->parameter( idx, name );
619 QtxPopupMgr* that = (QtxPopupMgr*)this;
620 that->myCache.insert( cacheName, val );
627 \brief Called when selection is destroyed.
629 Prevents crashes when the selection object is destroyed outside the
632 \param o selection object being destroyed
634 void QtxPopupMgr::onSelectionDestroyed( QObject* o )
636 if ( o == mySelection )
641 \class QtxPopupSelection
642 \brief This class is a part of the popup menu management system.
644 The QtxPopupSelection class is used as back-end for getting value
645 of each parameter found in the rule by the expression parser.
647 For example, it can be used for the analyzing of the currently
648 selected objects and defining the values of the parameters used
649 in the rules syntax expression. Rules, in their turn, define
650 each action state - visibility, enabled and toggled state.
656 QtxPopupSelection::QtxPopupSelection()
665 QtxPopupSelection::~QtxPopupSelection()
670 \brief Get an option value.
671 \param optName option name
672 \return option value or empty string if option is not found
674 QString QtxPopupSelection::option( const QString& optName ) const
677 if ( myOptions.contains( optName ) )
678 opt = myOptions[optName];
683 \brief Set an option value.
684 \param optName option name
685 \param opt option value
687 void QtxPopupSelection::setOption( const QString& optName, const QString& opt )
689 myOptions.insert( optName, opt );
692 QtxPopupMgr* QtxPopupSelection::popupMgr() const
697 void QtxPopupSelection::setPopupMgr( QtxPopupMgr* pm )
703 \brief Get the parameter value.
704 \param str parameter name
705 \return parameter value
707 QVariant QtxPopupSelection::parameter( const QString& str ) const
709 if ( str == selCountParam() )
711 else if ( str.startsWith( equalityParam() ) )
713 QtxEvalSetSets::ValueSet set;
714 QString par = str.mid( equalityParam().length() );
716 QtxPopupMgr* pMgr = popupMgr();
717 for ( int i = 0; i < (int)count(); i++ )
719 QVariant v = pMgr ? pMgr->parameter( par, i ) : parameter( i, par );
721 QtxEvalSetSets::add( set, v );
732 \brief Get symbol which detects the name of the parameter list.
733 \return equality symbol (by default, "$")
735 QString QtxPopupSelection::equalityParam() const
737 QString str = option( "equality" );
744 \brief Get name of the parameter, specifing number of selected objects
745 \return parameter name (by default, "selcount")
747 QString QtxPopupSelection::selCountParam() const
749 QString str = option( "selcount" );
756 \fn int QtxPopupSelection::count() const;
757 \brief Get number of the selected objects.
758 \return nb of selected objects
762 \fn QVariant QtxPopupSelection::parameter( const int idx, const QString& name ) const;
763 \brief Get value of the parameter which is of list type
764 \param idx parameter index
765 \param name parameter name
766 \return parameter value