1 // Copyright (C) 2007-2014 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"
32 \brief Used for comparing of two QVariant values.
33 \param v1 first argument for comparison
34 \param v2 second argument for comparison
35 \return \c true if \a v1 less than \a v2
37 bool operator<( const QVariant& v1, const QVariant& v2 )
39 QVariant::Type t1 = v1.type(), t2 = v2.type();
45 return v1.toInt() < v2.toInt();
46 case QVariant::Double:
47 return v1.toDouble() < v2.toDouble();
48 case QVariant::String:
49 return v1.toString() < v2.toString();
50 case QVariant::StringList:
53 const QList<QVariant>& aList1 = v1.toList(), aList2 = v2.toList();
54 QList<QVariant>::const_iterator anIt1 = aList1.begin(), aLast1 = aList1.end(),
55 anIt2 = aList2.begin(), aLast2 = aList2.end();
56 for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ )
58 if ( (*anIt1) != (*anIt2) )
59 return (*anIt1)<(*anIt2);
61 return anIt1 == aLast1 && anIt2 != aLast2;
64 return v1.toString() < v2.toString();
71 \class QtxPopupMgr::PopupCreator
73 \brief Popup menu actions creator.
75 Used by Reader to create actions by reading descriptions from the file
76 and fill in the action manager with the actions.
79 class QtxPopupMgr::PopupCreator : public QtxActionMgr::Creator
82 PopupCreator( QtxActionMgr::Reader*, QtxPopupMgr* );
83 virtual ~PopupCreator();
85 virtual int append( const QString&, const bool,
86 const ItemAttributes&, const int );
88 virtual QString rule( const ItemAttributes&,
89 const QtxPopupMgr::RuleType = VisibleRule ) const;
97 \param r menu action reader
98 \param mgr popup menu manager
100 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
102 : QtxActionMgr::Creator( r ),
110 QtxPopupMgr::PopupCreator::~PopupCreator()
115 \brief Create and append new action to the action manager.
116 \param tag item tag name
117 \param subMenu \c true if this item is submenu
118 \param attr attributes map
119 \param pId parent action ID
120 \return menu action ID
122 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
123 const ItemAttributes& attr, const int pId )
125 if ( !myMgr || !reader() )
128 QString label = reader()->option( "label", "label" ),
129 id = reader()->option( "id", "id" ),
130 pos = reader()->option( "pos", "pos" ),
131 group = reader()->option( "group", "group" ),
132 tooltip = reader()->option( "tooltip", "tooltip" ),
133 sep = reader()->option( "separator", "separator" ),
134 accel = reader()->option( "accel", "accel" ),
135 icon = reader()->option( "icon", "icon" ),
136 toggle = reader()->option( "toggle", "toggle" );
138 QtxActionMenuMgr* mgr = myMgr;
140 int res = -1, actId = intValue( attr, id, -1 );;
142 res = mgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
143 else if ( tag == sep )
144 res = mgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
149 QString name = strValue( attr, icon );
150 if( !name.isEmpty() )
152 if ( loadPixmap( name, pix ) )
156 QString actLabel = strValue( attr, label );
157 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
158 QKeySequence( strValue( attr, accel ) ),
160 newAct->setToolTip( strValue( attr, tooltip ) );
161 QString toggleact = strValue( attr, toggle );
162 bool isToggle = !toggleact.isEmpty();
163 newAct->setCheckable( isToggle );
164 newAct->setChecked( toggleact.toLower() == "true" );
167 int aid = mgr->registerAction( newAct, actId );
168 QString arule = rule( attr, QtxPopupMgr::VisibleRule );
169 if ( !arule.isEmpty() )
170 myMgr->setRule( newAct, arule, QtxPopupMgr::VisibleRule );
171 arule = rule( attr, QtxPopupMgr::EnableRule );
172 if ( !arule.isEmpty() )
173 myMgr->setRule( newAct, arule, QtxPopupMgr::EnableRule );
174 arule = rule( attr, QtxPopupMgr::ToggleRule );
175 if ( isToggle && !arule.isEmpty() )
176 myMgr->setRule( newAct, arule, QtxPopupMgr::ToggleRule );
177 res = mgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
184 \brief Get the rule for the menu item.
186 Default implementation returns empty rule.
188 \param attr attributes map
189 \param ruleType rule type (QtxPopupMgr::RuleType)
190 \return rule for the menu item corresponding to the rule type
192 QString QtxPopupMgr::PopupCreator::rule( const ItemAttributes& /*attr*/,
193 const QtxPopupMgr::RuleType /*ruleType*/ ) const
200 \brief Popup menu manager.
202 Menu manager allows using of set of action for automatic generating of
203 application context popup menu by reuquest and dynamic update of its
206 Use insert() methods to add menu items to the popup menu.
208 The visibility, enable and toggle state of the menu item is controlled
209 by the syntaxic rules, which can be set with setRule() methods.
210 The rules are parsed automatically with help of QtxEvalParser class.
212 QtxPopupSelection class is used as back-end for getting value of each
213 parameter found in the rule by the expression parser.
214 Use setSelection() and selection() to set/get the selection instance
215 for the popup menu manager.
217 Popup menu manager automatically optimizes the menu by removing
218 extra separators, hiding empty popup submenus etc.
223 \param object parent object
225 QtxPopupMgr::QtxPopupMgr( QObject* parent )
226 : QtxActionMenuMgr( 0, parent ),
233 \param popup popup menu
234 \param object parent object
236 QtxPopupMgr::QtxPopupMgr( QMenu* popup, QObject* parent )
237 : QtxActionMenuMgr( popup, parent ),
245 QtxPopupMgr::~QtxPopupMgr()
250 \brief Get popup menu.
253 QMenu* QtxPopupMgr::menu() const
255 return ::qobject_cast<QMenu*>( menuWidget() );
259 \brief Get popup menu.
260 \param menu popup menu
262 void QtxPopupMgr::setMenu( QMenu* menu )
264 setMenuWidget( menu );
268 \brief Get selection.
269 \return current selection object
271 QtxPopupSelection* QtxPopupMgr::selection() const
277 \brief Set selection.
278 \param sel new selection object
280 void QtxPopupMgr::setSelection( QtxPopupSelection* sel )
282 if ( mySelection == sel )
290 mySelection->setParent( this );
291 mySelection->setPopupMgr( this );
294 connect( mySelection, SIGNAL( destroyed( QObject* ) ),
295 this, SLOT( onSelectionDestroyed( QObject* ) ) );
297 QtxActionMgr::triggerUpdate();
301 \brief Register an action and return its identifier.
303 If \a id is less than 0, the identifier for the action is generated automatically.
304 If action with given \a id is already registered, it will be re-registered.
305 If required \a id is already in use, new identifier is generatied; in this case
306 returning value will different from required one.
308 \param act action to be registered
310 \param rule syntax rule
311 \param ruleType rule type (QtxPopupMgr::RuleType)
312 \return action ID (the same as \a id or generated one)
314 int QtxPopupMgr::registerAction( QAction* act, const int id, const QString& rule, const QtxPopupMgr::RuleType ruleType )
316 int _id = QtxActionMenuMgr::registerAction( act, id );
317 setRule( act, rule, ruleType );
322 \brief Unregister action from internal map.
325 void QtxPopupMgr::unRegisterAction( const int id )
327 QAction* a = action( id );
328 if ( myRules.contains( a ) )
330 for ( ExprMap::iterator it = myRules[a].begin(); it != myRules[a].end(); ++it )
337 QtxActionMenuMgr::unRegisterAction( id );
341 \brief Insert action to the popup menu manager.
343 \param pId parent menu action ID
344 \param rule syntax rule
345 \param ruleType rule type (QtxPopupMgr::RuleType)
348 int QtxPopupMgr::insertAction( const int id, const int pId, const QString& rule, const RuleType ruleType )
350 int res = QtxActionMenuMgr::insert( id, pId, -1 );
351 setRule( action( id ), rule, ruleType );
356 \brief Insert action to the popup menu manager.
358 \param pId parent menu action ID
359 \param rule syntax rule
360 \param ruleType rule type (QtxPopupMgr::RuleType)
363 int QtxPopupMgr::insertAction( QAction* a, const int pId, const QString& rule, const RuleType ruleType )
365 int res = QtxActionMenuMgr::insert( a, pId, -1 );
366 setRule( a, rule, ruleType );
371 \return true if action has rule of given type
375 bool QtxPopupMgr::hasRule( QAction* a, const RuleType t ) const
377 return a ? expression( a, t, false )!=0 : false;
381 \return true if action with given id has rule of given type
382 \param id - action id
385 bool QtxPopupMgr::hasRule( const int id, const RuleType t ) const
387 return hasRule( action( id ), t );
391 \brief Get rule of type \a type for the action \a a.
393 \param ruleType rule type (QtxPopupMgr::RuleType)
394 \return rule of required type
396 QString QtxPopupMgr::rule( QAction* a, const RuleType ruleType ) const
399 QtxEvalExpr* expr = expression( a, ruleType );
401 rule = expr->expression();
406 \brief Get rule of type \a type for the action \a id.
408 \param ruleType rule type (QtxPopupMgr::RuleType)
409 \return rule of required type
411 QString QtxPopupMgr::rule( const int id, const RuleType ruleType ) const
413 return rule( action( id ), ruleType );
417 \brief Set rule of type \a type for the action \a a.
420 \param ruleType rule type (QtxPopupMgr::RuleType)
421 \return rule of required type
423 void QtxPopupMgr::setRule( QAction* a, const QString& rule, const RuleType ruleType )
428 QtxEvalExpr* expr = expression( a, ruleType, true );
430 expr->setExpression( rule );
434 \brief Set rule of type \a type for the action \a id.
437 \param ruleType rule type (QtxPopupMgr::RuleType)
438 \return rule of required type
440 void QtxPopupMgr::setRule( const int id, const QString& rule, const RuleType ruleType )
442 setRule( action( id ), rule, ruleType );
446 \brief Calculate an expression.
447 \param p expression parser
448 \return \c true if parser has finished work without errors
450 bool QtxPopupMgr::result( QtxEvalParser* p ) const
455 QVariant vv = p->calculate();
456 res = p->error() == QtxEvalExpr::OK &&
457 ( ( vv.type() == QVariant::Int && vv.toInt() != 0 ) ||
458 ( vv.type() == QVariant::Bool && vv.toBool() ) );
464 \brief Fill the parser with parameters of the expression.
466 The values of the parameters are given from the selection object
469 \param p expression parser
470 \param returning list of parameters names which are not retrieved from the selection
473 void QtxPopupMgr::setParameters( QtxEvalParser* p, QStringList& specific ) const
475 if ( !p || !mySelection )
478 QStringList params = p->parameters();
479 for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
481 QVariant v = parameter( *it );
483 p->setParameter( *it, v );
485 specific.append( *it );
490 \brief Check the rule for the action.
492 \param ruleType rule type (QtxPopupMgr::RuleType)
493 \return \c true if current selection satisfies the action rule
495 bool QtxPopupMgr::isSatisfied( QAction* act, const RuleType ruleType ) const
500 QtxEvalExpr* exp = expression( act, ruleType );
506 QtxEvalParser* p = exp->parser();
508 QStringList specific;
509 p->clearParameters();
510 setParameters( p, specific );
512 QMap<QList<QVariant>, int> aCorteges;
513 if ( !specific.isEmpty() )
518 for ( int i = 0; i < mySelection->count() && !res; i++ )
521 for ( QStringList::const_iterator anIt1 = specific.begin(); anIt1 != specific.end(); ++anIt1 )
522 c.append( parameter( *anIt1, i ) );
523 aCorteges.insert( c, 0 );
525 for ( QMap<QList<QVariant>, int>::const_iterator anIt = aCorteges.begin(); anIt != aCorteges.end(); ++anIt )
527 const QList<QVariant>& aCortege = anIt.key();
528 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
529 QList<QVariant>::const_iterator anIt2 = aCortege.begin();
530 for ( ; anIt1 != aLast1; anIt1++, anIt2++ )
531 p->setParameter( *anIt1, *anIt2 );
532 res = res || result( p );
545 \brief Check if the menu item is visible.
547 \param place some parent action ID
548 \return \c true if the action is visible
550 bool QtxPopupMgr::isVisible( const int id, const int place ) const
552 return QtxActionMenuMgr::isVisible( id, place ) && ( !hasRule( id ) || isSatisfied( action( id ) ) );
556 \brief Perform internal update of the popup menu according
557 to the current selection.
559 void QtxPopupMgr::internalUpdate()
563 for ( RuleMap::iterator it = myRules.begin(); it != myRules.end(); ++it )
565 ExprMap& map = it.value();
566 if ( it.key()->isCheckable() && map.contains( ToggleRule ) &&
567 !map[ToggleRule]->expression().isEmpty() )
568 it.key()->setChecked( isSatisfied( it.key(), ToggleRule ) );
571 QtxActionMenuMgr::internalUpdate();
577 \brief Update popup according to the current selection.
579 void QtxPopupMgr::updateMenu()
585 \brief Get an syntax expression for the action according to the specified rule type.
587 \param ruleType rule type (QtxPopupMgr::RuleType)
588 \param create if \c true an expression does not exist, create it
589 \return syntax expression
591 QtxEvalExpr* QtxPopupMgr::expression( QAction* a, const RuleType ruleType, const bool create ) const
593 QtxEvalExpr* res = 0;
595 QtxPopupMgr* that = (QtxPopupMgr*)this;
596 RuleMap& ruleMap = that->myRules;
597 if ( !ruleMap.contains( a ) && create )
598 ruleMap.insert( a, ExprMap() );
600 if ( ruleMap.contains( a ) )
602 ExprMap& exprMap = ruleMap[a];
603 if ( exprMap.contains( ruleType ) )
604 res = exprMap[ruleType];
606 exprMap.insert( ruleType, res = new QtxEvalExpr() );
613 \brief Load actions description from the file.
614 \param fname file name
615 \param r action reader
616 \return \c true on success and \c false on error
618 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
620 PopupCreator cr( &r, this );
621 return r.read( fname, cr );
625 \brief Get the specified parameter value.
626 \param name parameter name
627 \param idx additional index used when used parameters with same names
628 \return parameter value
631 QVariant QtxPopupMgr::parameter( const QString& name, const int idx ) const
634 QString cacheName = name + ( idx >= 0 ? QString( "_%1" ).arg( idx ) : QString() );
635 if ( myCache.contains( cacheName ) )
636 val = myCache[cacheName];
640 val = idx < 0 ? selection()->parameter( name ) :
641 selection()->parameter( idx, name );
644 QtxPopupMgr* that = (QtxPopupMgr*)this;
645 that->myCache.insert( cacheName, val );
652 \brief Called when selection is destroyed.
654 Prevents crashes when the selection object is destroyed outside the
657 \param o selection object being destroyed
659 void QtxPopupMgr::onSelectionDestroyed( QObject* o )
661 if ( o == mySelection )
666 \class QtxPopupSelection
667 \brief This class is a part of the popup menu management system.
669 The QtxPopupSelection class is used as back-end for getting value
670 of each parameter found in the rule by the expression parser.
672 For example, it can be used for the analyzing of the currently
673 selected objects and defining the values of the parameters used
674 in the rules syntax expression. Rules, in their turn, define
675 each action state - visibility, enabled and toggled state.
681 QtxPopupSelection::QtxPopupSelection()
690 QtxPopupSelection::~QtxPopupSelection()
695 \brief Get an option value.
696 \param optName option name
697 \return option value or empty string if option is not found
699 QString QtxPopupSelection::option( const QString& optName ) const
702 if ( myOptions.contains( optName ) )
703 opt = myOptions[optName];
708 \brief Set an option value.
709 \param optName option name
710 \param opt option value
712 void QtxPopupSelection::setOption( const QString& optName, const QString& opt )
714 myOptions.insert( optName, opt );
717 QtxPopupMgr* QtxPopupSelection::popupMgr() const
722 void QtxPopupSelection::setPopupMgr( QtxPopupMgr* pm )
728 \brief Get the parameter value.
729 \param str parameter name
730 \return parameter value
732 QVariant QtxPopupSelection::parameter( const QString& str ) const
734 if ( str == selCountParam() )
736 else if ( str.startsWith( equalityParam() ) )
738 QtxEvalSetSets::ValueSet set;
739 QString par = str.mid( equalityParam().length() );
741 QtxPopupMgr* pMgr = popupMgr();
742 for ( int i = 0; i < (int)count(); i++ )
744 QVariant v = pMgr ? pMgr->parameter( par, i ) : parameter( i, par );
746 QtxEvalSetSets::add( set, v );
757 \brief Get symbol which detects the name of the parameter list.
758 \return equality symbol (by default, "$")
760 QString QtxPopupSelection::equalityParam() const
762 QString str = option( "equality" );
769 \brief Get name of the parameter, specifing number of selected objects
770 \return parameter name (by default, "selcount")
772 QString QtxPopupSelection::selCountParam() const
774 QString str = option( "selcount" );
781 \fn int QtxPopupSelection::count() const;
782 \brief Get number of the selected objects.
783 \return nb of selected objects
787 \fn QVariant QtxPopupSelection::parameter( const int idx, const QString& name ) const;
788 \brief Get value of the parameter which is of list type
789 \param idx parameter index
790 \param name parameter name
791 \return parameter value