1 // Copyright (C) 2007-2008 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.
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
22 // File: QtxListAction.cxx
23 // Author: Sergey TELKOV
25 #include "QtxListAction.h"
29 #include <QVBoxLayout>
30 #include <QMouseEvent>
31 #include <QListWidget>
32 #include <QToolButton>
33 #include <QApplication>
36 \class QtxListAction::ScrollEvent
38 \brief Event for the scrolling in the list of actions.
41 class QtxListAction::ScrollEvent : public QEvent
44 enum { Scroll = User + 1 };
46 ScrollEvent( bool down ) : QEvent( (QEvent::Type)Scroll ), myDown( down ) {}
47 virtual ~ScrollEvent() {}
49 bool isDown() const { return myDown; }
56 \class QtxListAction::ListWidget
58 \brief List of actions.
61 class QtxListAction::ListWidget : public QListWidget
64 ListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {}
65 virtual ~ListWidget() {}
68 virtual void scrollContentsBy( int dx, int dy )
70 QListWidget::scrollContentsBy( dx, dy );
72 QApplication::postEvent( viewport(), new ScrollEvent( dy <= 0 ) );
77 \class QtxListAction::ListFrame
79 \brief Expanding frame with action list and comment.
82 class QtxListAction::ListFrame: public QMenu
85 ListFrame( QtxListAction*, QWidget* parent );
89 const QStringList names() const;
90 void addNames( const QStringList& );
92 void setSingleComment( const QString& );
93 void setMultipleComment( const QString& );
96 void setSelected( const int );
98 int linesNumber() const;
99 int charsNumber() const;
101 void setLinesNumber( const int );
102 void setCharsNumber( const int );
104 virtual QSize sizeHint() const;
105 virtual QSize minimumSizeHint() const;
107 virtual bool eventFilter( QObject*, QEvent* );
109 virtual void setVisible( bool );
112 virtual void keyPressEvent( QKeyEvent* );
116 void updateComment();
117 void setNames( const QStringList& );
118 void removePostedEvens( QObject*, int );
123 QtxListAction* myAction;
129 QString mySingleComment;
130 QString myMultipleComment;
136 \param parent parent widget
138 QtxListAction::ListFrame::ListFrame( QtxListAction* a, QWidget* parent )
146 QVBoxLayout* top = new QVBoxLayout( this );
148 QFrame* main = new QFrame( this );
149 main->setFrameStyle( QFrame::Panel | QFrame::Raised );
150 top->addWidget( main );
152 QVBoxLayout* base = new QVBoxLayout( main );
153 base->setMargin( 3 );
154 base->setSpacing( 2 );
156 myList = new ListWidget( main );
157 myList->setSelectionMode( QListWidget::MultiSelection );
158 myList->setVerticalScrollMode( QListWidget::ScrollPerItem );
159 myList->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
160 myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
161 myList->viewport()->installEventFilter( this );
162 myList->viewport()->setMouseTracking( true );
163 myList->setFocusPolicy( Qt::NoFocus );
165 myComment = new QLabel( main );
166 myComment->setFrameStyle( QFrame::Panel | QFrame::Sunken );
167 myComment->setAlignment( Qt::AlignCenter );
168 myMultipleComment = "%1";
170 base->addWidget( myList );
171 base->addWidget( myComment );
177 QtxListAction::ListFrame::~ListFrame()
182 \brief Clear list of names.
184 void QtxListAction::ListFrame::clear()
191 \brief Add names to the list.
193 Truncates each name to fit the frame width.
194 Method QtxListAction::setCharsNumber(int) can be used to change
195 the frame width (in characters).
197 \param names list of names to be added
198 \sa setNames(), QtxListAction::setCharsNumber(int)
200 void QtxListAction::ListFrame::addNames( const QStringList& names )
202 for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it )
203 myNames.append( *it );
208 \brief Set names to the list.
210 Truncates each name to fit the frame width.
211 Method QtxListAction::setCharsNumber(int) can be used to change
212 the frame width (in characters).
214 \param names list of names to be set
215 \sa addNames(), QtxListAction::setCharsNumber(int)
217 void QtxListAction::ListFrame::setNames( const QStringList& names )
224 for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
227 QFontMetrics fm = myList->fontMetrics();
228 int maxW = charsNumber() * fm.maxWidth();
229 int w = fm.width( s );
232 QString extra( "..." );
233 int len = s.length();
234 int extraLen = fm.width( extra ) + 1;
237 w = fm.width( s, --len );
238 if ( w + extraLen < maxW )
248 myList->addItems( strList );
252 \brief Get list of names.
253 \return list of names
255 const QStringList QtxListAction::ListFrame::names() const
261 \brief Get maximum numer of lines shown without activation of vertical scroll bar.
262 \return number of lines
263 \sa setLinesNumber(), charsNumber(), setCharsNumber()
265 int QtxListAction::ListFrame::linesNumber() const
271 \brief Get maximum numer of characters in the line.
273 If the name length is greater than this value, it will be truncated.
275 \return number of characters
276 \sa setCharsNumber(), linesNumber(), setLinesNumber()
278 int QtxListAction::ListFrame::charsNumber() const
284 \brief Set maximum numer of lines shown without activation of vertical scroll bar.
285 \param maxLines number of lines
286 \sa linesNumber(), charsNumber(), setCharsNumber()
288 void QtxListAction::ListFrame::setLinesNumber( const int maxLines )
294 \brief Set maximum numer of characters in the line.
296 If the name length is greater than this value, it will be truncated.
298 \param maxChars number of characters
299 \sa charsNumber(), linesNumber(), setLinesNumber()
301 void QtxListAction::ListFrame::setCharsNumber( const int maxChars )
303 if ( myChars == maxChars )
311 \brief Set comment which is displayed when single name is selected.
312 \param comment comment format
314 void QtxListAction::ListFrame::setSingleComment( const QString& comment )
316 mySingleComment = comment;
322 \brief Set comment which is displayed when multiple names are selected.
323 \param comment comment format
325 void QtxListAction::ListFrame::setMultipleComment( const QString& comment )
327 myMultipleComment = comment;
333 \brief Update displayed comment.
335 void QtxListAction::ListFrame::updateComment()
338 int selNum = selected();
340 com = myMultipleComment;
341 else if ( selNum > 0 && !mySingleComment.isEmpty() )
342 com = mySingleComment;
344 if ( !com.isEmpty() )
345 com = com.arg( selNum );
347 myComment->setText( com );
351 \brief Get preferable size for the list widget.
352 \return preferable size
354 QSize QtxListAction::ListFrame::sizeHint() const
356 return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
357 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
358 myComment->sizeHint().height() );
362 \brief Get preferable minimum size for the list widget.
363 \return preferable minimum size
365 QSize QtxListAction::ListFrame::minimumSizeHint() const
367 return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10,
368 qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) +
369 myComment->sizeHint().height() );
373 \brief Validate the action.
375 void QtxListAction::ListFrame::accept()
377 int sel = selected();
378 if ( sel && myAction )
379 myAction->onMultiple( sel );
383 \brief Called when list widget is shown/hidden.
384 \param on if \c true, widget is shown, otherswise it is hidden
386 void QtxListAction::ListFrame::setVisible( bool on )
391 myList->scrollToItem( myList->item( 0 ), QListWidget::PositionAtTop );
396 QMenu::setVisible( on );
400 \brief Process key press event.
402 The following keys are supported:
408 \param e key press event
410 void QtxListAction::ListFrame::keyPressEvent( QKeyEvent* e )
412 if ( e->type() == QEvent::KeyRelease )
417 int selNum = selected();
421 setSelected( qMax( 1, selNum - 1 ) );
424 setSelected( qMax( 1, selNum + 1 ) );
427 setSelected( qMax( 1, selNum - linesNumber() ) );
429 case Qt::Key_PageDown:
430 setSelected( selNum += linesNumber() );
436 setSelected( myList->count() );
448 \brief Process mouse events on the viewport of the list widget.
449 \param o object recieving event (viewport)
451 \return \c true if further event processing should be stopped.
453 bool QtxListAction::ListFrame::eventFilter( QObject* o, QEvent* e )
459 case QEvent::MouseMove:
461 QMouseEvent* me = (QMouseEvent*)e;
462 if ( !myList->viewport()->rect().contains( me->pos() ) )
464 else if ( myList->itemAt( me->pos() ) )
465 setSelected( myList->row( myList->itemAt( me->pos() ) ) + 1 );
468 case QEvent::MouseButtonRelease:
470 case QEvent::MouseButtonPress:
471 case QEvent::MouseButtonDblClick:
473 case ScrollEvent::Scroll:
475 ScrollEvent* se = (ScrollEvent*)e;
476 QPoint pos = myList->viewport()->mapFromGlobal( QCursor::pos() );
477 if ( myList->viewport()->rect().contains( pos ) )
479 if ( myList->itemAt( pos ) )
480 setSelected( myList->row( myList->itemAt( pos ) ) + 1 );
482 else if ( se->isDown() )
483 setSelected( myList->row( myList->itemAt( myList->viewport()->rect().bottomLeft() -
484 QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
486 setSelected( myList->row( myList->itemAt( myList->viewport()->rect().topLeft() +
487 QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 );
498 return QMenu::eventFilter( o, e );
502 \brief Get number of selected names.
503 \return number of selected items
505 int QtxListAction::ListFrame::selected() const
508 QModelIndexList indexes = myList->selectionModel()->selectedRows();
509 for ( QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it )
510 sel = qMax( sel, (*it).row() + 1 );
516 \brief Set number of selected names.
517 \param lastSel number of items to be selected
519 void QtxListAction::ListFrame::setSelected( const int lastSel )
521 int last = qMin( lastSel, (int)myList->count() );
523 QItemSelection selection;
524 QItemSelectionModel* selModel = myList->selectionModel();
526 for ( int i = 0; i < last; i++ )
527 selection.select( selModel->model()->index( i, 0 ), selModel->model()->index( i, 0 ) );
529 selModel->select( selection, QItemSelectionModel::ClearAndSelect );
533 myList->scrollToItem( myList->item( item ) );
534 myList->clearFocus();
536 removePostedEvens( myList->viewport(), ScrollEvent::Scroll );
542 \brief Filter all events of specified type sent to specified object.
544 \param type event type to be filtered
546 void QtxListAction::ListFrame::removePostedEvens( QObject* o, int type )
548 class Filter : public QObject
551 Filter() : QObject( 0 ) {}
552 virtual bool eventFilter( QObject*, QEvent* )
559 o->installEventFilter( &f );
560 QApplication::sendPostedEvents( o, type );
565 \brief Action with associated list of items.
567 This class can be helpuful, for example, for creation of Undo/Redo
568 toolbar items which show list of available commands in the popup list box.
573 \param parent parent object
575 QtxListAction::QtxListAction( QObject* parent )
576 : QtxAction( parent ),
584 \param icon action icon
585 \param menuText menu text
586 \param accel key accelerator
587 \param parent parent object
589 QtxListAction::QtxListAction( const QIcon& icon, const QString& menuText,
590 int accel, QObject* parent )
591 : QtxAction( menuText, icon, menuText, accel, parent ),
599 \param menuText menu text
600 \param accel key accelerator
601 \param parent parent object
603 QtxListAction::QtxListAction( const QString& menuText, int accel, QObject* parent )
604 : QtxAction( menuText, menuText, accel, parent ),
612 \param text action description text (tooltip)
613 \param menuText menu text
614 \param accel key accelerator
615 \param parent parent object
617 QtxListAction::QtxListAction( const QString& text, const QString& menuText,
618 int accel, QObject* parent )
619 : QtxAction( text, menuText, accel, parent ),
627 \param text action description text (tooltip)
628 \param icon action icon
629 \param menuText menu text
630 \param accel key accelerator
631 \param parent parent object
633 QtxListAction::QtxListAction( const QString& text, const QIcon& icon,
634 const QString& menuText, int accel, QObject* parent )
635 : QtxAction( text, icon, menuText, accel, parent ),
644 QtxListAction::~QtxListAction()
651 \brief Get popup mode.
652 \return current popup mode (QtxListAction::PopupMode)
655 int QtxListAction::popupMode() const
657 return menu() ? SubMenu : Item;
661 \brief Set popup mode.
662 \param mode new popup mode (QtxListAction::PopupMode)
665 void QtxListAction::setPopupMode( const int mode )
667 if ( mode == popupMode() )
676 setMenu( new QMenu( 0 ) );
682 \brief Get current list of names.
683 \return list of names
685 QStringList QtxListAction::names() const
689 lst = myFrame->names();
694 \brief Add names to the list.
696 Truncates each name to fit the frame width.
697 Method setCharsNumber() can be used to change
698 the frame width (in characters).
700 \param names list of names to be added
701 \param clear if \c true, remove the old contents from the list
704 void QtxListAction::addNames( const QStringList& names, bool clear )
712 myFrame->addNames( names );
718 \brief Get maximum numer of lines shown without activation of vertical scroll bar.
719 \return number of lines
720 \sa setLinesNumber(), charsNumber(), setCharsNumber()
722 int QtxListAction::linesNumber() const
724 return myFrame->linesNumber();
728 \brief Get maximum numer of characters in the line.
730 If the name length is greater than this value, it will be truncated.
732 \return number of characters
733 \sa setCharsNumber(), linesNumber(), setLinesNumber()
735 int QtxListAction::charsNumber() const
737 return myFrame->charsNumber();
741 \brief Set maximum numer of lines shown without activation of vertical scroll bar.
742 \param nlines number of lines (5 by default)
743 \sa linesNumber(), charsNumber(), setCharsNumber()
745 void QtxListAction::setLinesNumber( const int nlines )
747 myFrame->setLinesNumber( nlines );
751 \brief Set maximum numer of characters in the line.
753 If the name length is greater than this value, it will be truncated.
755 \param maxChars number of characters (5 by default)
756 \sa charsNumber(), linesNumber(), setLinesNumber()
759 void QtxListAction::setCharsNumber( const int nchars )
761 myFrame->setCharsNumber( nchars );
765 \brief Set the format Qt string for comments displayed under the list
766 of actions for one action and for several actions.
768 Example: "Undo %1 actions" format string will work as "Undo 3 actions"
769 when 3 actions are selected. The default format string is "%1".
771 \param c single action comment format
772 \param c multiple actions comment format
774 void QtxListAction::setComment( const QString& c, const QString& sc )
779 myFrame->setSingleComment( sc.isEmpty() ? c : sc );
780 myFrame->setMultipleComment( c );
784 \brief Create action widget.
786 This function is called whenever the action is added
787 to a container widget that supports custom widgets like menu or toolbar.
789 \param parent container widget the action is added to
790 \return tool button for toolbar and 0 otherwise
792 QWidget* QtxListAction::createWidget( QWidget* parent )
794 if ( parent && parent->inherits( "QMenu" ) )
797 QToolButton* tb = new QToolButton( parent );
798 tb->setText( text() );
799 tb->setIcon( icon() );
800 tb->setPopupMode( QToolButton::MenuButtonPopup );
801 tb->setMenu( myFrame );
802 tb->setEnabled( isEnabled() && !names().isEmpty() );
803 tb->setToolTip( toolTip() );
804 connect( tb, SIGNAL( clicked( bool ) ), this, SLOT( onSingle( bool ) ) );
810 \brief Destroy action widget.
812 This function is called whenever the action is removed
813 from a container widget that supports custom widgets like menu or toolbar.
815 \param widget container widget the action is removed from
817 void QtxListAction::deleteWidget( QWidget* widget )
823 \brief Initialize the action.
825 void QtxListAction::initialize()
827 setPopupMode( Item );
829 myFrame = new QtxListAction::ListFrame( this, 0 );
830 myFrame->setLinesNumber( 7 );
831 myFrame->setCharsNumber( 5 );
835 connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) );
836 connect( this, SIGNAL( triggered( bool ) ), this, SLOT( onSingle( bool ) ) );
840 \brief Called the action contents is changed.
842 void QtxListAction::onChanged()
844 QStringList lst = myFrame->names();
849 for ( QStringList::iterator iter = lst.begin(); iter != lst.end(); ++iter )
851 QAction* a = new QAction( *iter, menu() );
852 menu()->addAction( a );
853 connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTriggered( bool ) ) );
857 QList<QWidget*> widList = createdWidgets();
858 for ( QList<QWidget*>::iterator it = widList.begin(); it != widList.end(); ++it )
860 (*it)->setEnabled( isEnabled() && !lst.isEmpty() );
861 QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
864 tb->setText( text() );
865 tb->setIcon( icon() );
866 tb->setToolTip( toolTip() );
872 \brief Called when a user click action button.
876 void QtxListAction::onSingle( bool /*on*/ )
882 \brief Called when multiple items are selected.
884 void QtxListAction::onMultiple( const int numActions )
889 if ( numActions > 0 )
890 emit triggered( numActions );
894 \brief Called when user activates an items in the popup sub menu.
897 void QtxListAction::onTriggered( bool /*on*/ )
902 QList<QAction*> actionList = menu()->actions();
903 int idx = actionList.indexOf( ::qobject_cast<QAction*>( sender() ) );
907 emit triggered( idx + 1 );
911 \fn QtxListAction::activated(int numItems );
912 \brief This signal is emitted when an action is activated.
913 \param numItems number of items being selected in the action list.