Salome HOME
PAL10670 - it is necessary to increase speed of selection and popup construction...
[modules/gui.git] / src / Qtx / QtxPopupMgr.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
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.
7 // 
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/
18 //
19
20 #include "QtxPopupMgr.h"
21 #include "QtxListOfOperations.h"
22 #include "QtxStdOperations.h"
23 #include "QtxAction.h"
24
25 #include <qpopupmenu.h>
26 #include <qdatetime.h>
27
28 //================================================================
29 // Function : 
30 // Purpose  : 
31 //================================================================
32 QtxValue QtxPopupMgr::Selection::globalParam( const QString& str ) const
33 {
34   if( str==selCountParam() )
35     return count();
36
37   else if( str[0]==equality() )
38   {
39     QtxSets::ValueSet set;
40     QString par = str.mid( 1 );
41
42     for( int i=0, n=count(); i<n; i++ )
43     {
44       QtxValue v = param( i, par );
45       if( v.isValid() )
46         QtxSets::add( set, v );
47       else
48         return QtxValue();      
49     }
50     return set;
51   }
52
53   else
54     return QtxValue();
55 }
56
57 //================================================================
58 // Function : 
59 // Purpose  : 
60 //================================================================
61 QChar QtxPopupMgr::Selection::equality() const
62 {
63   return defEquality();
64 }
65
66 //================================================================
67 // Function : 
68 // Purpose  : 
69 //================================================================
70 QString QtxPopupMgr::Selection::selCountParam() const
71 {
72   return defSelCountParam();
73 }
74
75 //================================================================
76 // Function : 
77 // Purpose  : 
78 //================================================================
79 QChar QtxPopupMgr::Selection::defEquality()
80 {
81     return '$';
82 }
83
84 //================================================================
85 // Function : 
86 // Purpose  : 
87 //================================================================
88 QString QtxPopupMgr::Selection::defSelCountParam()
89 {
90     return "selcount";
91 }
92
93
94
95
96
97 //================================================================
98 // Class : 
99 // Purpose  : 
100 //================================================================
101 class QtxCacheSelection : public QtxPopupMgr::Selection
102 {
103 public:
104   QtxCacheSelection( QtxPopupMgr::Selection* );
105   virtual ~QtxCacheSelection();
106
107   virtual int      count() const;
108   virtual QtxValue param( const int, const QString& ) const;
109   virtual QtxValue globalParam( const QString& ) const;
110
111 private:
112   typedef QMap< QString, QtxValue >  CacheMap;
113
114   QtxPopupMgr::Selection*    mySel;
115   CacheMap                   myParamCache;
116 };
117
118 //================================================================
119 // Function : 
120 // Purpose  : 
121 //================================================================
122 QtxCacheSelection::QtxCacheSelection( QtxPopupMgr::Selection* sel )
123 : mySel( sel )
124 {
125 }
126
127 //================================================================
128 // Function : 
129 // Purpose  : 
130 //================================================================
131 QtxCacheSelection::~QtxCacheSelection()
132 {
133 }
134
135 //================================================================
136 // Function : 
137 // Purpose  : 
138 //================================================================
139 int QtxCacheSelection::count() const
140 {
141   return mySel ? mySel->count() : 0;
142 }
143
144 //================================================================
145 // Function : 
146 // Purpose  : 
147 //================================================================
148 QtxValue QtxCacheSelection::param( const int i, const QString& name ) const
149 {
150   QString param_name = name + "#####" + QString::number( i );
151   if( myParamCache.contains( param_name ) )
152     return myParamCache[ param_name ];
153   else
154   {
155     QtxValue v;
156     if( mySel )
157       v = mySel->param( i, name );
158     if( v.isValid() )
159       ( ( CacheMap& )myParamCache ).insert( param_name, v );
160     return v;
161   }
162 }
163
164 //================================================================
165 // Function : 
166 // Purpose  : 
167 //================================================================
168 QtxValue QtxCacheSelection::globalParam( const QString& name ) const
169 {
170   if( myParamCache.contains( name ) )
171     return myParamCache[ name ];
172   else
173   {
174     QtxValue v;
175     if( mySel )
176       v = mySel->globalParam( name );
177     if( v.isValid() )
178       ( ( CacheMap& )myParamCache ).insert( name, v );
179     return v;
180   }
181 }
182
183
184
185
186
187 //================================================================
188 // Function : 
189 // Purpose  : 
190 //================================================================
191 QtxPopupMgr::Operations::Operations( QtxPopupMgr* mgr )
192 : QtxStrings(),
193   myPopupMgr( mgr )
194 {
195     QStringList aList;
196     aList.append( "every" );
197     aList.append( "any" );
198     aList.append( "onlyone" );
199     addOperations( aList );
200
201     myParser = new QtxParser( mgr->myOperations );
202 }
203
204 //================================================================
205 // Function : 
206 // Purpose  : 
207 //================================================================
208 QtxPopupMgr::Operations::~Operations()
209 {
210     delete myParser;
211 }
212
213 //================================================================
214 // Function : 
215 // Purpose  : 
216 //================================================================
217 int QtxPopupMgr::Operations::prior( const QString& op, bool isBin ) const
218 {
219     if( !isBin && ( op=="every" || op=="any" || op=="onlyone" ) )
220         return 1;
221     else
222         return QtxStrings::prior( op, isBin );
223
224 }
225
226 //================================================================
227 // Function : 
228 // Purpose  : 
229 //================================================================
230 QtxParser::Error QtxPopupMgr::Operations::calculate
231     ( const QString& op, QtxValue& v1, QtxValue& v2 ) const
232 {
233     int ind = -1;
234     if( op=="every" )
235         ind = 0;
236     else if( op=="any" )
237         ind = 1;
238     else if( op=="onlyone" )
239         ind = 2;
240
241     if( ind>=0 && ind<=2 )
242     {
243         QString val_name = op + "(" + v2.toString() + ")";
244         QtxParser::Error err = QtxParser::OK;
245
246         if( !myValues.contains( val_name ) )
247         {
248             myParser->setExpr( v2.toString() );
249             QStringList params, specific;
250             myParser->paramsList( params );
251
252             myParser->clear();
253             myPopupMgr->setParams( myParser, specific );
254
255             QtxPopupMgr::Selection* sel = myPopupMgr->myCurrentSelection;
256
257             int global_result = 0;
258             if( sel )
259                 for( int i=0, n=sel->count(); i<n; i++ )
260                 {
261                     QStringList::const_iterator anIt = specific.begin(),
262                                                 aLast = specific.end();
263                     for( ; anIt!=aLast; anIt++ )
264                     {
265                         QtxValue v = sel->param( i, *anIt );
266                         if( v.isValid() )
267                             myParser->set( *anIt, v );
268                         else
269                             return QtxParser::InvalidToken;
270                     }
271
272                     QtxValue res = myParser->calculate();
273                     err = myParser->lastError();
274                     if( err==QtxParser::OK )
275                         if( res.type()==QVariant::Bool )
276                         {
277                             if( res.toBool() )
278                                 global_result++;
279                             if( ind==2 && global_result>1 )
280                                 break;
281                         }
282                         else
283                             return QtxParser::InvalidResult;
284                     else
285                         return err;
286                 }
287
288             QtxValue& vv = ( QtxValue&  )myValues[ val_name ];
289             vv = ( ind==0 && global_result==sel->count() ) ||
290                  ( ind==1 ) ||
291                  ( ind==2 && global_result==1 );
292         }
293
294         v2 = myValues[ val_name ];
295
296         return err;
297     }
298     else
299         return QtxStrings::calculate( op, v1, v2 );
300 }
301
302 //================================================================
303 // Function : 
304 // Purpose  : 
305 //================================================================
306 void QtxPopupMgr::Operations::clear()
307 {
308     myValues.clear();
309 }
310
311
312
313
314
315
316
317
318
319 //================================================================
320 // Function : 
321 // Purpose  : 
322 //================================================================
323 QtxPopupMgr::QtxPopupMgr( QPopupMenu* popup, QObject* parent )
324 : QtxActionMenuMgr( popup, parent ),
325   myCurrentSelection( 0 )
326 {
327     createOperations();
328 }
329
330 //================================================================
331 // Function : 
332 // Purpose  : 
333 //================================================================
334 QtxPopupMgr::~QtxPopupMgr()
335 {
336 }
337
338 //================================================================
339 // Function : 
340 // Purpose  : 
341 //================================================================
342 void QtxPopupMgr::createOperations()
343 {
344     myOperations = new QtxListOfOperations;
345     myOperations->prepend( "logic",   new QtxLogic(),           0 );
346     myOperations->prepend( "arithm",  new QtxArithmetics(),    50 );
347     myOperations->append( "strings", new QtxStrings(),       100 );
348     myOperations->append( "sets",    new QtxSets(),          150 );
349     myOperations->append( "custom",  new Operations( this ), 200 );
350 }
351
352 //================================================================
353 // Function : 
354 // Purpose  : 
355 //================================================================
356 int QtxPopupMgr::registerAction( QAction* act,
357                                  const QString& visible,
358                                  const QString& toggle,
359                                  const int id )
360 {
361     int _id = QtxActionMenuMgr::registerAction( act, id );
362     setRule( _id, visible, true );
363     setRule( _id, toggle, false );
364     return _id;
365 }
366
367 //================================================================
368 // Function : 
369 // Purpose  : 
370 //================================================================
371 void QtxPopupMgr::unRegisterAction( const int id )
372 {
373     QAction* act = action( id );
374
375     myVisibility.remove( act );
376     myToggle.remove( act );
377
378     remove( id );
379     //QtxActionMenuMgr::unRegisterAction( id );
380 }
381
382 //================================================================
383 // Function : 
384 // Purpose  : 
385 //================================================================
386 bool QtxPopupMgr::hasRule( QAction* act, bool visibility ) const
387 {
388     return map( visibility ).contains( act );
389 }
390
391 //================================================================
392 // Function : 
393 // Purpose  : 
394 //================================================================
395 bool QtxPopupMgr::hasRule( const int id, bool visibility ) const
396 {
397     return hasRule( action( id ), visibility );
398 }
399
400 //================================================================
401 // Function : 
402 // Purpose  : 
403 //================================================================
404 void QtxPopupMgr::setRule( QAction* act, const QString& rule, bool visibility )
405 {
406     if( !act || rule.isEmpty() )
407         return;
408
409     if( !hasRule( act, visibility ) )
410     {
411         QtxParser* p = new QtxParser( myOperations, rule );
412         if( p->lastError()==QtxParser::OK )
413             map( visibility ).insert( act, p );
414         else
415             delete p;
416     }
417     else
418     {
419         QtxParser* p = map( visibility )[ act ];
420         p->setExpr( rule );
421         if( p->lastError()!=QtxParser::OK )
422             p->setExpr( QString() );
423     }
424 }
425
426 //================================================================
427 // Function : 
428 // Purpose  : 
429 //================================================================
430 void QtxPopupMgr::setRule( const int id, const QString& rule, bool visibility )
431 {
432     setRule( action( id ), rule, visibility );
433 }
434
435 //================================================================
436 // Function : 
437 // Purpose  : 
438 //================================================================
439 bool result( QtxParser* p )
440 {
441     bool res = false;
442     if( p )
443     {
444         QtxValue vv = p->calculate();
445         res = p->lastError()==QtxParser::OK &&
446             ( ( vv.type()==QVariant::Int && vv.toInt()!=0 ) ||
447               ( vv.type()==QVariant::Bool && vv.toBool() ) );
448     }
449     return res;
450 }
451
452 //================================================================
453 // Function : 
454 // Purpose  : 
455 //================================================================
456 void QtxPopupMgr::setParams( QtxParser* p, QStringList& specific ) const
457 {
458     if( !p || !myCurrentSelection )
459         return;
460
461     QStringList params;
462
463     p->paramsList( params );
464     QStringList::const_iterator anIt = params.begin(),
465                                 aLast = params.end();
466     for( ; anIt!=aLast; anIt++ )
467     {
468       QtxValue v = myCurrentSelection->globalParam( *anIt );
469       if( v.isValid() )
470         p->set( *anIt, v );
471       else
472         specific.append( *anIt );
473     }
474 }
475
476 bool operator<( const QtxValue& v1, const QtxValue& v2 )
477 {
478   QVariant::Type t1 = v1.type(), t2 = v2.type();
479   if( t1==t2 )
480   {
481     switch( t1 )
482     {
483     case QVariant::Int:
484       return v1.toInt() < v2.toInt();
485       
486     case QVariant::Double:
487       return v1.toDouble() < v2.toDouble();
488
489     case QVariant::CString:
490     case QVariant::String:
491       return v1.toString() < v2.toString();
492
493     case QVariant::StringList:
494     case QVariant::List:
495     {
496       const QValueList<QtxValue>& aList1 = v1.toList(), aList2 = v2.toList();
497       QValueList<QtxValue>::const_iterator
498         anIt1 = aList1.begin(), aLast1 = aList1.end(),
499         anIt2 = aList2.begin(), aLast2 = aList2.end();
500       for( ; anIt1!=aLast1 && anIt2!=aLast2; anIt1++, anIt2++ )
501         if( (*anIt1)!=(*anIt2) )
502           return (*anIt1)<(*anIt2);
503
504       return anIt1==aLast1 && anIt2!=aLast2;
505     }
506
507     default:
508       return v1.toString()<v2.toString();
509     }
510   }
511   else
512     return t1<t2;
513 }
514
515 //================================================================
516 // Function : 
517 // Purpose  : 
518 //================================================================
519 bool QtxPopupMgr::isSatisfied( QAction* act, bool visibility ) const
520 {
521   QString menu = act->menuText();
522
523   bool res = false;
524   if( !act )
525     return res;
526
527   if( hasRule( act, visibility ) )
528   {
529     QtxParser* p = map( visibility )[ act ];
530     QStringList specific;
531     p->clear();
532     ( ( Operations* )myOperations->operations( "custom" ) )->clear();
533
534     setParams( p, specific );
535
536     QMap<QValueList<QtxValue>,int> aCorteges;
537     QValueList<QtxValue> c;
538
539     if( specific.count()>0 )
540       if( myCurrentSelection )
541       {
542         res = false;
543
544         for( int i=0, n=myCurrentSelection->count(); i<n && !res; i++ )
545         {
546           QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
547           c.clear();
548           for( ; anIt1!=aLast1; anIt1++ )
549             c.append( myCurrentSelection->param( i, *anIt1 ) );
550           aCorteges.insert( c, 0 );
551         }
552         
553         //qDebug( QString( "%1 corteges" ).arg( aCorteges.count() ) );
554         QMap<QValueList<QtxValue>,int>::const_iterator anIt = aCorteges.begin(), aLast = aCorteges.end();
555         for( ; anIt!=aLast; anIt++ )
556         {
557           QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
558           const QValueList<QtxValue>& aCortege = anIt.key();
559           QValueList<QtxValue>::const_iterator anIt2 = aCortege.begin();
560           for( ; anIt1!=aLast1; anIt1++, anIt2++ )
561             p->set( *anIt1, *anIt2 );
562           res = res || result( p );
563         }
564
565         /*
566         for( int i=0, n=myCurrentSelection->count(); i<n && !res; i++ )
567         {
568           QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end();
569           for( ; anIt1!=aLast1; anIt1++ )
570             p->set( *anIt1, myCurrentSelection->param( i, *anIt1 ) );
571           res = res || result( p );
572         }*/
573       }
574       else
575         res = false;
576     else
577       res = result( p );
578   }
579
580   return res;
581 }
582
583 //================================================================
584 // Function : 
585 // Purpose  : 
586 //================================================================
587 bool QtxPopupMgr::isVisible( const int actId, const int place ) const
588 {
589     bool res = QtxActionMenuMgr::isVisible( actId, place );
590     QAction* act = action( actId );
591     if( hasRule( act, true ) )
592         res = res && isSatisfied( act, true );
593     return res;
594 }
595
596 //================================================================
597 // Function : 
598 // Purpose  : 
599 //================================================================
600 void QtxPopupMgr::updatePopup( QPopupMenu* p, Selection* sel )
601 {
602   QTime t1 = QTime::currentTime();
603
604   if( !p || !sel )
605     return;
606
607   myCurrentSelection = new QtxCacheSelection( sel );
608   RulesMap::iterator anIt = myToggle.begin(),
609                             aLast = myToggle.end();
610   for( ; anIt!=aLast; anIt++ )
611     if( anIt.key()->isToggleAction() && hasRule( anIt.key(), false ) )
612       anIt.key()->setOn( isSatisfied( anIt.key(), false ) );
613
614   setWidget( ( QWidget* )p );
615   updateMenu();
616   QTime t2 = QTime::currentTime();
617   qDebug( QString( "update popup time = %1 msecs" ).arg( t1.msecsTo( t2 ) ) );
618   qDebug( QString( "number of objects = %1" ).arg( myCurrentSelection->count() ) );
619
620   delete myCurrentSelection;
621 }
622
623 //================================================================
624 // Function : 
625 // Purpose  : 
626 //================================================================
627 QtxPopupMgr::RulesMap& QtxPopupMgr::map( bool visibility ) const
628 {
629     return ( RulesMap& )( visibility ? myVisibility : myToggle );
630 }
631
632 //================================================================
633 // Function : 
634 // Purpose  : 
635 //================================================================
636 bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r )
637 {
638   PopupCreator cr( &r, this );
639   return r.read( fname, cr );
640 }
641
642
643
644
645 //================================================================
646 // Function : 
647 // Purpose  : 
648 //================================================================
649 QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r,
650                                          QtxPopupMgr* mgr )
651 : QtxActionMgr::Creator( r ),
652   myMgr( mgr )
653 {
654 }
655
656 //================================================================
657 // Function : 
658 // Purpose  : 
659 //================================================================
660 QtxPopupMgr::PopupCreator::~PopupCreator()
661 {
662 }
663
664 //================================================================
665 // Function : 
666 // Purpose  : 
667 //================================================================
668 int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu,
669                                        const ItemAttributes& attr, const int pId )
670 {
671   if( !myMgr || !reader() )
672     return -1;
673
674   QString label   = reader()->option( "label",     "label"     ),
675           id      = reader()->option( "id",        "id"        ),
676           pos     = reader()->option( "pos",       "pos"       ),
677           group   = reader()->option( "group",     "group"     ),
678           tooltip = reader()->option( "tooltip",   "tooltip"   ),
679           sep     = reader()->option( "separator", "separator" ),
680           accel   = reader()->option( "accel",     "accel"     ),
681           icon    = reader()->option( "icon",      "icon"      ),
682           toggle  = reader()->option( "toggle",    "toggle"    );
683
684   int res = -1, actId = intValue( attr, id, -1 );;
685   if( subMenu )
686     res = myMgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
687   else if( tag==sep )
688     res = myMgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
689   else //if( !myMgr->contains( actId ) )
690   {
691     QPixmap pix; QIconSet set;
692     QString name = strValue( attr, icon );
693     if( !name.isEmpty() )
694     {
695       if( loadPixmap( name, pix ) )
696         set = QIconSet( pix );
697     }
698
699     QString actLabel = strValue( attr, label );
700     QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel,
701                                        QKeySequence( strValue( attr, accel ) ),
702                                        myMgr );
703     newAct->setToolTip( strValue( attr, tooltip ) );
704     QString toggleact = strValue( attr, toggle );
705     bool isToggle = !toggleact.isEmpty();
706     newAct->setToggleAction( isToggle );
707     newAct->setOn( toggleact.lower()=="true" );
708         
709     connect( newAct );
710     int aid = myMgr->registerAction( newAct, visibleRule( attr ), 
711                                      isToggle ? toggleRule( attr ) : QString::null,
712                                      actId );
713     res = myMgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) );
714   }
715
716   return res;
717 }
718
719 //================================================================
720 // Function : 
721 // Purpose  : 
722 //================================================================
723 QString QtxPopupMgr::PopupCreator::visibleRule( const ItemAttributes& ) const
724 {
725   return QString::null;
726 }
727
728 //================================================================
729 // Function : 
730 // Purpose  : 
731 //================================================================
732 QString QtxPopupMgr::PopupCreator::toggleRule( const ItemAttributes& ) const
733 {
734   return QString::null;
735 }