1 // Copyright (C) 2007-2015 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, 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
22 // File: QtxMainWindow.cxx
23 // Author: Sergey TELKOV
25 #include "QtxMainWindow.h"
27 #include "QtxToolBar.h"
35 #include <QRubberBand>
36 #include <QMouseEvent>
37 #include <QApplication>
38 #include <QDesktopWidget>
41 \class QtxMainWindow::Filter
43 \brief Internal object used to filter child removal events for
44 specified widget from parent widget.
47 class QtxMainWindow::Filter : public QObject
50 Filter( QWidget*, QtxMainWindow*, QObject* = 0 );
53 virtual bool eventFilter( QObject*, QEvent* );
56 QMainWindow* myMain; //!< parent main window
57 QWidget* myWidget; //!< widget being watched
62 \param wid widget to be watched
63 \param mw parent main window
64 \param parent parent object (in terms of QObject)
66 QtxMainWindow::Filter::Filter( QWidget* wid, QtxMainWindow* mw, QObject* parent )
71 QApplication::instance()->installEventFilter( this );
77 QtxMainWindow::Filter::~Filter()
84 Watches for the specified widget and prevents its removal from the
87 \param o recevier object
90 bool QtxMainWindow::Filter::eventFilter( QObject* o, QEvent* e )
92 if ( myMain == o && e->type() == QEvent::ChildRemoved &&
93 myWidget == ((QChildEvent*)e)->child() )
96 return QObject::eventFilter( o, e );
100 \class QtxMainWindow::Resizer
102 \brief Internal object used to resize dock widgets.
105 class QtxMainWindow::Resizer : public QObject
108 Resizer( const QPoint&, const Qt::Orientation, QtxMainWindow* );
111 QMouseEvent* finalEvent() const;
112 void setFinalEvent( QMouseEvent* );
114 void setPosition( const QPoint& );
115 virtual bool eventFilter( QObject*, QEvent* );
118 void setFilters( bool );
123 QRubberBand* myRubber;
124 Qt::Orientation myOrient;
125 QMouseEvent* myFinEvent;
130 \param mw parent main window
132 QtxMainWindow::Resizer::Resizer( const QPoint& p, const Qt::Orientation o, QtxMainWindow* mw )
140 myRubber = new QRubberBand( QRubberBand::Line, 0 );
150 QtxMainWindow::Resizer::~Resizer()
157 void QtxMainWindow::Resizer::setPosition( const QPoint& pos )
162 QPoint min = myMain->mapToGlobal( myMain->rect().topLeft() );
163 QPoint max = myMain->mapToGlobal( myMain->rect().bottomRight() );
164 if ( myOrient == Qt::Horizontal ) {
165 int p = qMax( qMin( myPos.y(), max.y() ), min.y() );
166 r = QRect( myMain->mapToGlobal( QPoint( 0, 0 ) ).x(), p - 1, myMain->width(), 3 );
169 int p = qMax( qMin( myPos.x(), max.x() ), min.x() );
170 r = QRect( p - 1, myMain->mapToGlobal( QPoint( 0, 0 ) ).y(), 3, myMain->height() );
172 myRubber->setGeometry( r );
173 if ( !myRubber->isVisible() )
178 QMouseEvent* QtxMainWindow::Resizer::finalEvent() const
183 void QtxMainWindow::Resizer::setFinalEvent( QMouseEvent* e )
191 \param o recevier object
194 bool QtxMainWindow::Resizer::eventFilter( QObject* o, QEvent* e )
196 if ( e->type() == QEvent::Timer ) {
201 QApplication::postEvent( myMain, finalEvent() );
206 return QObject::eventFilter( o, e );
209 void QtxMainWindow::Resizer::setFilters( bool on )
213 myMain->layout()->installEventFilter( this );
215 myMain->layout()->removeEventFilter( this );
218 QTimer* t = qFindChild<QTimer*>( myMain->layout() );
221 t->installEventFilter( this );
223 t->removeEventFilter( this );
229 \brief Enhanced main window which supports dockable menubar and status bar
230 plus geometry saving/restoring.
235 \param parent parent widget
236 \param f widget flags (Qt::WindowFlags)
238 QtxMainWindow::QtxMainWindow( QWidget* parent, Qt::WindowFlags f )
239 : QMainWindow( parent, f ),
245 myFullScreenAllowed(true),
246 myMinimizeAllowed(true)
248 //rnv: Enables tooltips for inactive windows.
249 //rnv: For details see http://bugtracker.opencascade.com/show_bug.cgi?id=20893
250 setAttribute(Qt::WA_AlwaysShowToolTips);
256 QtxMainWindow::~QtxMainWindow()
258 setDockableMenuBar( false );
259 setDockableStatusBar( false );
263 \brief Check if the menu bar is dockable.
264 \return \c true if dockable menu bar exists
266 bool QtxMainWindow::isDockableMenuBar() const
268 return myMenuBar != 0;
272 \brief Set menu bar dockable/undockable.
273 \param on if \c true, make menu bar dockable, otherwise
274 make menu bar undockable
276 void QtxMainWindow::setDockableMenuBar( const bool on )
278 if ( isDockableMenuBar() == on )
281 QMenuBar* mb = menuBar();
285 if ( on && !myMenuBar )
287 myMenuBar = new QtxToolBar( true, this );
288 new Filter( mb, this, myMenuBar );
289 myMenuBar->setObjectName( "menu_bar_container" );
290 myMenuBar->setWindowTitle( tr( "Menu bar" ) );
291 myMenuBar->addWidget( mb );
292 myMenuBar->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
294 addToolBarBreak( Qt::TopToolBarArea );
295 addToolBar( Qt::TopToolBarArea, myMenuBar );
296 addToolBarBreak( Qt::TopToolBarArea );
298 connect( myMenuBar, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
300 else if ( !on && myMenuBar )
303 disconnect( myMenuBar, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
310 \brief Check if the status bar is dockable.
311 \return \c true if dockable status bar exists
313 bool QtxMainWindow::isDockableStatusBar() const
319 \brief Set status bar dockable/undockable.
320 \param on if \c true, make status bar dockable, otherwise
321 make status bar undockable
323 void QtxMainWindow::setDockableStatusBar( const bool on )
325 if ( isDockableStatusBar() == on )
328 QStatusBar* sb = statusBar();
332 if ( on && !myStatusBar )
334 sb->setMinimumWidth( 250 );
335 sb->setSizeGripEnabled( false );
336 myStatusBar = new QtxToolBar( true, this );
337 new Filter( sb, this, myStatusBar );
338 myStatusBar->setObjectName( "status_bar_container" );
339 myStatusBar->setWindowTitle( tr( "Status bar" ) );
340 myStatusBar->addWidget( sb );
341 myStatusBar->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
343 addToolBar( Qt::BottomToolBarArea, myStatusBar );
345 connect( myStatusBar, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
347 else if ( !on && myStatusBar )
350 disconnect( myStatusBar, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
354 sb->setSizeGripEnabled( true );
358 bool QtxMainWindow::isOpaqueResize() const
363 void QtxMainWindow::setOpaqueResize( bool on )
369 \brief Dump main window geometry to the string.
370 \return string represenation of the window geometry
372 QString QtxMainWindow::storeGeometry() const
374 QRect frame = frameGeometry();
375 QRect screen = QApplication::desktop()->availableGeometry( this );
378 if ( frame.left() == screen.left() )
380 else if ( frame.right() == screen.right() )
383 x = QString( "+%1" ).arg( frame.left() );
386 if ( frame.top() == screen.top() )
388 else if ( frame.bottom() == screen.bottom() )
391 y = QString( "+%1" ).arg( frame.top() );
393 QString geom = QString( "%1x%2%3%4" ).arg( width() ).arg( height() ).arg( x ).arg( y );
396 switch ( windowState() )
398 case Qt::WindowMaximized:
399 state = QString( "max" );
401 case Qt::WindowMinimized:
402 if ( isMinimizeAllowed() ) state = QString( "min" );
404 case Qt::WindowFullScreen:
405 state = isFullScreenAllowed() ? QString( "full" ) : QString( "max" );
409 if ( !state.isEmpty() )
410 geom += QString( ":" ) + state;
416 \brief Restore main window geometry from the string.
417 \param str string represenation of the window geometry
419 void QtxMainWindow::retrieveGeometry( const QString& str )
425 QRect rect = geometry();
426 QRect screen = QApplication::desktop()->availableGeometry( this );
428 QRegExp szRx( "(\\d+%?)\\s*x\\s*(\\d+%?)" );
429 if ( szRx.indexIn( geom ) != -1 )
433 int ws = geometryValue( szRx.cap( 1 ).trimmed(), w, wp );
436 w = screen.width() * qMax( qMin( w, 100 ), 0 ) / 100;
441 int hs = geometryValue( szRx.cap( 2 ).trimmed(), h, hp );
444 h = screen.height() * qMax( qMin( h, 100 ), 0 ) / 100;
448 rect.setSize( QSize( w, h ) );
451 QRegExp posRx( "([+|-]\\d+%?)\\s*([+|-]\\d+%?)" );
452 if ( posRx.indexIn( geom ) != -1 )
456 int xs = geometryValue( posRx.cap( 1 ).trimmed(), x, xp );
461 x = screen.width() * qMax( qMin( x, 100 ), 0 ) / 100;
462 x = ( xs > 0 ? x : screen.right() - x - rect.width() ) + frameGeometry().x() - geometry().x();
467 int ys = geometryValue( posRx.cap( 2 ).trimmed(), y, yp );
472 y = screen.height() * qMax( qMin( y, 100 ), 0 ) / 100;
473 y = ( ys > 0 ? y : screen.bottom() - y - rect.height() ) + frameGeometry().y() - geometry().y();
480 Qt::WindowState state = Qt::WindowNoState;
482 QRegExp stRx( ":(\\w+)" );
483 if ( stRx.indexIn( geom ) != -1 )
485 QString stStr = stRx.cap( 1 ).trimmed().toLower();
486 if ( stStr.startsWith( QString( "max" ) ) ) {
487 state = Qt::WindowMaximized;
489 else if ( stStr.startsWith( QString( "min" ) ) ) {
490 if ( isMinimizeAllowed() )
491 state = Qt::WindowMinimized;
493 else if ( stStr.startsWith( QString( "full" ) ) ) {
494 state = isFullScreenAllowed() ? Qt::WindowFullScreen : Qt::WindowMaximized;
498 resize( rect.size() );
499 move( rect.topLeft() );
501 if ( state != Qt::WindowNoState )
502 setWindowState( state );
506 \brief Retrieve numerical value from the string.
508 Numerical value in the string have the structure [+|-]\d*[%],
509 that is one or more digits which can start from "+" or "-" and
510 can end with "%" symbol.
512 \param str string being converted
513 \param num returning value (> 0)
514 \param percent if string ends with "%" this parameter is equal to \c true after
515 returning from the function
516 \return -1 if value < 0, 1 if value > 0 and 0 in case of error
518 int QtxMainWindow::geometryValue( const QString& str, int& num, bool& percent ) const
522 QString numStr = str;
523 if ( numStr.startsWith( "+" ) || numStr.startsWith( "-" ) )
525 res = numStr.startsWith( "+" ) ? 1 : -1;
526 numStr = numStr.mid( 1 );
529 percent = numStr.endsWith( "%" );
531 numStr = numStr.mid( 0, numStr.length() - 1 );
534 num = numStr.toInt( &ok );
542 \brief Called when child object (menu bar, status bar) is destroyed.
544 Clears internal pointer to prevent crashes.
546 \param obj signal sender (object being destroyed)
548 void QtxMainWindow::onDestroyed( QObject* obj )
551 if ( obj == myMenuBar )
556 else if ( obj == myStatusBar )
564 QChildEvent ce( QEvent::ChildRemoved, o );
565 QApplication::sendEvent( this, &ce );
569 bool QtxMainWindow::event( QEvent* e )
571 // if ( e->type() == QEvent::WindowDeactivate ) {
572 // printf( "----------------> Deactivated\n" );
576 QMouseEvent* me = static_cast<QMouseEvent*>( e );
577 if ( ( e->type() == QEvent::MouseButtonRelease && me->button() == Qt::LeftButton ) ||
578 ( e->type() == QEvent::MouseButtonPress && me->button() != Qt::LeftButton ) ) {
579 if ( me->button() == Qt::LeftButton ) {
581 QMainWindow::event( myMouseMove );
586 QMouseEvent* me = static_cast<QMouseEvent*>( e );
587 myResizer->setFinalEvent( new QMouseEvent( QEvent::MouseButtonRelease, me->pos(), me->globalPos(),
588 Qt::LeftButton, me->buttons(), me->modifiers() ) );
595 if ( myResizer && e->type() == QEvent::MouseMove ) {
596 QMouseEvent* me = static_cast<QMouseEvent*>( e );
599 myMouseMove = new QMouseEvent( me->type(), me->pos(), me->globalPos(),
600 me->button(), me->buttons(), me->modifiers() );
601 myResizer->setPosition( me->globalPos() );
604 bool ok = QMainWindow::event( e );
606 if ( !myResizer && e->type() == QEvent::MouseButtonPress ) {
607 QMouseEvent* me = static_cast<QMouseEvent*>( e );
608 if ( !isOpaqueResize() && ok && testAttribute( Qt::WA_SetCursor ) && me->button() == Qt::LeftButton ) {
611 switch ( cursor().shape() )
613 case Qt::SplitHCursor:
616 case Qt::SplitVCursor:
624 myResizer = new Resizer( me->globalPos(), o, this );
625 myMouseMove = new QMouseEvent( me->type(), me->pos(), me->globalPos(),
626 me->button(), me->buttons(), me->modifiers() );
635 \brief FullScreenAllowed flag allowed dump in the main window geometry
636 Qt::WindowFullScreen parameter.
637 \return \c FullScreenAllowed flag.
639 bool QtxMainWindow::isFullScreenAllowed() const {
640 return myFullScreenAllowed;
645 \brief Set FullScreenAllowed flag.
646 The default value is true.
647 \param f value of the FullScreenAllowed flag.
649 void QtxMainWindow::setFullScreenAllowed( const bool f ) {
650 myFullScreenAllowed = f;
654 \brief MinimizeAllowed flag allowed dump in the main window geometry
655 Qt::WindowMinimized parameter.
656 \return \c MinimizeAllowed flag.
658 bool QtxMainWindow::isMinimizeAllowed() const {
659 return myMinimizeAllowed;
664 \brief Set MinimizeAllowed flag.
665 The default value is true.
666 \param f value of the MinimizeAllowed flag.
668 void QtxMainWindow::setMinimizeAllowed( const bool f ) {
669 myMinimizeAllowed = f;