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: QtxMultiAction.cxx
23 // Author: Sergey TELKOV
25 #include "QtxMultiAction.h"
32 #include <QToolButton>
33 #include <QApplication>
34 #include <QStyleOptionButton>
37 \class QtxMultiAction::Filter
38 \brief Waches for the buttons in the popup menu
39 to update the tool buttons state.
43 class QtxMultiAction::Filter : public QObject
46 //! \brief Constructor
47 Filter( QObject* parent ) : QObject( parent ) {}
50 //! \brief Process events from the child tool buttons
51 bool eventFilter( QObject* o, QEvent* e )
53 if ( e->type() == QEvent::Leave ) {
54 QToolButton* tb = qobject_cast<QToolButton*>( o );
58 return QObject::eventFilter( o, e );
63 \class QtxMultiAction::Menu
64 \brief Custom menu to be used with the toolbuttons as drop down list.
68 class QtxMultiAction::Menu : public QMenu
71 //! \brief Constructor
72 Menu( QWidget* parent = 0 ) : QMenu( parent ) {}
77 //! \brief Paint the button
78 virtual bool event( QEvent* e )
84 case QEvent::WhatsThis:
85 case QEvent::QueryWhatsThis:
87 QHelpEvent* help = static_cast<QHelpEvent*>( e );
88 QWidget* w = QApplication::widgetAt( help->globalPos() );
89 if ( w && Qtx::isParent( w, this ) )
91 QHelpEvent he( help->type(), w->mapFromGlobal( help->globalPos() ), help->globalPos() );
92 QApplication::sendEvent( w, &he );
97 case QEvent::StatusTip:
98 case QEvent::WhatsThisClicked:
101 QApplication::sendEvent( parentWidget(), e );
106 res = QMenu::event( e );
114 \class QtxMultiAction::Button
115 \brief Custom button to be used in the toolbar.
119 class QtxMultiAction::Button : public QToolButton
122 //! \brief Constructor
123 Button( QWidget* parent = 0 ) : QToolButton( parent ) {}
124 //! \brief Destructor
128 //! \brief Paint the button
129 virtual void paintEvent( QPaintEvent* e )
131 QToolButton::paintEvent( e );
138 QStyleOptionButton opt;
139 opt.initFrom( this );
140 QRect rect = opt.rect;
141 int x = rect.x(), y = rect.y();
143 opt.rect = QRect( x + w - s - m, y + h - s - m, s, s );
145 opt.rect = QRect( x + w - s - m - 1, y + h - s - m - 1, s, s );
148 style()->drawPrimitive( QStyle::PE_IndicatorSpinDown, &opt, &p );
153 \class QtxMultiAction
154 \brief The class QtxMultiAction implements modifiable action.
156 The QtxMultiAction class provides a possibility to assign a set of actions
157 (insertAction() function). The action can be used in the toolbar (and even
158 in the menu) to show drop-down menu with the list of the assigned actions.
160 Initially the first action from the list becomes current and it is activated
161 when the tool button is clicked by the user. If user presses and holds the mouse
162 button at the tool button, it shows the popup menu with all the assigned actions.
163 When the user selects any action from the popup menu, it becames current.
168 \param parent parent object
170 QtxMultiAction::QtxMultiAction( QObject* parent )
171 : QtxActionSet( parent ),
175 setMenu( new QMenu( 0 ) );
177 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
182 \param txt action menu text
183 \param parent parent object
185 QtxMultiAction::QtxMultiAction( const QString& txt, QObject* parent )
186 : QtxActionSet( parent ),
191 setMenu( new QMenu( 0 ) );
193 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
198 \param ico action menu icon
199 \param txt action menu text
200 \param parent parent object
202 QtxMultiAction::QtxMultiAction( const QIcon& ico, const QString& txt, QObject* parent )
203 : QtxActionSet( parent ),
209 setMenu( new QMenu( 0 ) );
211 connect( this, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
217 QtxMultiAction::~QtxMultiAction()
222 \brief Set current action.
223 \param a action to be set current
225 void QtxMultiAction::setActiveAction( QAction* a )
227 if ( a && actions().contains( a ) && a != myCurrent && a->isEnabled() )
235 \brief Get current action.
236 \return current action (0 if there is no active action)
238 QAction* QtxMultiAction::activeAction() const
244 \brief Called when the user activates the current action
245 (for example by clicking the tool button).
248 void QtxMultiAction::onClicked( bool /*on*/ )
251 myCurrent->activate( QAction::Trigger );
255 \brief Called when user activates any action from the
257 \param a action being activated
259 void QtxMultiAction::onTriggered( QAction* a )
264 QList<QWidget*> lst = createdWidgets();
265 for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
267 QToolButton* tb = ::qobject_cast<QToolButton*>( *it );
268 if ( tb && tb->menu() )
272 if ( myCurrent != a )
280 \brief Update action.
282 void QtxMultiAction::updateAction()
284 QtxActionSet::updateAction();
286 QList<QWidget*> lst = createdWidgets();
287 for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
288 updateButton( ::qobject_cast<QToolButton*>( *it ) );
292 \brief Update child (popup menu) action.
293 \param w widget menu widget
295 void QtxMultiAction::updateAction( QWidget* w )
300 if ( w->inherits( "QMenu" ) )
302 QtxActionSet::updateAction( menu() );
304 QApplication::instance()->removeEventFilter( this );
306 menu()->removeAction( this );
308 QApplication::instance()->installEventFilter( this );
313 \brief Check if the action itself should be invisible
314 (only child action are shown)
315 \return \c true if the action itself should be visible
317 bool QtxMultiAction::isEmptyAction() const
323 \brief Create widget to be displayed in the toolbar.
324 \param parent parent widget (should be toolbar)
325 \return toolbar button
327 QWidget* QtxMultiAction::createWidget( QWidget* parent )
329 QToolBar* tb = ::qobject_cast<QToolBar*>( parent );
333 QToolButton* w = new QToolButton( tb );
334 w->setMenu( new Menu( w ) );
335 w->setMouseTracking( true );
336 w->setFocusPolicy( Qt::NoFocus );
337 w->setIconSize( tb->iconSize() );
338 w->setToolButtonStyle( tb->toolButtonStyle() );
340 connect( w, SIGNAL( clicked( bool ) ), this, SLOT( onClicked( bool ) ) );
341 connect( tb, SIGNAL( iconSizeChanged( const QSize& ) ), w, SLOT( setIconSize( QSize ) ) );
342 connect( tb, SIGNAL( toolButtonStyleChanged( Qt::ToolButtonStyle ) ),
343 w, SLOT( setToolButtonStyle( Qt::ToolButtonStyle ) ) );
350 \brief Called when the child action is added to this action.
351 \param a child action being added
353 void QtxMultiAction::actionAdded( QAction* a )
355 connect( a, SIGNAL( changed() ), this, SLOT( onActionChanged() ) );
360 \brief Called when the child action is removed from this action.
361 \param a child action being removed
363 void QtxMultiAction::actionRemoved( QAction* a )
365 disconnect( a, SIGNAL( changed() ), this, SLOT( onActionChanged() ) );
367 if ( myCurrent != a )
378 \brief Update toolbar button.
379 \param btn toolbar button
381 void QtxMultiAction::updateButton( QToolButton* btn )
386 btn->setIcon( myCurrent ? myCurrent->icon() : QIcon() );
387 btn->setText( myCurrent ? myCurrent->text() : QString() );
388 btn->setToolTip( myCurrent ? myCurrent->toolTip() : QString() );
389 btn->setStatusTip( myCurrent ? myCurrent->statusTip() : QString() );
391 QMenu* pm = btn->menu();
396 for ( int i = 0; pm->layout() && i < pm->layout()->count(); i++ )
397 delete pm->layout()->widget();
401 QVBoxLayout* vbox = new QVBoxLayout( pm );
402 vbox->setMargin( 1 );
403 vbox->setSpacing( 0 );
404 Filter* filter = new Filter( vbox );
405 QList<QAction*> actList = actions();
406 for ( QList<QAction*>::iterator itr = actList.begin(); itr != actList.end(); ++itr )
408 QToolButton* b = new QToolButton( pm );
409 b->setDefaultAction( *itr );
410 b->setToolTip( (*itr)->toolTip() );
411 b->setStatusTip( (*itr)->statusTip() );
412 b->setAutoRaise( true );
413 b->setIconSize( btn->iconSize() );
414 b->setToolButtonStyle( btn->toolButtonStyle() );
415 b->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
416 b->installEventFilter( filter );
417 vbox->addWidget( b );
422 \brief Called when any child action is enabled/disabled.
424 If the current action is disabled, the multi-action switches
425 to first found enabled. If all child actions are disabled, the
426 action itself is also disabled.
428 void QtxMultiAction::onActionChanged()
430 if ( myCurrent && myCurrent->isEnabled() )
433 QList<QAction*> alist = actions();
435 for ( QList<QAction*>::ConstIterator it = alist.begin(); it != alist.end() && !a; ++it ) {
436 if ( (*it)->isEnabled() )
443 myCurrent = alist.isEmpty() ? 0 : alist.first();
445 setEnabled( myCurrent && myCurrent->isEnabled() );