Back to index

salome-gui  6.5.0
QtxListAction.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 // File:      QtxListAction.cxx
00024 // Author:    Sergey TELKOV
00025 //
00026 #include "QtxListAction.h"
00027 
00028 #include <QMenu>
00029 #include <QLabel>
00030 #include <QVBoxLayout>
00031 #include <QMouseEvent>
00032 #include <QListWidget>
00033 #include <QToolButton>
00034 #include <QApplication>
00035 
00042 class QtxListAction::ScrollEvent : public QEvent
00043 {
00044 public:
00045   enum { Scroll = User + 1 };
00046 
00047   ScrollEvent( bool down ) : QEvent( (QEvent::Type)Scroll ), myDown( down ) {}
00048   virtual ~ScrollEvent() {}
00049 
00050   bool isDown() const { return myDown; }
00051 
00052 private:
00053   bool myDown;
00054 };
00055 
00062 class QtxListAction::ListWidget : public QListWidget
00063 {
00064 public:
00065   ListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {}
00066   virtual ~ListWidget() {}
00067 
00068 protected:
00069   virtual void scrollContentsBy( int dx, int dy )
00070   {
00071     QListWidget::scrollContentsBy( dx, dy );
00072     if ( dy != 0 )
00073       QApplication::postEvent( viewport(), new ScrollEvent( dy <= 0 ) );
00074   }
00075 };
00076 
00083 class QtxListAction::ListFrame: public QMenu
00084 {
00085 public:
00086   ListFrame( QtxListAction*, QWidget* parent );
00087   virtual ~ListFrame();
00088 
00089   void                    clear();
00090   const QStringList       names() const;
00091   void                    addNames( const QStringList& );
00092 
00093   void                    setSingleComment( const QString& );
00094   void                    setMultipleComment( const QString& );
00095 
00096   int                     selected() const;
00097   void                    setSelected( const int );
00098 
00099   int                     linesNumber() const;
00100   int                     charsNumber() const;
00101 
00102   void                    setLinesNumber( const int );
00103   void                    setCharsNumber( const int );
00104 
00105   virtual QSize           sizeHint() const;
00106   virtual QSize           minimumSizeHint() const;
00107 
00108   virtual bool            eventFilter( QObject*, QEvent* );
00109 
00110   virtual void            setVisible( bool );
00111 
00112 protected:
00113   virtual void            keyPressEvent( QKeyEvent* );
00114 
00115 private:
00116   void                    accept();
00117   void                    updateComment();
00118   void                    setNames( const QStringList& );
00119   void                    removePostedEvens( QObject*, int );
00120 
00121 private:
00122   QListWidget*            myList;
00123   QStringList             myNames;
00124   QtxListAction*          myAction;
00125   QLabel*                 myComment;
00126 
00127   int                     myLines;
00128   int                     myChars;
00129 
00130   QString                 mySingleComment;
00131   QString                 myMultipleComment;
00132 };
00133 
00139 QtxListAction::ListFrame::ListFrame( QtxListAction* a, QWidget* parent )
00140 : QMenu( parent ),
00141   myList( 0 ),
00142   myAction( a ),
00143   myComment( 0 ),
00144   myLines( 5 ),
00145   myChars( 5 )
00146 {
00147   QVBoxLayout* top = new QVBoxLayout( this );
00148   top->setMargin( 0 );
00149   QFrame* main = new QFrame( this );
00150   main->setFrameStyle( QFrame::Panel | QFrame::Raised );
00151   top->addWidget( main );
00152 
00153   QVBoxLayout* base = new QVBoxLayout( main );
00154   base->setMargin( 3 );
00155   base->setSpacing( 2 );
00156 
00157   myList = new ListWidget( main );
00158   myList->setSelectionMode( QListWidget::MultiSelection );
00159   myList->setVerticalScrollMode( QListWidget::ScrollPerItem );
00160   myList->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
00161   myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00162   myList->viewport()->installEventFilter( this );
00163   myList->viewport()->setMouseTracking( true );
00164   myList->setFocusPolicy( Qt::NoFocus );
00165 
00166   myComment = new QLabel( main );
00167   myComment->setFrameStyle( QFrame::Panel | QFrame::Sunken );
00168   myComment->setAlignment( Qt::AlignCenter );
00169   myMultipleComment = "%1";
00170 
00171   base->addWidget( myList );
00172   base->addWidget( myComment );
00173 }
00174 
00178 QtxListAction::ListFrame::~ListFrame()
00179 {
00180 }
00181 
00185 void QtxListAction::ListFrame::clear()
00186 {
00187   myNames.clear();
00188   setNames( myNames );
00189 }
00190 
00201 void QtxListAction::ListFrame::addNames( const QStringList& names )
00202 {
00203   for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
00204     myNames.append( *it );
00205   setNames( myNames );
00206 }
00207 
00218 void QtxListAction::ListFrame::setNames( const QStringList& names )
00219 {
00220   if ( !myList )
00221     return;
00222 
00223   myList->clear();
00224   QStringList strList;
00225   for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
00226   {
00227     QString s = *it;
00228     QFontMetrics fm = myList->fontMetrics();
00229     int maxW = charsNumber() * fm.maxWidth();
00230     int w = fm.width( s );
00231     if ( w > maxW )
00232     {
00233       QString extra( "..." );
00234       int len = s.length();
00235       int extraLen = fm.width( extra ) + 1;
00236       while ( true )
00237       {
00238         w = fm.width( s, --len );
00239         if ( w + extraLen < maxW )
00240         {
00241           s = s.left( len );
00242           break;
00243         }
00244       }
00245       s += extra;
00246     }
00247     strList.append( s );
00248   }
00249   myList->addItems( strList );
00250 }
00251 
00256 const QStringList QtxListAction::ListFrame::names() const
00257 {
00258   return myNames;
00259 }
00260 
00266 int QtxListAction::ListFrame::linesNumber() const
00267 {
00268   return myLines;
00269 }
00270 
00279 int QtxListAction::ListFrame::charsNumber() const
00280 {
00281   return myChars;
00282 }
00283 
00289 void QtxListAction::ListFrame::setLinesNumber( const int maxLines )
00290 {
00291   myLines = maxLines;
00292 }
00293 
00302 void QtxListAction::ListFrame::setCharsNumber( const int maxChars )
00303 {
00304   if ( myChars == maxChars )
00305     return;
00306 
00307   myChars = maxChars;
00308   setNames( myNames );
00309 }
00310 
00315 void QtxListAction::ListFrame::setSingleComment( const QString& comment )
00316 {
00317   mySingleComment = comment;
00318   setNames( myNames );
00319   updateComment();
00320 }
00321 
00326 void QtxListAction::ListFrame::setMultipleComment( const QString& comment )
00327 {
00328   myMultipleComment = comment;
00329   setNames( myNames );
00330   updateComment();
00331 }
00332 
00336 void QtxListAction::ListFrame::updateComment()
00337 {
00338   QString com;
00339   int selNum = selected();
00340   if ( selNum > 1 )
00341     com = myMultipleComment;
00342   else if ( selNum > 0 && !mySingleComment.isEmpty() )
00343     com = mySingleComment;
00344   
00345   if ( !com.isEmpty() )
00346     com = com.arg( selNum );
00347   
00348   myComment->setText( com );
00349 }
00350 
00355 QSize QtxListAction::ListFrame::sizeHint() const
00356 {
00357   return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
00358                 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
00359                 myComment->sizeHint().height() );
00360 }
00361 
00366 QSize QtxListAction::ListFrame::minimumSizeHint() const
00367 {
00368   return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
00369                 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
00370                 myComment->sizeHint().height() );
00371 }
00372 
00376 void QtxListAction::ListFrame::accept()
00377 {
00378   int sel = selected();
00379   if ( sel && myAction )
00380     myAction->onMultiple( sel );
00381 }
00382 
00387 void QtxListAction::ListFrame::setVisible( bool on )
00388 {
00389   if ( on )
00390   {
00391     myList->setFocus();
00392     myList->scrollToItem( myList->item( 0 ), QListWidget::PositionAtTop );
00393     setSelected( 0 );
00394     updateComment();
00395   }
00396 
00397   QMenu::setVisible( on );
00398 }
00399 
00411 void QtxListAction::ListFrame::keyPressEvent( QKeyEvent* e )
00412 {
00413   if ( e->type() == QEvent::KeyRelease )
00414     return;
00415 
00416   e->accept();
00417 
00418   int selNum = selected();
00419   switch( e->key() )
00420   {
00421   case Qt::Key_Up:
00422     setSelected( qMax( 1, selNum - 1 ) );
00423     break;
00424   case Qt::Key_Down:
00425     setSelected( qMax( 1, selNum + 1 ) );
00426     break;
00427   case Qt::Key_PageUp:
00428     setSelected( qMax( 1, selNum - linesNumber() ) );
00429     break;
00430   case Qt::Key_PageDown:
00431     setSelected( selNum += linesNumber() );
00432     break;
00433   case Qt::Key_Home:
00434     setSelected( 1 );
00435     break;
00436   case Qt::Key_End:
00437     setSelected( myList->count() );
00438     break;
00439   case Qt::Key_Return:
00440     accept();
00441     break;
00442   case Qt::Key_Escape:
00443     hide();
00444     break;
00445   }
00446 }
00447 
00454 bool QtxListAction::ListFrame::eventFilter( QObject* o, QEvent* e )
00455 {
00456   bool res = true;
00457 
00458   switch( e->type() )
00459   {
00460   case QEvent::MouseMove:
00461     {
00462       QMouseEvent* me = (QMouseEvent*)e;
00463       if ( !myList->viewport()->rect().contains( me->pos() ) )
00464         setSelected( 0 );
00465       else if ( myList->itemAt( me->pos() ) )
00466         setSelected( myList->row( myList->itemAt( me->pos() ) ) + 1 );
00467     }
00468     break;
00469   case QEvent::MouseButtonRelease:
00470     accept();
00471   case QEvent::MouseButtonPress:
00472   case QEvent::MouseButtonDblClick:
00473     break;
00474   case ScrollEvent::Scroll:
00475     {
00476       ScrollEvent* se = (ScrollEvent*)e;
00477       QPoint pos = myList->viewport()->mapFromGlobal( QCursor::pos() );
00478       if ( myList->viewport()->rect().contains( pos ) )
00479       {
00480         if ( myList->itemAt( pos ) )
00481           setSelected( myList->row( myList->itemAt( pos ) ) + 1 );
00482       }
00483       else if ( se->isDown() )
00484         setSelected( myList->row( myList->itemAt( myList->viewport()->rect().bottomLeft() -
00485                                                   QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
00486       else
00487         setSelected( myList->row( myList->itemAt( myList->viewport()->rect().topLeft() +
00488                                                   QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
00489     }
00490     break;
00491   default:
00492     res = false;
00493     break;
00494   }
00495 
00496   if ( res )
00497     return true;
00498   else
00499     return QMenu::eventFilter( o, e );
00500 }
00501 
00506 int QtxListAction::ListFrame::selected() const
00507 {
00508   int sel = 0;
00509   QModelIndexList indexes = myList->selectionModel()->selectedRows();
00510   for ( QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it )
00511     sel = qMax( sel, (*it).row() + 1 );
00512   
00513   return sel;
00514 }
00515 
00520 void QtxListAction::ListFrame::setSelected( const int lastSel )
00521 {
00522   int last = qMin( lastSel, (int)myList->count() );
00523 
00524   QItemSelection selection;
00525   QItemSelectionModel* selModel = myList->selectionModel();
00526 
00527   for ( int i = 0; i < last; i++ )
00528     selection.select( selModel->model()->index( i, 0 ), selModel->model()->index( i, 0 ) );
00529 
00530   selModel->select( selection, QItemSelectionModel::ClearAndSelect );
00531   
00532   int item = last - 1;
00533 
00534   myList->scrollToItem( myList->item( item ) );
00535   myList->clearFocus();
00536 
00537   removePostedEvens( myList->viewport(), ScrollEvent::Scroll );
00538 
00539   updateComment();
00540 }
00541 
00547 void QtxListAction::ListFrame::removePostedEvens( QObject* o, int type )
00548 {
00549   class Filter : public QObject
00550   {
00551   public:
00552     Filter() : QObject( 0 ) {}
00553     virtual bool eventFilter( QObject*, QEvent* )
00554     {
00555       return true;
00556     }
00557   };
00558 
00559   Filter f;
00560   o->installEventFilter( &f );
00561   QApplication::sendPostedEvents( o, type );
00562 }
00563 
00576 QtxListAction::QtxListAction( QObject* parent )
00577 : QtxAction( parent ),
00578   myFrame( 0 )
00579 {
00580   initialize();
00581 }
00582 
00590 QtxListAction::QtxListAction( const QIcon& icon, const QString& menuText, 
00591                               int accel, QObject* parent )
00592 : QtxAction( menuText, icon, menuText, accel, parent ),
00593   myFrame( 0 )
00594 {
00595   initialize();
00596 }
00597 
00604 QtxListAction::QtxListAction( const QString& menuText, int accel, QObject* parent )
00605 : QtxAction( menuText, menuText, accel, parent ),
00606   myFrame( 0 )
00607 {
00608   initialize();
00609 }
00610 
00618 QtxListAction::QtxListAction( const QString& text, const QString& menuText, 
00619                               int accel, QObject* parent )
00620 : QtxAction( text, menuText, accel, parent ),
00621   myFrame( 0 )
00622 {
00623   initialize();
00624 }
00625 
00634 QtxListAction::QtxListAction( const QString& text, const QIcon& icon, 
00635                               const QString& menuText, int accel, QObject* parent )
00636 : QtxAction( text, icon, menuText, accel, parent ),
00637   myFrame( 0 )
00638 {
00639   initialize();
00640 }
00641 
00645 QtxListAction::~QtxListAction()
00646 {
00647   delete myFrame;
00648   myFrame = 0;
00649 }
00650 
00656 int QtxListAction::popupMode() const
00657 {
00658   return menu() ? SubMenu : Item;
00659 }
00660 
00666 void QtxListAction::setPopupMode( const int mode )
00667 {
00668   if ( mode == popupMode() )
00669     return;
00670 
00671   if ( mode == Item )
00672   {
00673     delete menu();
00674     setMenu( 0 );
00675   }
00676   else
00677     setMenu( new QMenu( 0 ) );
00678 
00679   onChanged();
00680 }
00681 
00686 QStringList QtxListAction::names() const
00687 {
00688   QStringList lst;
00689   if ( myFrame )
00690     lst = myFrame->names();
00691   return lst;
00692 }
00693 
00705 void QtxListAction::addNames( const QStringList& names, bool clear )
00706 {
00707   if ( !myFrame )
00708     return;
00709 
00710   if ( clear )
00711     myFrame->clear();
00712 
00713   myFrame->addNames( names );
00714 
00715   onChanged();
00716 }
00717 
00723 int QtxListAction::linesNumber() const
00724 {
00725   return myFrame->linesNumber();
00726 }
00727 
00736 int QtxListAction::charsNumber() const
00737 {
00738   return myFrame->charsNumber();
00739 }
00740 
00746 void QtxListAction::setLinesNumber( const int nlines )
00747 {
00748   myFrame->setLinesNumber( nlines );
00749 }
00750 
00760 void QtxListAction::setCharsNumber( const int nchars )
00761 {
00762   myFrame->setCharsNumber( nchars );
00763 }
00764 
00775 void QtxListAction::setComment( const QString& c, const QString& sc )
00776 {
00777   if ( !myFrame )
00778     return;
00779 
00780   myFrame->setSingleComment( sc.isEmpty() ? c : sc );
00781   myFrame->setMultipleComment( c );
00782 }
00783 
00793 QWidget* QtxListAction::createWidget( QWidget* parent )
00794 {
00795   if ( parent && parent->inherits( "QMenu" ) )
00796     return 0;
00797 
00798   QToolButton* tb = new QToolButton( parent );
00799   tb->setText( text() );
00800   tb->setIcon( icon() );
00801   tb->setPopupMode( QToolButton::MenuButtonPopup );
00802   tb->setMenu( myFrame );
00803   tb->setEnabled( isEnabled() && !names().isEmpty() );
00804   tb->setToolTip( toolTip() );
00805   connect( tb, SIGNAL( clicked( bool ) ), this, SLOT( onSingle( bool ) ) );
00806 
00807   return tb;
00808 }
00809 
00818 void QtxListAction::deleteWidget( QWidget* widget )
00819 {
00820   delete widget;
00821 }
00822 
00826 void QtxListAction::initialize()
00827 {
00828   setPopupMode( Item );
00829   
00830   myFrame = new QtxListAction::ListFrame( this, 0 );
00831   myFrame->setLinesNumber( 7 );
00832   myFrame->setCharsNumber( 5 );
00833 
00834   myFrame->hide();
00835 
00836   connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) );
00837   connect( this, SIGNAL( triggered( bool ) ), this, SLOT( onSingle( bool ) ) );
00838 }
00839 
00843 void QtxListAction::onChanged()
00844 {
00845   QStringList lst = myFrame->names();
00846 
00847   if ( menu() )
00848   {
00849     menu()->clear();
00850     for ( QStringList::iterator iter = lst.begin(); iter != lst.end(); ++iter )
00851     {
00852       QAction* a = new QAction( *iter, menu() );
00853       menu()->addAction( a );
00854       connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTriggered( bool ) ) );
00855     }
00856   }
00857 
00858   QList<QWidget*> widList = createdWidgets();
00859   for ( QList<QWidget*>::iterator it = widList.begin(); it != widList.end(); ++it )
00860   {
00861     (*it)->setEnabled( isEnabled() && !lst.isEmpty() );
00862     QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
00863     if ( tb )
00864     {
00865       tb->setText( text() );
00866       tb->setIcon( icon() );
00867       tb->setToolTip( toolTip() );
00868     }
00869   }
00870 }
00871 
00877 void QtxListAction::onSingle( bool /*on*/ )
00878 {
00879   onMultiple( 1 );
00880 }
00881 
00885 void QtxListAction::onMultiple( const int numActions )
00886 {
00887   if ( myFrame )
00888     myFrame->hide();
00889 
00890   if ( numActions > 0 )
00891     emit triggered( numActions );
00892 }
00893 
00898 void QtxListAction::onTriggered( bool /*on*/ )
00899 {
00900   if ( !menu() )
00901     return;
00902 
00903   QList<QAction*> actionList = menu()->actions();
00904   int idx = actionList.indexOf( ::qobject_cast<QAction*>( sender() ) );
00905   if ( idx < 0 )
00906     return;
00907 
00908   emit triggered( idx + 1 );
00909 }
00910