1 // Copyright (C) 2007-2024 CEA, EDF, 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: QtxListAction.cxx
24 // Author: Sergey TELKOV
26 #include "QtxListAction.h"
30 #include <QVBoxLayout>
31 #include <QMouseEvent>
32 #include <QListWidget>
33 #include <QToolButton>
34 #include <QApplication>
37 \class QtxListAction::ScrollEvent
39 \brief Event for the scrolling in the list of actions.
42 class QtxListAction::ScrollEvent : public QEvent
45 enum { Scroll = User + 1 };
47 ScrollEvent( bool down ) : QEvent( (QEvent::Type)Scroll ), myDown( down ) {}
48 virtual ~ScrollEvent() {}
50 bool isDown() const { return myDown; }
57 \class QtxListAction::ListWidget
59 \brief List of actions.
62 class QtxListAction::ListWidget : public QListWidget
65 ListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {}
66 virtual ~ListWidget() {}
69 virtual void scrollContentsBy( int dx, int dy )
71 QListWidget::scrollContentsBy( dx, dy );
73 QApplication::postEvent( viewport(), new ScrollEvent( dy <= 0 ) );
78 \class QtxListAction::ListFrame
80 \brief Expanding frame with action list and comment.
83 class QtxListAction::ListFrame: public QMenu
86 ListFrame( QtxListAction*, QWidget* parent );
90 const QStringList names() const;
91 void addNames( const QStringList& );
93 void setSingleComment( const QString& );
94 void setMultipleComment( const QString& );
97 void setSelected( const int );
99 int linesNumber() const;
100 int charsNumber() const;
102 void setLinesNumber( const int );
103 void setCharsNumber( const int );
105 virtual QSize sizeHint() const;
106 virtual QSize minimumSizeHint() const;
108 virtual bool eventFilter( QObject*, QEvent* );
110 virtual void setVisible( bool );
113 virtual void keyPressEvent( QKeyEvent* );
117 void updateComment();
118 void setNames( const QStringList& );
119 void removePostedEvens( QObject*, int );
124 QtxListAction* myAction;
130 QString mySingleComment;
131 QString myMultipleComment;
137 \param parent parent widget
139 QtxListAction::ListFrame::ListFrame( QtxListAction* a, QWidget* parent )
147 QVBoxLayout* top = new QVBoxLayout( this );
149 QFrame* main = new QFrame( this );
150 main->setFrameStyle( QFrame::Panel | QFrame::Raised );
151 top->addWidget( main );
153 QVBoxLayout* base = new QVBoxLayout( main );
154 base->setMargin( 3 );
155 base->setSpacing( 2 );
157 myList = new ListWidget( main );
158 myList->setSelectionMode( QListWidget::MultiSelection );
159 myList->setVerticalScrollMode( QListWidget::ScrollPerItem );
160 myList->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
161 myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
162 myList->viewport()->installEventFilter( this );
163 myList->viewport()->setMouseTracking( true );
164 myList->setFocusPolicy( Qt::NoFocus );
166 myComment = new QLabel( main );
167 myComment->setFrameStyle( QFrame::Panel | QFrame::Sunken );
168 myComment->setAlignment( Qt::AlignCenter );
169 myMultipleComment = "%1";
171 base->addWidget( myList );
172 base->addWidget( myComment );
178 QtxListAction::ListFrame::~ListFrame()
183 \brief Clear list of names.
185 void QtxListAction::ListFrame::clear()
192 \brief Add names to the list.
194 Truncates each name to fit the frame width.
195 Method QtxListAction::setCharsNumber(int) can be used to change
196 the frame width (in characters).
198 \param names list of names to be added
199 \sa setNames(), QtxListAction::setCharsNumber(int)
201 void QtxListAction::ListFrame::addNames( const QStringList& names )
203 for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
204 myNames.append( *it );
209 \brief Set names to the list.
211 Truncates each name to fit the frame width.
212 Method QtxListAction::setCharsNumber(int) can be used to change
213 the frame width (in characters).
215 \param names list of names to be set
216 \sa addNames(), QtxListAction::setCharsNumber(int)
218 void QtxListAction::ListFrame::setNames( const QStringList& names )
225 for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
228 QFontMetrics fm = myList->fontMetrics();
229 int maxW = charsNumber() * fm.maxWidth();
230 int w = fm.width( s );
233 QString extra( "..." );
234 int len = s.length();
235 int extraLen = fm.width( extra ) + 1;
238 w = fm.width( s, --len );
239 if ( w + extraLen < maxW )
249 myList->addItems( strList );
253 \brief Get list of names.
254 \return list of names
256 const QStringList QtxListAction::ListFrame::names() const
262 \brief Get maximum numer of lines shown without activation of vertical scroll bar.
263 \return number of lines
264 \sa setLinesNumber(), charsNumber(), setCharsNumber()
266 int QtxListAction::ListFrame::linesNumber() const
272 \brief Get maximum numer of characters in the line.
274 If the name length is greater than this value, it will be truncated.
276 \return number of characters
277 \sa setCharsNumber(), linesNumber(), setLinesNumber()
279 int QtxListAction::ListFrame::charsNumber() const
285 \brief Set maximum numer of lines shown without activation of vertical scroll bar.
286 \param maxLines number of lines
287 \sa linesNumber(), charsNumber(), setCharsNumber()
289 void QtxListAction::ListFrame::setLinesNumber( const int maxLines )
295 \brief Set maximum numer of characters in the line.
297 If the name length is greater than this value, it will be truncated.
299 \param maxChars number of characters
300 \sa charsNumber(), linesNumber(), setLinesNumber()
302 void QtxListAction::ListFrame::setCharsNumber( const int maxChars )
304 if ( myChars == maxChars )
312 \brief Set comment which is displayed when single name is selected.
313 \param comment comment format
315 void QtxListAction::ListFrame::setSingleComment( const QString& comment )
317 mySingleComment = comment;
323 \brief Set comment which is displayed when multiple names are selected.
324 \param comment comment format
326 void QtxListAction::ListFrame::setMultipleComment( const QString& comment )
328 myMultipleComment = comment;
334 \brief Update displayed comment.
336 void QtxListAction::ListFrame::updateComment()
339 int selNum = selected();
341 com = myMultipleComment;
342 else if ( selNum > 0 && !mySingleComment.isEmpty() )
343 com = mySingleComment;
345 if ( !com.isEmpty() )
346 com = com.arg( selNum );
348 myComment->setText( com );
352 \brief Get preferable size for the list widget.
353 \return preferable size
355 QSize QtxListAction::ListFrame::sizeHint() const
357 return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
358 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
359 myComment->sizeHint().height() );
363 \brief Get preferable minimum size for the list widget.
364 \return preferable minimum size
366 QSize QtxListAction::ListFrame::minimumSizeHint() const
368 return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
369 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
370 myComment->sizeHint().height() );
374 \brief Validate the action.
376 void QtxListAction::ListFrame::accept()
378 int sel = selected();
379 if ( sel && myAction )
380 myAction->onMultiple( sel );
384 \brief Called when list widget is shown/hidden.
385 \param on if \c true, widget is shown, otherswise it is hidden
387 void QtxListAction::ListFrame::setVisible( bool on )
392 myList->scrollToItem( myList->item( 0 ), QListWidget::PositionAtTop );
397 QMenu::setVisible( on );
401 \brief Process key press event.
403 The following keys are supported:
409 \param e key press event
411 void QtxListAction::ListFrame::keyPressEvent( QKeyEvent* e )
413 if ( e->type() == QEvent::KeyRelease )
418 int selNum = selected();
422 setSelected( qMax( 1, selNum - 1 ) );
425 setSelected( qMax( 1, selNum + 1 ) );
428 setSelected( qMax( 1, selNum - linesNumber() ) );
430 case Qt::Key_PageDown:
431 setSelected( selNum += linesNumber() );
437 setSelected( myList->count() );
449 \brief Process mouse events on the viewport of the list widget.
450 \param o object recieving event (viewport)
452 \return \c true if further event processing should be stopped.
454 bool QtxListAction::ListFrame::eventFilter( QObject* o, QEvent* e )
458 switch( (int)e->type() )
460 case QEvent::MouseMove:
462 QMouseEvent* me = (QMouseEvent*)e;
463 if ( !myList->viewport()->rect().contains( me->pos() ) )
465 else if ( myList->itemAt( me->pos() ) )
466 setSelected( myList->row( myList->itemAt( me->pos() ) ) + 1 );
469 case QEvent::MouseButtonRelease:
471 case QEvent::MouseButtonPress:
472 case QEvent::MouseButtonDblClick:
474 case ScrollEvent::Scroll:
476 ScrollEvent* se = (ScrollEvent*)e;
477 QPoint pos = myList->viewport()->mapFromGlobal( QCursor::pos() );
478 if ( myList->viewport()->rect().contains( pos ) )
480 if ( myList->itemAt( pos ) )
481 setSelected( myList->row( myList->itemAt( pos ) ) + 1 );
483 else if ( se->isDown() )
484 setSelected( myList->row( myList->itemAt( myList->viewport()->rect().bottomLeft() -
485 QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
487 setSelected( myList->row( myList->itemAt( myList->viewport()->rect().topLeft() +
488 QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
499 return QMenu::eventFilter( o, e );
503 \brief Get number of selected names.
504 \return number of selected items
506 int QtxListAction::ListFrame::selected() const
509 QModelIndexList indexes = myList->selectionModel()->selectedRows();
510 for ( QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it )
511 sel = qMax( sel, (*it).row() + 1 );
517 \brief Set number of selected names.
518 \param lastSel number of items to be selected
520 void QtxListAction::ListFrame::setSelected( const int lastSel )
522 int last = qMin( lastSel, (int)myList->count() );
524 QItemSelection selection;
525 QItemSelectionModel* selModel = myList->selectionModel();
527 for ( int i = 0; i < last; i++ )
528 selection.select( selModel->model()->index( i, 0 ), selModel->model()->index( i, 0 ) );
530 selModel->select( selection, QItemSelectionModel::ClearAndSelect );
534 myList->scrollToItem( myList->item( item ) );
535 myList->clearFocus();
537 removePostedEvens( myList->viewport(), ScrollEvent::Scroll );
543 \brief Filter all events of specified type sent to specified object.
545 \param type event type to be filtered
547 void QtxListAction::ListFrame::removePostedEvens( QObject* o, int type )
549 class Filter : public QObject
552 Filter() : QObject( 0 ) {}
553 virtual bool eventFilter( QObject*, QEvent* )
560 o->installEventFilter( &f );
561 QApplication::sendPostedEvents( o, type );
566 \brief Action with associated list of items.
568 This class can be helpuful, for example, for creation of Undo/Redo
569 toolbar items which show list of available commands in the popup list box.
574 \param parent parent object
576 QtxListAction::QtxListAction( QObject* parent )
577 : QtxAction( parent ),
585 \param icon action icon
586 \param menuText menu text
587 \param accel key accelerator
588 \param parent parent object
590 QtxListAction::QtxListAction( const QIcon& icon, const QString& menuText,
591 int accel, QObject* parent )
592 : QtxAction( menuText, icon, menuText, accel, parent ),
600 \param menuText menu text
601 \param accel key accelerator
602 \param parent parent object
604 QtxListAction::QtxListAction( const QString& menuText, int accel, QObject* parent )
605 : QtxAction( menuText, menuText, accel, parent ),
613 \param text action description text (tooltip)
614 \param menuText menu text
615 \param accel key accelerator
616 \param parent parent object
618 QtxListAction::QtxListAction( const QString& text, const QString& menuText,
619 int accel, QObject* parent )
620 : QtxAction( text, menuText, accel, parent ),
628 \param text action description text (tooltip)
629 \param icon action icon
630 \param menuText menu text
631 \param accel key accelerator
632 \param parent parent object
634 QtxListAction::QtxListAction( const QString& text, const QIcon& icon,
635 const QString& menuText, int accel, QObject* parent )
636 : QtxAction( text, icon, menuText, accel, parent ),
645 QtxListAction::~QtxListAction()
652 \brief Get popup mode.
653 \return current popup mode (QtxListAction::PopupMode)
656 int QtxListAction::popupMode() const
658 return menu() ? SubMenu : Item;
662 \brief Set popup mode.
663 \param mode new popup mode (QtxListAction::PopupMode)
666 void QtxListAction::setPopupMode( const int mode )
668 if ( mode == popupMode() )
677 setMenu( new QMenu( 0 ) );
683 \brief Get current list of names.
684 \return list of names
686 QStringList QtxListAction::names() const
690 lst = myFrame->names();
695 \brief Add names to the list.
697 Truncates each name to fit the frame width.
698 Method setCharsNumber() can be used to change
699 the frame width (in characters).
701 \param names list of names to be added
702 \param clear if \c true, remove the old contents from the list
705 void QtxListAction::addNames( const QStringList& names, bool clear )
713 myFrame->addNames( names );
719 \brief Get maximum numer of lines shown without activation of vertical scroll bar.
720 \return number of lines
721 \sa setLinesNumber(), charsNumber(), setCharsNumber()
723 int QtxListAction::linesNumber() const
725 return myFrame->linesNumber();
729 \brief Get maximum numer of characters in the line.
731 If the name length is greater than this value, it will be truncated.
733 \return number of characters
734 \sa setCharsNumber(), linesNumber(), setLinesNumber()
736 int QtxListAction::charsNumber() const
738 return myFrame->charsNumber();
742 \brief Set maximum numer of lines shown without activation of vertical scroll bar.
743 \param nlines number of lines (5 by default)
744 \sa linesNumber(), charsNumber(), setCharsNumber()
746 void QtxListAction::setLinesNumber( const int nlines )
748 myFrame->setLinesNumber( nlines );
752 \brief Set maximum numer of characters in the line.
754 If the name length is greater than this value, it will be truncated.
756 \param maxChars number of characters (5 by default)
757 \sa charsNumber(), linesNumber(), setLinesNumber()
760 void QtxListAction::setCharsNumber( const int nchars )
762 myFrame->setCharsNumber( nchars );
766 \brief Set the format Qt string for comments displayed under the list
767 of actions for one action and for several actions.
769 Example: "Undo %1 actions" format string will work as "Undo 3 actions"
770 when 3 actions are selected. The default format string is "%1".
772 \param c single action comment format
773 \param c multiple actions comment format
775 void QtxListAction::setComment( const QString& c, const QString& sc )
780 myFrame->setSingleComment( sc.isEmpty() ? c : sc );
781 myFrame->setMultipleComment( c );
785 \brief Create action widget.
787 This function is called whenever the action is added
788 to a container widget that supports custom widgets like menu or toolbar.
790 \param parent container widget the action is added to
791 \return tool button for toolbar and 0 otherwise
793 QWidget* QtxListAction::createWidget( QWidget* parent )
795 if ( parent && parent->inherits( "QMenu" ) )
798 QToolButton* tb = new QToolButton( parent );
799 tb->setText( text() );
800 tb->setIcon( icon() );
801 tb->setPopupMode( QToolButton::MenuButtonPopup );
802 tb->setMenu( myFrame );
803 tb->setEnabled( isEnabled() && !names().isEmpty() );
804 tb->setToolTip( toolTip() );
805 connect( tb, SIGNAL( clicked( bool ) ), this, SLOT( onSingle( bool ) ) );
811 \brief Destroy action widget.
813 This function is called whenever the action is removed
814 from a container widget that supports custom widgets like menu or toolbar.
816 \param widget container widget the action is removed from
818 void QtxListAction::deleteWidget( QWidget* widget )
824 \brief Initialize the action.
826 void QtxListAction::initialize()
828 setPopupMode( Item );
830 myFrame = new QtxListAction::ListFrame( this, 0 );
831 myFrame->setLinesNumber( 7 );
832 myFrame->setCharsNumber( 5 );
836 connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) );
837 connect( this, SIGNAL( triggered( bool ) ), this, SLOT( onSingle( bool ) ) );
841 \brief Called the action contents is changed.
843 void QtxListAction::onChanged()
845 QStringList lst = myFrame->names();
850 for ( QStringList::iterator iter = lst.begin(); iter != lst.end(); ++iter )
852 QAction* a = new QAction( *iter, menu() );
853 menu()->addAction( a );
854 connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTriggered( bool ) ) );
858 QList<QWidget*> widList = createdWidgets();
859 for ( QList<QWidget*>::iterator it = widList.begin(); it != widList.end(); ++it )
861 (*it)->setEnabled( isEnabled() && !lst.isEmpty() );
862 QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
865 tb->setText( text() );
866 tb->setIcon( icon() );
867 tb->setToolTip( toolTip() );
873 \brief Called when a user click action button.
877 void QtxListAction::onSingle( bool /*on*/ )
883 \brief Called when multiple items are selected.
885 void QtxListAction::onMultiple( const int numActions )
890 if ( numActions > 0 )
891 emit triggered( numActions );
895 \brief Called when user activates an items in the popup sub menu.
898 void QtxListAction::onTriggered( bool /*on*/ )
903 QList<QAction*> actionList = menu()->actions();
904 int idx = actionList.indexOf( ::qobject_cast<QAction*>( sender() ) );
908 emit triggered( idx + 1 );
912 \fn QtxListAction::activated(int numItems );
913 \brief This signal is emitted when an action is activated.
914 \param numItems number of items being selected in the action list.