1 // Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
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, or (at your option) any later version.
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/ or email : webmaster.salome@opencascade.com
20 // File: QtxMultiAction.cxx
21 // Author: Sergey TELKOV
23 #include "QtxMultiAction.h"
30 #include <QToolButton>
31 #include <QApplication>
32 #include <QStyleOptionButton>
35 \class QtxMultiAction::Filter
36 \brief Waches for the buttons in the popup menu
37 to update the tool buttons state.
41 class QtxMultiAction::Filter : public QObject
44 //! \brief Constructor
45 Filter( QObject* parent ) : QObject( parent ) {}
48 //! \brief Process events from the child tool buttons
49 bool eventFilter( QObject* o, QEvent* e )
51 if ( e->type() == QEvent::Leave ) {
52 QToolButton* tb = qobject_cast<QToolButton*>( o );
56 return QObject::eventFilter( o, e );
61 \class QtxMultiAction::Menu
62 \brief Custom menu to be used with the toolbuttons as drop down list.
66 class QtxMultiAction::Menu : public QMenu
69 //! \brief Constructor
70 Menu( QWidget* parent = 0 ) : QMenu( parent ) {}
75 //! \brief Paint the button
76 virtual bool event( QEvent* e )
82 case QEvent::WhatsThis:
83 case QEvent::QueryWhatsThis:
85 QHelpEvent* help = static_cast<QHelpEvent*>( e );
86 QWidget* w = QApplication::widgetAt( help->globalPos() );
87 if ( w && Qtx::isParent( w, this ) )
89 QHelpEvent he( help->type(), w->mapFromGlobal( help->globalPos() ), help->globalPos() );
90 QApplication::sendEvent( w, &he );
95 case QEvent::StatusTip:
96 case QEvent::WhatsThisClicked:
99 QApplication::sendEvent( parentWidget(), e );
104 res = QMenu::event( e );
112 \class QtxMultiAction::Button
113 \brief Custom button to be used in the toolbar.
117 class QtxMultiAction::Button : public QToolButton
120 //! \brief Constructor
121 Button( QWidget* parent = 0 ) : QToolButton( parent ) {}
122 //! \brief Destructor
126 //! \brief Paint the button
127 virtual void paintEvent( QPaintEvent* e )
129 QToolButton::paintEvent( e );
136 QStyleOptionButton opt;
137 opt.initFrom( this );
138 QRect rect = opt.rect;
139 int x = rect.x(), y = rect.y();
141 opt.rect = QRect( x + w - s - m, y + h - s - m, s, s );
143 opt.rect = QRect( x + w - s - m - 1, y + h - s - m - 1, s, s );
146 style()->drawPrimitive( QStyle::PE_IndicatorSpinDown, &opt, &p );
151 \class QtxMultiAction
152 \brief The class QtxMultiAction implements modifiable action.
154 The QtxMultiAction class provides a possibility to assign a set of actions
155 (insertAction() function). The action can be used in the toolbar (and even
156 in the menu) to show drop-down menu with the list of the assigned actions.
158 Initially the first action from the list becomes current and it is activated
159 when the tool button is clicked by the user. If user presses and holds the mouse
160 button at the tool button, it shows the popup menu with all the assigned actions.
161 When the user selects any action from the popup menu, it becames current.
166 \param parent parent object
168 QtxMultiAction::QtxMultiAction( QObject* parent )
169 : QtxActionSet( parent ),
173 setMenu( new QMenu( 0 ) );
175 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
180 \param txt action menu text
181 \param parent parent object
183 QtxMultiAction::QtxMultiAction( const QString& txt, QObject* parent )
184 : QtxActionSet( parent ),
189 setMenu( new QMenu( 0 ) );
191 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
196 \param ico action menu icon
197 \param txt action menu text
198 \param parent parent object
200 QtxMultiAction::QtxMultiAction( const QIcon& ico, const QString& txt, QObject* parent )
201 : QtxActionSet( parent ),
207 setMenu( new QMenu( 0 ) );
209 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
215 QtxMultiAction::~QtxMultiAction()
217 // to avoid memory leak
218 if( QMenu* aMenu = menu() )
226 \brief Set current action.
227 \param a action to be set current
229 void QtxMultiAction::setActiveAction( QAction* a )
231 if ( a && actions().contains( a ) && a != myCurrent && a->isEnabled() )
239 \brief Get current action.
240 \return current action (0 if there is no active action)
242 QAction* QtxMultiAction::activeAction() const
248 \brief Called when the user activates the current action
249 (for example by clicking the tool button).
252 void QtxMultiAction::onClicked( bool /*on*/ )
255 myCurrent->activate( QAction::Trigger );
259 \brief Called when user activates any action from the
261 \param a action being activated
263 void QtxMultiAction::onTriggered( QAction* a )
268 QList<QWidget*> lst = createdWidgets();
269 for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
271 QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
272 if ( tb && tb->menu() )
276 if ( myCurrent != a )
284 \brief Update action.
286 void QtxMultiAction::updateAction()
288 QtxActionSet::updateAction();
290 QList<QWidget*> lst = createdWidgets();
291 for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
292 updateButton( ::qobject_cast<QToolButton*>( *it ) );
296 \brief Update child (popup menu) action.
297 \param w widget menu widget
299 void QtxMultiAction::updateAction( QWidget* w )
304 if ( w->inherits( "QMenu" ) )
306 QtxActionSet::updateAction( menu() );
308 QApplication::instance()->removeEventFilter( this );
310 menu()->removeAction( this );
312 QApplication::instance()->installEventFilter( this );
317 \brief Check if the action itself should be invisible
318 (only child action are shown)
319 \return \c true if the action itself should be visible
321 bool QtxMultiAction::isEmptyAction() const
327 \brief Create widget to be displayed in the toolbar.
328 \param parent parent widget (should be toolbar)
329 \return toolbar button
331 QWidget* QtxMultiAction::createWidget( QWidget* parent )
333 QToolBar* tb = ::qobject_cast<QToolBar*>( parent );
337 QToolButton* w = new QToolButton( tb );
338 w->setMenu( new Menu( w ) );
339 w->setMouseTracking( true );
340 w->setFocusPolicy( Qt::NoFocus );
341 w->setIconSize( tb->iconSize() );
342 w->setToolButtonStyle( tb->toolButtonStyle() );
344 connect( w, SIGNAL( clicked( bool ) ), this, SLOT( onClicked( bool ) ) );
345 connect( tb, SIGNAL( iconSizeChanged( const QSize& ) ), w, SLOT( setIconSize( QSize ) ) );
346 connect( tb, SIGNAL( toolButtonStyleChanged( Qt::ToolButtonStyle ) ),
347 w, SLOT( setToolButtonStyle( Qt::ToolButtonStyle ) ) );
354 \brief Called when the child action is added to this action.
355 \param a child action being added
357 void QtxMultiAction::actionAdded( QAction* a )
359 connect( a, SIGNAL( changed() ), this, SLOT( onActionChanged() ) );
364 \brief Called when the child action is removed from this action.
365 \param a child action being removed
367 void QtxMultiAction::actionRemoved( QAction* a )
369 disconnect( a, SIGNAL( changed() ), this, SLOT( onActionChanged() ) );
371 if ( myCurrent != a )
382 \brief Update toolbar button.
383 \param btn toolbar button
385 void QtxMultiAction::updateButton( QToolButton* btn )
390 btn->setIcon( myCurrent ? myCurrent->icon() : QIcon() );
391 btn->setText( myCurrent ? myCurrent->text() : QString() );
392 btn->setToolTip( myCurrent ? myCurrent->toolTip() : QString() );
393 btn->setStatusTip( myCurrent ? myCurrent->statusTip() : QString() );
395 QMenu* pm = btn->menu();
400 for ( int i = 0; pm->layout() && i < pm->layout()->count(); i++ )
401 delete pm->layout()->widget();
405 QVBoxLayout* vbox = new QVBoxLayout( pm );
406 vbox->setMargin( 1 );
407 vbox->setSpacing( 0 );
408 Filter* filter = new Filter( vbox );
409 QList<QAction*> actList = actions();
410 for ( QList<QAction*>::iterator itr = actList.begin(); itr != actList.end(); ++itr )
412 QToolButton* b = new QToolButton( pm );
413 b->setDefaultAction( *itr );
414 b->setToolTip( (*itr)->toolTip() );
415 b->setStatusTip( (*itr)->statusTip() );
416 b->setAutoRaise( true );
417 b->setIconSize( btn->iconSize() );
418 b->setToolButtonStyle( btn->toolButtonStyle() );
419 b->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
420 b->installEventFilter( filter );
421 vbox->addWidget( b );
426 \brief Called when any child action is enabled/disabled.
428 If the current action is disabled, the multi-action switches
429 to first found enabled. If all child actions are disabled, the
430 action itself is also disabled.
432 void QtxMultiAction::onActionChanged()
434 if ( myCurrent && myCurrent->isEnabled() )
437 QList<QAction*> alist = actions();
439 for ( QList<QAction*>::ConstIterator it = alist.begin(); it != alist.end() && !a; ++it ) {
440 if ( (*it)->isEnabled() )
447 myCurrent = alist.isEmpty() ? 0 : alist.first();
449 setEnabled( myCurrent && myCurrent->isEnabled() );