1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/
20 #include "QtxPopupMgr.h"
21 #include "QtxListOfOperations.h"
22 #include "QtxStdOperations.h"
23 #include "QtxAction.h"
25 #include <qpopupmenu.h>
26 #include <qdatetime.h>
30 \return value of global parameter (depending on whole selection, but not dependending on one object of selection)
31 \param str - name of parameter
33 By default, it returns count of selected objects ("selcount") and list of parameters ("$<name>")
35 QtxValue QtxPopupMgr::Selection::globalParam( const QString& str ) const
37 if( str==selCountParam() )
40 else if( str[0]==equality() )
42 QtxSets::ValueSet set;
43 QString par = str.mid( 1 );
45 for( int i=0, n=count(); i<n; i++ )
47 QtxValue v = param( i, par );
49 QtxSets::add( set, v );
61 \return symbole to detect name of parameter list
63 QChar QtxPopupMgr::Selection::equality() const
69 \return name of parameter for count of selected objects
71 QString QtxPopupMgr::Selection::selCountParam() const
73 return defSelCountParam();
77 \return default symbole to detect name of parameter list
79 QChar QtxPopupMgr::Selection::defEquality()
85 \return default name of parameter for count of selected objects
87 QString QtxPopupMgr::Selection::defSelCountParam()
95 \class QtxCacheSelection
97 Special selection class, that caches parameter values.
98 Every parameter during popup building is calculated only one time,
99 although it may be included to many rules. After calculation
100 it is stored in internal map
103 class QtxCacheSelection : public QtxPopupMgr::Selection
106 QtxCacheSelection( QtxPopupMgr::Selection* );
107 virtual ~QtxCacheSelection();
109 virtual int count() const;
110 virtual QtxValue param( const int, const QString& ) const;
111 virtual QtxValue globalParam( const QString& ) const;
114 typedef QMap< QString, QtxValue > CacheMap;
116 QtxPopupMgr::Selection* mySel;
117 CacheMap myParamCache;
122 \param sel - base selection used for parameter calculation
124 QtxCacheSelection::QtxCacheSelection( QtxPopupMgr::Selection* sel )
132 QtxCacheSelection::~QtxCacheSelection()
137 \return count of selected objects
139 int QtxCacheSelection::count() const
141 return mySel ? mySel->count() : 0;
145 Calculates and caches parameters.
146 Already calculated parameters are returned without calculation
147 \return parameter value
148 \param i - index of selected object
149 \param name - name of parameter
151 QtxValue QtxCacheSelection::param( const int i, const QString& name ) const
153 QString param_name = name + "#####" + QString::number( i );
154 if( myParamCache.contains( param_name ) )
155 return myParamCache[ param_name ];
160 v = mySel->param( i, name );
162 ( ( CacheMap& )myParamCache ).insert( param_name, v );
168 Calculates and caches global parameters.
169 Already calculated parameters are returned without calculation
170 \return parameter value
171 \param name - name of parameter
173 QtxValue QtxCacheSelection::globalParam( const QString& name ) const
175 if( myParamCache.contains( name ) )
176 return myParamCache[ name ];
181 v = mySel->globalParam( name );
183 ( ( CacheMap& )myParamCache ).insert( name, v );
193 \param mgr - popup manager
195 QtxPopupMgr::Operations::Operations( QtxPopupMgr* mgr )
200 aList.append( "every" );
201 aList.append( "any" );
202 aList.append( "onlyone" );
203 addOperations( aList );
205 myParser = new QtxParser( mgr->myOperations );
210 Deletes internal parser
212 QtxPopupMgr::Operations::~Operations()
218 \return priority of popup operation 'op'.
219 \param isBin indicate whether the operation is binary
221 int QtxPopupMgr::Operations::prior( const QString& op, bool isBin ) const
223 if( !isBin && ( op=="every" || op=="any" || op=="onlyone" ) )
226 return QtxStrings::prior( op, isBin );
231 Calculates result of operation
232 \return one of error states
233 \param op - name of operation
234 \param v1 - first operation argument (must be used also to store result)
235 \param v2 - second operation argument
237 QtxParser::Error QtxPopupMgr::Operations::calculate
238 ( const QString& op, QtxValue& v1, QtxValue& v2 ) const
245 else if( op=="onlyone" )
248 if( ind>=0 && ind<=2 )
250 QString val_name = op + "(" + v2.toString() + ")";
251 QtxParser::Error err = QtxParser::OK;
253 if( !myValues.contains( val_name ) )
255 myParser->setExpr( v2.toString() );
256 QStringList params, specific;
257 myParser->paramsList( params );
260 myPopupMgr->setParams( myParser, specific );
262 QtxPopupMgr::Selection* sel = myPopupMgr->myCurrentSelection;
264 int global_result = 0;
266 for( int i=0, n=sel->count(); i<n; i++ )
268 QStringList::const_iterator anIt = specific.begin(),
269 aLast = specific.end();
270 for( ; anIt!=aLast; anIt++ )
272 QtxValue v = sel->param( i, *anIt );
274 myParser->set( *anIt, v );
276 return QtxParser::InvalidToken;
279 QtxValue res = myParser->calculate();
280 err = myParser->lastError();
281 if( err==QtxParser::OK )
282 if( res.type()==QVariant::Bool )
286 if( ind==2 && global_result>1 )
290 return QtxParser::InvalidResult;
295 QtxValue& vv = ( QtxValue& )myValues[ val_name ];
296 vv = ( ind==0 && global_result==sel->count() ) ||
298 ( ind==2 && global_result==1 );
301 v2 = myValues[ val_name ];
306 return QtxStrings::calculate( op, v1, v2 );
310 Clears internal map of values
312 void QtxPopupMgr::Operations::clear()
327 QtxPopupMgr::QtxPopupMgr( QPopupMenu* popup, QObject* parent )
328 : QtxActionMenuMgr( popup, parent ),
329 myCurrentSelection( 0 )
337 QtxPopupMgr::~QtxPopupMgr()
342 Creates popup operations instance
344 void QtxPopupMgr::createOperations()
346 myOperations = new QtxListOfOperations;
347 myOperations->prepend( "logic", new QtxLogic(), 0 );
348 myOperations->prepend( "arithm", new QtxArithmetics(), 50 );
349 myOperations->append( "strings", new QtxStrings(), 100 );
350 myOperations->append( "sets", new QtxSets(), 150 );
351 myOperations->append( "custom", new Operations( this ), 200 );
355 Additional version of registerAction
356 \param act - action to be registered
357 \param visible - rule for visibility state
358 \param toggle - rule for toggle on state
359 \param id - proposed id (if it is less than 0, then id will be generated automatically)
361 int QtxPopupMgr::registerAction( QAction* act,
362 const QString& visible,
363 const QString& toggle,
366 int _id = QtxActionMenuMgr::registerAction( act, id );
367 setRule( _id, visible, true );
368 setRule( _id, toggle, false );
373 Removes action from internal map
374 \param id - action id
376 void QtxPopupMgr::unRegisterAction( const int id )
378 QAction* act = action( id );
380 myVisibility.remove( act );
381 myToggle.remove( act );
384 //QtxActionMenuMgr::unRegisterAction( id );
388 \return true if manager has rule for action
390 \param visibility - if it is true, then rule for "visibility" is checked, otherwise - for "toggle"
392 bool QtxPopupMgr::hasRule( QAction* act, bool visibility ) const
394 return map( visibility ).contains( act );
398 \return true if manager has rule for action
399 \param id - action id
400 \param visibility - if it is true, then rule for "visibility" is checked, otherwise - for "toggle"
402 bool QtxPopupMgr::hasRule( const int id, bool visibility ) const
404 return hasRule( action( id ), visibility );
408 Sets new rule for action
410 \param rule - string expression of rule
411 \param visibility - if it is true, then rule for "visibility" will be set, otherwise - for "toggle"
413 void QtxPopupMgr::setRule( QAction* act, const QString& rule, bool visibility )
415 if( !act || rule.isEmpty() )
418 if( !hasRule( act, visibility ) )
420 QtxParser* p = new QtxParser( myOperations, rule );
421 if( p->lastError()==QtxParser::OK )
422 map( visibility ).insert( act, p );
428 QtxParser* p = map( visibility )[ act ];
430 if( p->lastError()!=QtxParser::OK )
431 p->setExpr( QString() );
436 Sets new rule for action
437 \param id - action id
438 \param rule - string expression of rule
439 \param visibility - if it is true, then rule for "visibility" will be set, otherwise - for "toggle"
441 void QtxPopupMgr::setRule( const int id, const QString& rule, bool visibility )
443 setRule( action( id ), rule, visibility );
447 \return true if parser has finished work without errors
450 bool result( QtxParser* p )
455 QtxValue vv = p->calculate();
456 res = p->lastError()==QtxParser::OK &&
457 ( ( vv.type()==QVariant::Int && vv.toInt()!=0 ) ||
458 ( vv.type()==QVariant::Bool && vv.toBool() ) );
464 Fills parser parameters with help of Selection::globalParam() method
466 \param specific - list will be filled with names of parameters depending on selection objects (not global)
468 void QtxPopupMgr::setParams( QtxParser* p, QStringList& specific ) const
470 if( !p || !myCurrentSelection )
475 p->paramsList( params );
476 QStringList::const_iterator anIt = params.begin(),
477 aLast = params.end();
478 for( ; anIt!=aLast; anIt++ )
480 QtxValue v = myCurrentSelection->globalParam( *anIt );
484 specific.append( *anIt );
489 \return true if 'v1'<'v2'
490 This function can work with many types of values
492 bool operator<( const QtxValue& v1, const QtxValue& v2 )
494 QVariant::Type t1 = v1.type(), t2 = v2.type();
500 return v1.toInt() < v2.toInt();
502 case QVariant::Double:
503 return v1.toDouble() < v2.toDouble();
505 case QVariant::CString:
506 case QVariant::String:
507 return v1.toString() < v2.toString();
509 case QVariant::StringList:
512 const QValueList<QtxValue>& aList1 = v1.toList(), aList2 = v2.toList();
513 QValueList<QtxValue>::const_iterator
514 anIt1 = aList1.begin(), aLast1 = aList1.end(),
515 anIt2 = aList2.begin(), aLast2 = aList2.end();
516 for( ; anIt1!=aLast1 && anIt2!=aLast2; anIt1++, anIt2++ )
517 if( (*anIt1)!=(*anIt2) )
518 return (*anIt1)<(*anIt2);
520 return anIt1==aLast1 && anIt2!=aLast2;
524 return v1.toString()<v2.toString();
532 \return true if rule of action is satisfied on current selection
534 \param visibility - what rule is checked: for visibility(true) or for toggle(false)
536 bool QtxPopupMgr::isSatisfied( QAction* act, bool visibility ) const
538 QString menu = act->menuText();
544 if( hasRule( act, visibility ) )
546 QtxParser* p = map( visibility )[ act ];
547 QStringList specific;
549 ( ( Operations* )myOperations->operations( "custom" ) )->clear();
551 setParams( p, specific );
553 QMap<QValueList<QtxValue>,int> aCorteges;
554 QValueList<QtxValue> c;
556 if( specific.count()>0 )
557 if( myCurrentSelection )
561 for( int i=0, n=myCurrentSelection->count(); i<n && !res; i++ )
563 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
565 for( ; anIt1!=aLast1; anIt1++ )
566 c.append( myCurrentSelection->param( i, *anIt1 ) );
567 aCorteges.insert( c, 0 );
570 //qDebug( QString( "%1 corteges" ).arg( aCorteges.count() ) );
571 QMap<QValueList<QtxValue>,int>::const_iterator anIt = aCorteges.begin(), aLast = aCorteges.end();
572 for( ; anIt!=aLast; anIt++ )
574 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
575 const QValueList<QtxValue>& aCortege = anIt.key();
576 QValueList<QtxValue>::const_iterator anIt2 = aCortege.begin();
577 for( ; anIt1!=aLast1; anIt1++, anIt2++ )
578 p->set( *anIt1, *anIt2 );
579 res = res || result( p );
583 for( int i=0, n=myCurrentSelection->count(); i<n && !res; i++ )
585 QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
586 for( ; anIt1!=aLast1; anIt1++ )
587 p->set( *anIt1, myCurrentSelection->param( i, *anIt1 ) );
588 res = res || result( p );
601 \return true if item corresponding to action is visible
602 \param actId - action id
603 \param place - index of place
605 bool QtxPopupMgr::isVisible( const int actId, const int place ) const
607 bool res = QtxActionMenuMgr::isVisible( actId, place );
608 QAction* act = action( actId );
609 if( hasRule( act, true ) )
610 res = res && isSatisfied( act, true );
615 Updates popup according to selection
616 \param p - popup menu
617 \param sel - selection
619 void QtxPopupMgr::updatePopup( QPopupMenu* p, Selection* sel )
621 QTime t1 = QTime::currentTime();
626 myCurrentSelection = new QtxCacheSelection( sel );
627 RulesMap::iterator anIt = myToggle.begin(),
628 aLast = myToggle.end();
629 for( ; anIt!=aLast; anIt++ )
630 if( anIt.key()->isToggleAction() && hasRule( anIt.key(), false ) )
631 anIt.key()->setOn( isSatisfied( anIt.key(), false ) );
633 setWidget( ( QWidget* )p );
635 QTime t2 = QTime::currentTime();
636 qDebug( QString( "update popup time = %1 msecs" ).arg( t1.msecsTo( t2 ) ) );
637 qDebug( QString( "number of objects = %1" ).arg( myCurrentSelection->count() ) );
639 delete myCurrentSelection;
643 \return reference to map of rules
644 \param visibility - type of map: visibility of toggle
646 QtxPopupMgr::RulesMap& QtxPopupMgr::map( bool visibility ) const
648 return ( RulesMap& )( visibility ? myVisibility : myToggle );
652 Loads actions description from file
653 \param fname - name of file
654 \param r - reader of file
655 \return true on success
657 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
659 PopupCreator cr( &r, this );
660 return r.read( fname, cr );
668 \param r - menu reader
669 \param mgr - menu manager
671 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
673 : QtxActionMgr::Creator( r ),
680 */QtxPopupMgr::PopupCreator::~PopupCreator()
686 Appends new menu items
687 \param tag - tag of item
688 \param subMenu - it has submenu
689 \param attr - list of attributes
690 \param pId - id of action corresponding to parent item
692 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
693 const ItemAttributes& attr, const int pId )
695 if( !myMgr || !reader() )
698 QString label = reader()->option( "label", "label" ),
699 id = reader()->option( "id", "id" ),
700 pos = reader()->option( "pos", "pos" ),
701 group = reader()->option( "group", "group" ),
702 tooltip = reader()->option( "tooltip", "tooltip" ),
703 sep = reader()->option( "separator", "separator" ),
704 accel = reader()->option( "accel", "accel" ),
705 icon = reader()->option( "icon", "icon" ),
706 toggle = reader()->option( "toggle", "toggle" );
708 int res = -1, actId = intValue( attr, id, -1 );;
710 res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
712 res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
713 else //if( !myMgr->contains( actId ) )
715 QPixmap pix; QIconSet set;
716 QString name = strValue( attr, icon );
717 if( !name.isEmpty() )
719 if( loadPixmap( name, pix ) )
720 set = QIconSet( pix );
723 QString actLabel = strValue( attr, label );
724 QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
725 QKeySequence( strValue( attr, accel ) ),
727 newAct->setToolTip( strValue( attr, tooltip ) );
728 QString toggleact = strValue( attr, toggle );
729 bool isToggle = !toggleact.isEmpty();
730 newAct->setToggleAction( isToggle );
731 newAct->setOn( toggleact.lower()=="true" );
734 int aid = myMgr->registerAction( newAct, visibleRule( attr ),
735 isToggle ? toggleRule( attr ) : QString::null,
737 res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
744 \return visibility rule by attributes
745 Default implementation is empty
747 QString QtxPopupMgr::PopupCreator::visibleRule( const ItemAttributes& ) const
749 return QString::null;
753 \return toggle rule by attributes
754 Default implementation is empty
756 QString QtxPopupMgr::PopupCreator::toggleRule( const ItemAttributes& ) const
758 return QString::null;