1 // Copyright (C) 2007-2008 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.
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
22 // File: QtxPopupMgr.cxx
23 // Author: Alexander SOLOVYOV, Sergey TELKOV
25 #include "QtxPopupMgr.h"
26 #include "QtxAction.h"
27 #include "QtxEvalExpr.h"
31 \brief Used for comparing of two QVariant values.
32 \param v1 first argument for comparison
33 \param v2 second argument for comparison
34 \return \c true if \a v1 less than \a v2
36 bool operator<( const QVariant& v1, const QVariant& v2 )
38 QVariant::Type t1 = v1.type(), t2 = v2.type();
44 return v1.toInt() < v2.toInt();
45 case QVariant::Double:
46 return v1.toDouble() < v2.toDouble();
47 case QVariant::String:
48 return v1.toString() < v2.toString();
49 case QVariant::StringList:
52 const QList<QVariant>& aList1 = v1.toList(), aList2 = v2.toList();
53 QList<QVariant>::const_iterator anIt1 = aList1.begin(), aLast1 = aList1.end(),
54 anIt2 = aList2.begin(), aLast2 = aList2.end();
55 for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ )
57 if ( (*anIt1) != (*anIt2) )
58 return (*anIt1)<(*anIt2);
60 return anIt1 == aLast1 && anIt2 != aLast2;
63 return v1.toString() < v2.toString();
70 \class QtxPopupMgr::PopupCreator
72 \brief Popup menu actions creator.
74 Used by Reader to create actions by reading descriptions from the file
75 and fill in the action manager with the actions.
78 class QtxPopupMgr::PopupCreator : public QtxActionMgr::Creator
81 PopupCreator( QtxActionMgr::Reader*, QtxPopupMgr* );
82 virtual ~PopupCreator();
84 virtual int append( const QString&, const bool,
85 const ItemAttributes&, const int );
87 virtual QString rule( const ItemAttributes&,
88 const QtxPopupMgr::RuleType = VisibleRule ) const;
96 \param r menu action reader
97 \param mgr popup menu manager
99 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
101 : QtxActionMgr::Creator( r ),
109 QtxPopupMgr::PopupCreator::~PopupCreator()
114 \brief Create and append new action to the action manager.
115 \param tag item tag name
116 \param subMenu \c true if this item is submenu
117 \param attr attributes map
118 \param pId parent action ID
119 \return menu action ID
121 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
122 const ItemAttributes& attr, const int pId )
124 if ( !myMgr || !reader() )
127 QString label = reader()->option( "label", "label" ),
128 id = reader()->option( "id", "id" ),
129 pos = reader()->option( "pos", "pos" ),
130 group = reader()->option( "group", "group" ),
131 tooltip = reader()->option( "tooltip", "tooltip" ),
132 sep = reader()->option( "separator", "separator" ),
133 accel = reader()->option( "accel", "accel" ),
134 icon = reader()->option( "icon", "icon" ),
135 toggle = reader()->option( "toggle", "toggle" );
137 QtxActionMenuMgr* mgr = myMgr;
139 int res = -1, actId = intValue( attr, id, -1 );;
141 res = mgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
142 else if ( tag == sep )
143 res = mgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
148 QString name = strValue( attr, icon );
149 if( !name.isEmpty() )
151 if ( loadPixmap( name, pix ) )
155 QString actLabel = strValue( attr, label );
156 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
157 QKeySequence( strValue( attr, accel ) ),
159 newAct->setToolTip( strValue( attr, tooltip ) );
160 QString toggleact = strValue( attr, toggle );
161 bool isToggle = !toggleact.isEmpty();
162 newAct->setCheckable( isToggle );
163 newAct->setChecked( toggleact.toLower() == "true" );
166 int aid = mgr->registerAction( newAct, actId );
167 QString arule = rule( attr, QtxPopupMgr::VisibleRule );
168 if ( !arule.isEmpty() )
169 myMgr->setRule( newAct, arule, QtxPopupMgr::VisibleRule );
170 arule = rule( attr, QtxPopupMgr::EnableRule );
171 if ( !arule.isEmpty() )
172 myMgr->setRule( newAct, arule, QtxPopupMgr::EnableRule );
173 arule = rule( attr, QtxPopupMgr::ToggleRule );
174 if ( isToggle && !arule.isEmpty() )
175 myMgr->setRule( newAct, arule, QtxPopupMgr::ToggleRule );
176 res = mgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
183 \brief Get the rule for the menu item.
185 Default implementation returns empty rule.
187 \param attr attributes map
188 \param ruleType rule type (QtxPopupMgr::RuleType)
189 \return rule for the menu item corresponding to the rule type
191 QString QtxPopupMgr::PopupCreator::rule( const ItemAttributes& /*attr*/,
192 const QtxPopupMgr::RuleType /*ruleType*/ ) const
199 \brief Popup menu manager.
201 Menu manager allows using of set of action for automatic generating of
202 application context popup menu by reuquest and dynamic update of its
205 Use insert() methods to add menu items to the popup menu.
207 The visibility, enable and toggle state of the menu item is controlled
208 by the syntaxic rules, which can be set with setRule() methods.
209 The rules are parsed automatically with help of QtxEvalParser class.
211 QtxPopupSelection class is used as back-end for getting value of each
212 parameter found in the rule by the expression parser.
213 Use setSelection() and selection() to set/get the selection instance
214 for the popup menu manager.
216 Popup menu manager automatically optimizes the menu by removing
217 extra separators, hiding empty popup submenus etc.
222 \param object parent object
224 QtxPopupMgr::QtxPopupMgr( QObject* parent )
225 : QtxActionMenuMgr( 0, parent ),
232 \param popup popup menu
233 \param object parent object
235 QtxPopupMgr::QtxPopupMgr( QMenu* popup, QObject* parent )
236 : QtxActionMenuMgr( popup, parent ),
244 QtxPopupMgr::~QtxPopupMgr()
249 \brief Get popup menu.
252 QMenu* QtxPopupMgr::menu() const
254 return ::qobject_cast<QMenu*>( menuWidget() );
258 \brief Get popup menu.
259 \param menu popup menu
261 void QtxPopupMgr::setMenu( QMenu* menu )
263 setMenuWidget( menu );
267 \brief Get selection.
268 \return current selection object
270 QtxPopupSelection* QtxPopupMgr::selection() const
276 \brief Set selection.
277 \param sel new selection object
279 void QtxPopupMgr::setSelection( QtxPopupSelection* sel )
281 if ( mySelection == sel )
289 mySelection->setParent( this );
290 connect( mySelection, SIGNAL( destroyed( QObject* ) ),
291 this, SLOT( onSelectionDestroyed( QObject* ) ) );
293 QtxActionMgr::triggerUpdate();
297 \brief Register an action and return its identifier.
299 If \a id is less than 0, the identifier for the action is generated automatically.
300 If action with given \a id is already registered, it will be re-registered.
301 If required \a id is already in use, new identifier is generatied; in this case
302 returning value will different from required one.
304 \param act action to be registered
306 \param rule syntax rule
307 \param ruleType rule type (QtxPopupMgr::RuleType)
308 \return action ID (the same as \a id or generated one)
310 int QtxPopupMgr::registerAction( QAction* act, const int id, const QString& rule, const QtxPopupMgr::RuleType ruleType )
312 int _id = QtxActionMenuMgr::registerAction( act, id );
313 setRule( act, rule, ruleType );
318 \brief Unregister action from internal map.
321 void QtxPopupMgr::unRegisterAction( const int id )
323 QAction* a = action( id );
324 if ( myRules.contains( a ) )
326 for ( ExprMap::iterator it = myRules[a].begin(); it != myRules[a].end(); ++it )
333 QtxActionMenuMgr::unRegisterAction( id );
337 \brief Insert action to the popup menu manager.
339 \param pId parent menu action ID
340 \param rule syntax rule
341 \param ruleType rule type (QtxPopupMgr::RuleType)
344 int QtxPopupMgr::insertAction( const int id, const int pId, const QString& rule, const RuleType ruleType )
346 int res = QtxActionMenuMgr::insert( id, pId, -1 );
347 setRule( action( id ), rule, ruleType );
352 \brief Insert action to the popup menu manager.
354 \param pId parent menu action ID
355 \param rule syntax rule
356 \param ruleType rule type (QtxPopupMgr::RuleType)
359 int QtxPopupMgr::insertAction( QAction* a, const int pId, const QString& rule, const RuleType ruleType )
361 int res = QtxActionMenuMgr::insert( a, pId, -1 );
362 setRule( a, rule, ruleType );
367 \return true if action has rule of given type
371 bool QtxPopupMgr::hasRule( QAction* a, const RuleType t ) const
373 return a ? expression( a, t, false ) : false;
377 \return true if action with given id has rule of given type
378 \param id - action id
381 bool QtxPopupMgr::hasRule( const int id, const RuleType t ) const
383 return hasRule( action( id ), t );
387 \brief Get rule of type \a type for the action \a a.
389 \param ruleType rule type (QtxPopupMgr::RuleType)
390 \return rule of required type
392 QString QtxPopupMgr::rule( QAction* a, const RuleType ruleType ) const
395 QtxEvalExpr* expr = expression( a, ruleType );
397 rule = expr->expression();
402 \brief Get rule of type \a type for the action \a id.
404 \param ruleType rule type (QtxPopupMgr::RuleType)
405 \return rule of required type
407 QString QtxPopupMgr::rule( const int id, const RuleType ruleType ) const
409 return rule( action( id ), ruleType );
413 \brief Set rule of type \a type for the action \a a.
416 \param ruleType rule type (QtxPopupMgr::RuleType)
417 \return rule of required type
419 void QtxPopupMgr::setRule( QAction* a, const QString& rule, const RuleType ruleType )
424 QtxEvalExpr* expr = expression( a, ruleType, true );
426 expr->setExpression( rule );
430 \brief Set rule of type \a type for the action \a id.
433 \param ruleType rule type (QtxPopupMgr::RuleType)
434 \return rule of required type
436 void QtxPopupMgr::setRule( const int id, const QString& rule, const RuleType ruleType )
438 setRule( action( id ), rule, ruleType );
442 \brief Calculate an expression.
443 \param p expression parser
444 \return \c true if parser has finished work without errors
446 bool QtxPopupMgr::result( QtxEvalParser* p ) const
451 QVariant vv = p->calculate();
452 res = p->error() == QtxEvalExpr::OK &&
453 ( ( vv.type() == QVariant::Int && vv.toInt() != 0 ) ||
454 ( vv.type() == QVariant::Bool && vv.toBool() ) );
460 \brief Fill the parser with parameters of the expression.
462 The values of the parameters are given from the selection object
465 \param p expression parser
466 \param returning list of parameters names which are not retrieved from the selection
469 void QtxPopupMgr::setParameters( QtxEvalParser* p, QStringList& specific ) const
471 if ( !p || !mySelection )
474 QStringList params = p->parameters();
475 for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
477 QVariant v = parameter( *it );
479 p->setParameter( *it, v );
481 specific.append( *it );
486 \brief Check the rule for the action.
488 \param ruleType rule type (QtxPopupMgr::RuleType)
489 \return \c true if current selection satisfies the action rule
491 bool QtxPopupMgr::isSatisfied( QAction* act, const RuleType ruleType ) const
496 QtxEvalExpr* exp = expression( act, ruleType );
502 QtxEvalParser* p = exp->parser();
504 QStringList specific;
505 p->clearParameters();
506 setParameters( p, specific );
508 QMap<QList<QVariant>, int> aCorteges;
509 if ( !specific.isEmpty() )
514 for ( int i = 0; i < mySelection->count() && !res; i++ )
517 for ( QStringList::const_iterator anIt1 = specific.begin(); anIt1 != specific.end(); ++anIt1 )
518 c.append( parameter( *anIt1, i ) );
519 aCorteges.insert( c, 0 );
521 for ( QMap<QList<QVariant>, int>::const_iterator anIt = aCorteges.begin(); anIt != aCorteges.end(); ++anIt )
523 const QList<QVariant>& aCortege = anIt.key();
524 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
525 QList<QVariant>::const_iterator anIt2 = aCortege.begin();
526 for ( ; anIt1 != aLast1; anIt1++, anIt2++ )
527 p->setParameter( *anIt1, *anIt2 );
528 res = res || result( p );
541 \brief Check if the menu item is visible.
543 \param place some parent action ID
544 \return \c true if the action is visible
546 bool QtxPopupMgr::isVisible( const int id, const int place ) const
548 return QtxActionMenuMgr::isVisible( id, place ) && ( !hasRule( id ) || isSatisfied( action( id ) ) );
552 \brief Perform internal update of the popup menu according
553 to the current selection.
555 void QtxPopupMgr::internalUpdate()
559 for ( RuleMap::iterator it = myRules.begin(); it != myRules.end(); ++it )
561 ExprMap& map = it.value();
562 if ( it.key()->isCheckable() && map.contains( ToggleRule ) &&
563 !map[ToggleRule]->expression().isEmpty() )
564 it.key()->setChecked( isSatisfied( it.key(), ToggleRule ) );
567 QtxActionMenuMgr::internalUpdate();
573 \brief Update popup according to the current selection.
575 void QtxPopupMgr::updateMenu()
581 \brief Get an syntax expression for the action according to the specified rule type.
583 \param ruleType rule type (QtxPopupMgr::RuleType)
584 \param create if \c true an expression does not exist, create it
585 \return syntax expression
587 QtxEvalExpr* QtxPopupMgr::expression( QAction* a, const RuleType ruleType, const bool create ) const
589 QtxEvalExpr* res = 0;
591 QtxPopupMgr* that = (QtxPopupMgr*)this;
592 RuleMap& ruleMap = that->myRules;
593 if ( !ruleMap.contains( a ) && create )
594 ruleMap.insert( a, ExprMap() );
596 if ( ruleMap.contains( a ) )
598 ExprMap& exprMap = ruleMap[a];
599 if ( exprMap.contains( ruleType ) )
600 res = exprMap[ruleType];
602 exprMap.insert( ruleType, res = new QtxEvalExpr() );
609 \brief Load actions description from the file.
610 \param fname file name
611 \param r action reader
612 \return \c true on success and \c false on error
614 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
616 PopupCreator cr( &r, this );
617 return r.read( fname, cr );
621 \brief Get the specified parameter value.
622 \param name parameter name
623 \param idx additional index used when used parameters with same names
624 \return parameter value
627 QVariant QtxPopupMgr::parameter( const QString& name, const int idx ) const
630 QString cacheName = name + ( idx >= 0 ? QString( "_%1" ).arg( idx ) : QString() );
631 if ( myCache.contains( cacheName ) )
632 val = myCache[cacheName];
636 val = idx < 0 ? selection()->parameter( name ) :
637 selection()->parameter( idx, name );
640 QtxPopupMgr* that = (QtxPopupMgr*)this;
641 that->myCache.insert( cacheName, val );
648 \brief Called when selection is destroyed.
650 Prevents crashes when the selection object is destroyed outside the
653 \param o selection object being destroyed
655 void QtxPopupMgr::onSelectionDestroyed( QObject* o )
657 if ( o == mySelection )
662 \class QtxPopupSelection
663 \brief This class is a part of the popup menu management system.
665 The QtxPopupSelection class is used as back-end for getting value
666 of each parameter found in the rule by the expression parser.
668 For example, it can be used for the analyzing of the currently
669 selected objects and defining the values of the parameters used
670 in the rules syntax expression. Rules, in their turn, define
671 each action state - visibility, enabled and toggled state.
677 QtxPopupSelection::QtxPopupSelection()
685 QtxPopupSelection::~QtxPopupSelection()
690 \brief Get an option value.
691 \param optName option name
692 \return option value or empty string if option is not found
694 QString QtxPopupSelection::option( const QString& optName ) const
697 if ( myOptions.contains( optName ) )
698 opt = myOptions[optName];
703 \brief Set an option value.
704 \param optName option name
705 \param opt option value
707 void QtxPopupSelection::setOption( const QString& optName, const QString& opt )
709 myOptions.insert( optName, opt );
713 \brief Get the parameter value.
714 \param str parameter name
715 \return parameter value
717 QVariant QtxPopupSelection::parameter( const QString& str ) const
719 if ( str == selCountParam() )
721 else if ( str.startsWith( equalityParam() ) )
723 QtxEvalSetSets::ValueSet set;
724 QString par = str.mid( equalityParam().length() );
725 for ( int i = 0; i < (int)count(); i++ )
727 QVariant v = parameter( i, par );
729 QtxEvalSetSets::add( set, v );
740 \brief Get symbol which detects the name of the parameter list.
741 \return equality symbol (by default, "$")
743 QString QtxPopupSelection::equalityParam() const
745 QString str = option( "equality" );
752 \brief Get name of the parameter, specifing number of selected objects
753 \return parameter name (by default, "selcount")
755 QString QtxPopupSelection::selCountParam() const
757 QString str = option( "selcount" );
764 \fn int QtxPopupSelection::count() const;
765 \brief Get number of the selected objects.
766 \return nb of selected objects
770 \fn QVariant QtxPopupSelection::parameter( const int idx, const QString& name ) const;
771 \brief Get value of the parameter which is of list type
772 \param idx parameter index
773 \param name parameter name
774 \return parameter value