1 // Copyright (C) 2007-2016 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 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
36 \brief Used for comparing of two QVariant values.
37 \param v1 first argument for comparison
38 \param v2 second argument for comparison
39 \return \c true if \a v1 less than \a v2
41 bool operator<( const QVariant& v1, const QVariant& v2 )
43 QVariant::Type t1 = v1.type(), t2 = v2.type();
49 return v1.toInt() < v2.toInt();
50 case QVariant::Double:
51 return v1.toDouble() < v2.toDouble();
52 case QVariant::String:
53 return v1.toString() < v2.toString();
54 case QVariant::StringList:
57 const QList<QVariant>& aList1 = v1.toList(), aList2 = v2.toList();
58 QList<QVariant>::const_iterator anIt1 = aList1.begin(), aLast1 = aList1.end(),
59 anIt2 = aList2.begin(), aLast2 = aList2.end();
60 for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ )
62 if ( (*anIt1) != (*anIt2) )
63 return (*anIt1) < (*anIt2);
65 return anIt1 == aLast1 && anIt2 != aLast2;
68 return v1.toString() < v2.toString();
76 bool operator<( const QList<QVariant>& v1, const QList<QVariant>& v2 )
78 QList<QVariant>::const_iterator anIt1 = v1.begin(), aLast1 = v1.end(),
79 anIt2 = v2.begin(), aLast2 = v2.end();
80 for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ )
82 if ( (*anIt1) != (*anIt2) )
83 return (*anIt1) < (*anIt2);
85 return anIt1 == aLast1 && anIt2 != aLast2;
88 #endif // QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
91 \class QtxPopupMgr::PopupCreator
93 \brief Popup menu actions creator.
95 Used by Reader to create actions by reading descriptions from the file
96 and fill in the action manager with the actions.
99 class QtxPopupMgr::PopupCreator : public QtxActionMgr::Creator
102 PopupCreator( QtxActionMgr::Reader*, QtxPopupMgr* );
103 virtual ~PopupCreator();
105 virtual int append( const QString&, const bool,
106 const ItemAttributes&, const int );
108 virtual QString rule( const ItemAttributes&,
109 const QtxPopupMgr::RuleType = VisibleRule ) const;
117 \param r menu action reader
118 \param mgr popup menu manager
120 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
122 : QtxActionMgr::Creator( r ),
130 QtxPopupMgr::PopupCreator::~PopupCreator()
135 \brief Create and append new action to the action manager.
136 \param tag item tag name
137 \param subMenu \c true if this item is submenu
138 \param attr attributes map
139 \param pId parent action ID
140 \return menu action ID
142 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
143 const ItemAttributes& attr, const int pId )
145 if ( !myMgr || !reader() )
148 QString label = reader()->option( "label", "label" ),
149 id = reader()->option( "id", "id" ),
150 pos = reader()->option( "pos", "pos" ),
151 group = reader()->option( "group", "group" ),
152 tooltip = reader()->option( "tooltip", "tooltip" ),
153 sep = reader()->option( "separator", "separator" ),
154 accel = reader()->option( "accel", "accel" ),
155 icon = reader()->option( "icon", "icon" ),
156 toggle = reader()->option( "toggle", "toggle" );
158 QtxActionMenuMgr* mgr = myMgr;
160 int res = -1, actId = intValue( attr, id, -1 );;
162 res = mgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
163 else if ( tag == sep )
164 res = mgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
169 QString name = strValue( attr, icon );
170 if( !name.isEmpty() )
172 if ( loadPixmap( name, pix ) )
176 QString actLabel = strValue( attr, label );
177 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
178 QKeySequence( strValue( attr, accel ) ),
180 newAct->setToolTip( strValue( attr, tooltip ) );
181 QString toggleact = strValue( attr, toggle );
182 bool isToggle = !toggleact.isEmpty();
183 newAct->setCheckable( isToggle );
184 newAct->setChecked( toggleact.toLower() == "true" );
187 int aid = mgr->registerAction( newAct, actId );
188 QString arule = rule( attr, QtxPopupMgr::VisibleRule );
189 if ( !arule.isEmpty() )
190 myMgr->setRule( newAct, arule, QtxPopupMgr::VisibleRule );
191 arule = rule( attr, QtxPopupMgr::EnableRule );
192 if ( !arule.isEmpty() )
193 myMgr->setRule( newAct, arule, QtxPopupMgr::EnableRule );
194 arule = rule( attr, QtxPopupMgr::ToggleRule );
195 if ( isToggle && !arule.isEmpty() )
196 myMgr->setRule( newAct, arule, QtxPopupMgr::ToggleRule );
197 res = mgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
204 \brief Get the rule for the menu item.
206 Default implementation returns empty rule.
208 \param attr attributes map
209 \param ruleType rule type (QtxPopupMgr::RuleType)
210 \return rule for the menu item corresponding to the rule type
212 QString QtxPopupMgr::PopupCreator::rule( const ItemAttributes& /*attr*/,
213 const QtxPopupMgr::RuleType /*ruleType*/ ) const
220 \brief Popup menu manager.
222 Menu manager allows using of set of action for automatic generating of
223 application context popup menu by reuquest and dynamic update of its
226 Use insert() methods to add menu items to the popup menu.
228 The visibility, enable and toggle state of the menu item is controlled
229 by the syntaxic rules, which can be set with setRule() methods.
230 The rules are parsed automatically with help of QtxEvalParser class.
232 QtxPopupSelection class is used as back-end for getting value of each
233 parameter found in the rule by the expression parser.
234 Use setSelection() and selection() to set/get the selection instance
235 for the popup menu manager.
237 Popup menu manager automatically optimizes the menu by removing
238 extra separators, hiding empty popup submenus etc.
243 \param object parent object
245 QtxPopupMgr::QtxPopupMgr( QObject* parent )
246 : QtxActionMenuMgr( 0, parent ),
253 \param popup popup menu
254 \param object parent object
256 QtxPopupMgr::QtxPopupMgr( QMenu* popup, QObject* parent )
257 : QtxActionMenuMgr( popup, parent ),
265 QtxPopupMgr::~QtxPopupMgr()
270 \brief Get popup menu.
273 QMenu* QtxPopupMgr::menu() const
275 return ::qobject_cast<QMenu*>( menuWidget() );
279 \brief Get popup menu.
280 \param menu popup menu
282 void QtxPopupMgr::setMenu( QMenu* menu )
284 setMenuWidget( menu );
288 \brief Get selection.
289 \return current selection object
291 QtxPopupSelection* QtxPopupMgr::selection() const
297 \brief Set selection.
298 \param sel new selection object
300 void QtxPopupMgr::setSelection( QtxPopupSelection* sel )
302 if ( mySelection == sel )
310 mySelection->setParent( this );
311 mySelection->setPopupMgr( this );
314 connect( mySelection, SIGNAL( destroyed( QObject* ) ),
315 this, SLOT( onSelectionDestroyed( QObject* ) ) );
317 QtxActionMgr::triggerUpdate();
321 \brief Register an action and return its identifier.
323 If \a id is less than 0, the identifier for the action is generated automatically.
324 If action with given \a id is already registered, it will be re-registered.
325 If required \a id is already in use, new identifier is generatied; in this case
326 returning value will different from required one.
328 \param act action to be registered
330 \param rule syntax rule
331 \param ruleType rule type (QtxPopupMgr::RuleType)
332 \return action ID (the same as \a id or generated one)
334 int QtxPopupMgr::registerAction( QAction* act, const int id, const QString& rule, const QtxPopupMgr::RuleType ruleType )
336 int _id = QtxActionMenuMgr::registerAction( act, id );
337 setRule( act, rule, ruleType );
342 \brief Unregister action from internal map.
345 void QtxPopupMgr::unRegisterAction( const int id )
347 QAction* a = action( id );
348 if ( myRules.contains( a ) )
350 for ( ExprMap::iterator it = myRules[a].begin(); it != myRules[a].end(); ++it )
357 QtxActionMenuMgr::unRegisterAction( id );
361 \brief Insert action to the popup menu manager.
363 \param pId parent menu action ID
364 \param rule syntax rule
365 \param ruleType rule type (QtxPopupMgr::RuleType)
368 int QtxPopupMgr::insertAction( const int id, const int pId, const QString& rule, const RuleType ruleType )
370 int res = QtxActionMenuMgr::insert( id, pId, -1 );
371 setRule( action( id ), rule, ruleType );
376 \brief Insert action to the popup menu manager.
378 \param pId parent menu action ID
379 \param rule syntax rule
380 \param ruleType rule type (QtxPopupMgr::RuleType)
383 int QtxPopupMgr::insertAction( QAction* a, const int pId, const QString& rule, const RuleType ruleType )
385 int res = QtxActionMenuMgr::insert( a, pId, -1 );
386 setRule( a, rule, ruleType );
391 \return true if action has rule of given type
395 bool QtxPopupMgr::hasRule( QAction* a, const RuleType t ) const
397 return a ? expression( a, t, false )!=0 : false;
401 \return true if action with given id has rule of given type
402 \param id - action id
405 bool QtxPopupMgr::hasRule( const int id, const RuleType t ) const
407 return hasRule( action( id ), t );
411 \brief Get rule of type \a type for the action \a a.
413 \param ruleType rule type (QtxPopupMgr::RuleType)
414 \return rule of required type
416 QString QtxPopupMgr::rule( QAction* a, const RuleType ruleType ) const
419 QtxEvalExpr* expr = expression( a, ruleType );
421 rule = expr->expression();
426 \brief Get rule of type \a type for the action \a id.
428 \param ruleType rule type (QtxPopupMgr::RuleType)
429 \return rule of required type
431 QString QtxPopupMgr::rule( const int id, const RuleType ruleType ) const
433 return rule( action( id ), ruleType );
437 \brief Set rule of type \a type for the action \a a.
440 \param ruleType rule type (QtxPopupMgr::RuleType)
441 \return rule of required type
443 void QtxPopupMgr::setRule( QAction* a, const QString& rule, const RuleType ruleType )
448 QtxEvalExpr* expr = expression( a, ruleType, true );
450 expr->setExpression( rule );
454 \brief Set rule of type \a type for the action \a id.
457 \param ruleType rule type (QtxPopupMgr::RuleType)
458 \return rule of required type
460 void QtxPopupMgr::setRule( const int id, const QString& rule, const RuleType ruleType )
462 setRule( action( id ), rule, ruleType );
466 \brief Calculate an expression.
467 \param p expression parser
468 \return \c true if parser has finished work without errors
470 bool QtxPopupMgr::result( QtxEvalParser* p ) const
475 QVariant vv = p->calculate();
476 res = p->error() == QtxEvalExpr::OK &&
477 ( ( vv.type() == QVariant::Int && vv.toInt() != 0 ) ||
478 ( vv.type() == QVariant::Bool && vv.toBool() ) );
484 \brief Fill the parser with parameters of the expression.
486 The values of the parameters are given from the selection object
489 \param p expression parser
490 \param returning list of parameters names which are not retrieved from the selection
493 void QtxPopupMgr::setParameters( QtxEvalParser* p, QStringList& specific ) const
495 if ( !p || !mySelection )
498 QStringList params = p->parameters();
499 for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
501 QVariant v = parameter( *it );
503 p->setParameter( *it, v );
505 specific.append( *it );
510 \brief Check the rule for the action.
512 \param ruleType rule type (QtxPopupMgr::RuleType)
513 \return \c true if current selection satisfies the action rule
515 bool QtxPopupMgr::isSatisfied( QAction* act, const RuleType ruleType ) const
520 QtxEvalExpr* exp = expression( act, ruleType );
526 QtxEvalParser* p = exp->parser();
528 QStringList specific;
529 p->clearParameters();
530 setParameters( p, specific );
532 QMap<QList<QVariant>, int> aCorteges;
533 if ( !specific.isEmpty() )
538 for ( int i = 0; i < mySelection->count() && !res; i++ )
541 for ( QStringList::const_iterator anIt1 = specific.begin(); anIt1 != specific.end(); ++anIt1 )
542 c.append( parameter( *anIt1, i ) );
543 aCorteges.insert( c, 0 );
545 for ( QMap<QList<QVariant>, int>::const_iterator anIt = aCorteges.begin(); anIt != aCorteges.end(); ++anIt )
547 const QList<QVariant>& aCortege = anIt.key();
548 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
549 QList<QVariant>::const_iterator anIt2 = aCortege.begin();
550 for ( ; anIt1 != aLast1; anIt1++, anIt2++ )
551 p->setParameter( *anIt1, *anIt2 );
552 res = res || result( p );
565 \brief Check if the menu item is visible.
567 \param place some parent action ID
568 \return \c true if the action is visible
570 bool QtxPopupMgr::isVisible( const int id, const int place ) const
572 return QtxActionMenuMgr::isVisible( id, place ) && ( !hasRule( id ) || isSatisfied( action( id ) ) );
576 \brief Perform internal update of the popup menu according
577 to the current selection.
579 void QtxPopupMgr::internalUpdate()
583 for ( RuleMap::iterator it = myRules.begin(); it != myRules.end(); ++it )
585 ExprMap& map = it.value();
586 if ( it.key()->isCheckable() && map.contains( ToggleRule ) &&
587 !map[ToggleRule]->expression().isEmpty() )
588 it.key()->setChecked( isSatisfied( it.key(), ToggleRule ) );
591 QtxActionMenuMgr::internalUpdate();
597 \brief Update popup according to the current selection.
599 void QtxPopupMgr::updateMenu()
605 \brief Get an syntax expression for the action according to the specified rule type.
607 \param ruleType rule type (QtxPopupMgr::RuleType)
608 \param create if \c true an expression does not exist, create it
609 \return syntax expression
611 QtxEvalExpr* QtxPopupMgr::expression( QAction* a, const RuleType ruleType, const bool create ) const
613 QtxEvalExpr* res = 0;
615 QtxPopupMgr* that = (QtxPopupMgr*)this;
616 RuleMap& ruleMap = that->myRules;
617 if ( !ruleMap.contains( a ) && create )
618 ruleMap.insert( a, ExprMap() );
620 if ( ruleMap.contains( a ) )
622 ExprMap& exprMap = ruleMap[a];
623 if ( exprMap.contains( ruleType ) )
624 res = exprMap[ruleType];
626 exprMap.insert( ruleType, res = new QtxEvalExpr() );
633 \brief Load actions description from the file.
634 \param fname file name
635 \param r action reader
636 \return \c true on success and \c false on error
638 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
640 PopupCreator cr( &r, this );
641 return r.read( fname, cr );
645 \brief Get the specified parameter value.
646 \param name parameter name
647 \param idx additional index used when used parameters with same names
648 \return parameter value
651 QVariant QtxPopupMgr::parameter( const QString& name, const int idx ) const
654 QString cacheName = name + ( idx >= 0 ? QString( "_%1" ).arg( idx ) : QString() );
655 if ( myCache.contains( cacheName ) )
656 val = myCache[cacheName];
660 val = idx < 0 ? selection()->parameter( name ) :
661 selection()->parameter( idx, name );
664 QtxPopupMgr* that = (QtxPopupMgr*)this;
665 that->myCache.insert( cacheName, val );
672 \brief Called when selection is destroyed.
674 Prevents crashes when the selection object is destroyed outside the
677 \param o selection object being destroyed
679 void QtxPopupMgr::onSelectionDestroyed( QObject* o )
681 if ( o == mySelection )
686 \class QtxPopupSelection
687 \brief This class is a part of the popup menu management system.
689 The QtxPopupSelection class is used as back-end for getting value
690 of each parameter found in the rule by the expression parser.
692 For example, it can be used for the analyzing of the currently
693 selected objects and defining the values of the parameters used
694 in the rules syntax expression. Rules, in their turn, define
695 each action state - visibility, enabled and toggled state.
701 QtxPopupSelection::QtxPopupSelection()
710 QtxPopupSelection::~QtxPopupSelection()
715 \brief Get an option value.
716 \param optName option name
717 \return option value or empty string if option is not found
719 QString QtxPopupSelection::option( const QString& optName ) const
722 if ( myOptions.contains( optName ) )
723 opt = myOptions[optName];
728 \brief Set an option value.
729 \param optName option name
730 \param opt option value
732 void QtxPopupSelection::setOption( const QString& optName, const QString& opt )
734 myOptions.insert( optName, opt );
737 QtxPopupMgr* QtxPopupSelection::popupMgr() const
742 void QtxPopupSelection::setPopupMgr( QtxPopupMgr* pm )
748 \brief Get the parameter value.
749 \param str parameter name
750 \return parameter value
752 QVariant QtxPopupSelection::parameter( const QString& str ) const
754 if ( str == selCountParam() )
756 else if ( str.startsWith( equalityParam() ) )
758 QtxEvalSetSets::ValueSet set;
759 QString par = str.mid( equalityParam().length() );
761 QtxPopupMgr* pMgr = popupMgr();
762 for ( int i = 0; i < (int)count(); i++ )
764 QVariant v = pMgr ? pMgr->parameter( par, i ) : parameter( i, par );
766 QtxEvalSetSets::add( set, v );
777 \brief Get symbol which detects the name of the parameter list.
778 \return equality symbol (by default, "$")
780 QString QtxPopupSelection::equalityParam() const
782 QString str = option( "equality" );
789 \brief Get name of the parameter, specifing number of selected objects
790 \return parameter name (by default, "selcount")
792 QString QtxPopupSelection::selCountParam() const
794 QString str = option( "selcount" );
801 \fn int QtxPopupSelection::count() const;
802 \brief Get number of the selected objects.
803 \return nb of selected objects
807 \fn QVariant QtxPopupSelection::parameter( const int idx, const QString& name ) const;
808 \brief Get value of the parameter which is of list type
809 \param idx parameter index
810 \param name parameter name
811 \return parameter value