X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FQtx%2FQtxWorkstack.cxx;h=9de0de4c71648c325151c48f0b81eabb0a731fa8;hb=5311944be0aed7d19e26c1e962ba7fd004178827;hp=f67e0cdb291380f5924448e6f4466eebd83f7cff;hpb=1c889394b028b786898a995d38c07c8f3d564837;p=modules%2Fgui.git diff --git a/src/Qtx/QtxWorkstack.cxx b/src/Qtx/QtxWorkstack.cxx index f67e0cdb2..9de0de4c7 100644 --- a/src/Qtx/QtxWorkstack.cxx +++ b/src/Qtx/QtxWorkstack.cxx @@ -1,24 +1,25 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. // -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. // -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // File: QtxWorkstack.cxx // Author: Sergey TELKOV // @@ -31,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -50,12 +51,32 @@ class QtxWorkstackArea::WidgetEvent : public QEvent { public: - WidgetEvent( Type t, QWidget* w = 0 ) : QEvent( t ), myWidget( w ) {}; + WidgetEvent( Type t, QtxWorkstackChild* w = 0 ) : QEvent( t ), myChild( w ) {}; + + QtxWorkstackChild* child() const { return myChild; } + +private: + QtxWorkstackChild* myChild; // event receiver widget +}; + +/*! + \class QtxWorkstackArea::RestoreEvent + \internal + \brief Internal class used to forward restore info events to the workarea +*/ + +class QtxWorkstackArea::RestoreEvent : public QtxWorkstackArea::WidgetEvent +{ +public: + RestoreEvent( Type t, int id, int f, QtxWorkstackChild* w ) + : WidgetEvent( t, w ), myId( id ), myFlags( f ) {}; - QWidget* widget() const { return myWidget; } + int id() const { return myId; } + int flags() const { return myFlags; } private: - QWidget* myWidget; // event receiver widget + int myId; + int myFlags; }; /*! @@ -168,13 +189,13 @@ void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab ) /*! \brief Called when drop operation is finished. - + Inserts dropped widget to the target workarea. */ void QtxWorkstackDrag::dropWidget() { if ( myArea ) - myArea->insertWidget( myChild->widget(), myTab ); + myArea->insertChild( myChild, myTab ); } /*! @@ -280,7 +301,7 @@ QSize CloseButton::sizeHint() const { ensurePolished(); int dim = 0; - if( !icon().isNull() ) + if( !icon().isNull() ) { const QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), QIcon::Normal ); @@ -295,8 +316,8 @@ QSize CloseButton::sizeHint() const \return minimum size value */ QSize CloseButton::minimumSizeHint() const -{ - return sizeHint(); +{ + return sizeHint(); } /*! @@ -352,11 +373,142 @@ void CloseButton::paintEvent( QPaintEvent* ) QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), isEnabled() ? underMouse() ? QIcon::Active : QIcon::Normal - : QIcon::Disabled, + : QIcon::Disabled, isDown() ? QIcon::On : QIcon::Off ); style()->drawItemPixmap( &p, r, Qt::AlignCenter, pm ); } + +/*! + \class QtxWorkstackSplitter + \internal + \brief Workstack splitter. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +QtxWorkstackSplitter::QtxWorkstackSplitter( QWidget* parent ) +: QSplitter( parent ) +{ + setChildrenCollapsible( false ); +} + +/*! + \brief Destructor. +*/ +QtxWorkstackSplitter::~QtxWorkstackSplitter() +{ +} + +/*! + \brief Get parent workstack + \return workstack owning this workarea +*/ +QtxWorkstack* QtxWorkstackSplitter::workstack() const +{ + QtxWorkstack* ws = 0; + QWidget* wid = parentWidget(); + while ( wid && !ws ) + { + ws = ::qobject_cast( wid ); + wid = wid->parentWidget(); + } + return ws; +} + +/*! + \brief Save the widget area configuration into data stream. +*/ +void QtxWorkstackSplitter::saveState( QDataStream& stream ) const +{ + stream << QtxWorkstack::SplitMarker; + + uchar flags = 0; + if ( orientation() == Qt::Horizontal ) + flags |= QtxWorkstack::Horizontal; + + stream << flags; + stream << count(); + + QList sz = sizes(); + for ( QList::const_iterator it = sz.begin(); it != sz.end(); ++it ) + stream << *it; + + for ( int i = 0; i < count(); i++ ) + { + QWidget* wid = widget( i ); + QtxWorkstackSplitter* split = ::qobject_cast( wid ); + if ( split ) + split->saveState( stream ); + else + { + QtxWorkstackArea* area = ::qobject_cast( wid ); + if ( area ) + area->saveState( stream ); + } + } +} + +/*! + \brief Restore the widget area configuration from data stream info. + \return \c true in successful case. +*/ +bool QtxWorkstackSplitter::restoreState( QDataStream& stream, QMap& map ) +{ + int num = 0; + uchar flags = 0; + + stream >> flags; + stream >> num; + + setOrientation( flags & QtxWorkstack::Horizontal ? Qt::Horizontal : Qt::Vertical ); + + QList sz; + for ( int s = 0; s < num; s++ ) + { + int sn = 0; + stream >> sn; + sz.append( sn ); + } + + bool ok = true; + for ( int i = 0; i < num && ok; i++ ) + { + int marker; + stream >> marker; + + if ( stream.status() != QDataStream::Ok ) + return false; + + if ( marker == QtxWorkstack::SplitMarker ) + { + QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this ); + addWidget( split ); + split->setVisible( true ); + + ok = split->restoreState( stream, map ); + } + else if ( marker == QtxWorkstack::AreaMarker ) + { + QtxWorkstack* ws = workstack(); + QtxWorkstackArea* area = ws->createArea( this ); + addWidget( area ); + area->setVisible( true ); + + ok = area->restoreState( stream, map ); + } + else + return false; + } + + if ( ok ) + setSizes( sz ); + + return ok; +} + /*! \class QtxWorkstackArea \internal @@ -376,16 +528,16 @@ QtxWorkstackArea::QtxWorkstackArea( QWidget* parent ) base->setMargin( frameWidth() ); base->setSpacing( 0 ); - QWidget* top = new QWidget( this ); - base->addWidget( top ); + myTop = new QWidget( this ); + base->addWidget( myTop ); - QHBoxLayout* tl = new QHBoxLayout( top ); + QHBoxLayout* tl = new QHBoxLayout( myTop ); tl->setMargin( 0 ); - myBar = new QtxWorkstackTabBar( top ); + myBar = new QtxWorkstackTabBar( myTop ); tl->addWidget( myBar, 1 ); - CloseButton* close = new CloseButton( top ); + CloseButton* close = new CloseButton( myTop ); close->setIcon( style()->standardIcon( QStyle::SP_TitleBarCloseButton ) ); myClose = close; tl->addWidget( myClose ); @@ -430,8 +582,8 @@ bool QtxWorkstackArea::isNull() const bool QtxWorkstackArea::isEmpty() const { bool res = false; - for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !res; ++it ) - res = it.value().vis; + for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it ) + res = (*it)->visibility(); return !res; } @@ -442,28 +594,49 @@ bool QtxWorkstackArea::isEmpty() const \param f widget flags \return child widget container object (or 0 if index is invalid) */ -QWidget* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f ) +QtxWorkstackChild* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f ) { if ( !wid ) return 0; - int pos = myList.indexOf( wid ); + QtxWorkstackChild* c = child( wid ); + if ( !c ) + c = new QtxWorkstackChild( wid, myStack, f ); + + insertChild( c, idx ); + + return c; +} + +void QtxWorkstackArea::insertChild( QtxWorkstackChild* child, const int idx ) +{ + if ( !child ) + return; + + QtxWorkstackArea* a = child->area(); + if ( a && a != this ) + a->removeChild( child, false ); + + int pos = myList.indexOf( child ); if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) ) - return 0; + return; + + bool found = myList.contains( child ); - myList.removeAll( wid ); + myList.removeAll( child ); pos = idx < 0 ? myList.count() : idx; - myList.insert( qMin( pos, (int)myList.count() ), wid ); - if ( !myInfo.contains( wid ) ) + myList.insert( qMin( pos, (int)myList.count() ), child ); + + if ( !found ) { - QtxWorkstackChild* child = new QtxWorkstackChild( wid, myStack, f ); - myChild.insert( wid, child ); - myInfo.insert( wid, WidgetInfo() ); - myInfo[wid].id = generateId(); - myInfo[wid].vis = wid->isVisibleTo( wid->parentWidget() ); + bool hasId = false; + for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !hasId; ++it ) + hasId = (*it)->id() == child->id(); + + if ( hasId || child->id() < 0 ) + child->setId( generateId() ); connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) ); - connect( wid, SIGNAL( destroyed() ), this, SLOT( onWidgetDestroyed() ) ); connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) ); connect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) ); connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) ); @@ -472,10 +645,8 @@ QWidget* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::Window updateState(); - setWidgetActive( wid ); - wid->setFocus(); - - return myChild[wid]; + setWidgetActive( child->widget() ); + child->widget()->setFocus(); } /*! @@ -497,37 +668,42 @@ void QtxWorkstackArea::onContextMenuRequested( QPoint p ) } /*! - \brief Called when area's child widget is destroyed. - - Removes child widget from the area. + \brief Remove widget from workarea. + \param wid widget to be removed + \param del if \c true the widget should be also deleted */ -void QtxWorkstackArea::onWidgetDestroyed() +void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) { - if ( sender() ) - removeWidget( (QWidget*)sender(), false ); + removeChild( child( wid ), del ); } /*! - \brief Remove widget from workarea. - \param wid widget to be removed + \brief Remove child from workarea. + \param child child to be removed \param del if \c true the widget should be also deleted */ -void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) +void QtxWorkstackArea::removeChild( QtxWorkstackChild* child, const bool del ) { - if ( !myList.contains( wid ) ) + if ( !myList.contains( child ) ) return; - if ( myBar->indexOf( widgetId( wid ) ) != -1 ) - myBar->removeTab( myBar->indexOf( widgetId( wid ) ) ); + myStack->removeWidget( child ); - myStack->removeWidget( child( wid ) ); + if ( myBar->indexOf( child->id() ) != -1 ) + myBar->removeTab( myBar->indexOf( child->id() ) ); - myList.removeAll( wid ); - myInfo.remove( wid ); - myChild.remove( wid ); + myList.removeAll( child ); if ( del ) - delete child( wid ); + delete child; + else if ( child->widget() ) + { + disconnect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) ); + disconnect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) ); + disconnect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) ); + disconnect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) ); + disconnect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) ); + } if ( isNull() ) deleteLater(); @@ -535,6 +711,11 @@ void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) updateState(); } +QList QtxWorkstackArea::childList() const +{ + return myList; +} + /*! \brief Get all visible child widgets. \return list of visible child widgets @@ -542,10 +723,11 @@ void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) QWidgetList QtxWorkstackArea::widgetList() const { QWidgetList lst; - for ( QWidgetList::const_iterator it = myList.begin(); it != myList.end(); ++it ) + for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it ) { - if ( widgetVisibility( *it ) ) - lst.append( *it ); + QtxWorkstackChild* c = *it; + if ( c->visibility() ) + lst.append( c->widget() ); } return lst; } @@ -575,26 +757,7 @@ void QtxWorkstackArea::setActiveWidget( QWidget* wid ) */ bool QtxWorkstackArea::contains( QWidget* wid ) const { - return myList.contains( wid ); -} - -/*! - \brief Show/hide workarea. - \param on new visibility state -*/ -void QtxWorkstackArea::setVisible( bool on ) -{ - QMap map; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) - { - map.insert( *it, isBlocked( *it ) ); - setBlocked( *it, true ); - } - - QFrame::setVisible( on ); - - for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) - setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); + return child( wid ); } /*! @@ -628,8 +791,7 @@ QtxWorkstack* QtxWorkstackArea::workstack() const QWidget* wid = parentWidget(); while ( wid && !ws ) { - if ( wid->inherits( "QtxWorkstack" ) ) - ws = (QtxWorkstack*)wid; + ws = ::qobject_cast( wid ); wid = wid->parentWidget(); } return ws; @@ -664,6 +826,92 @@ bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e ) return false; } +/*! + \brief Save the own widgets configuration into data stream. +*/ +void QtxWorkstackArea::saveState( QDataStream& stream ) const +{ + stream << QtxWorkstack::AreaMarker; + stream << myList.count(); + stream << myBar->tabId( myBar->currentIndex() ); + for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it ) + { + QtxWorkstackChild* c = *it; + + stream << QtxWorkstack::WidgetMarker; + + stream << c->widget()->objectName(); + stream << c->id(); + + uchar flags = 0; + if ( c->visibility() ) + flags |= QtxWorkstack::Visible; + + stream << flags; + } +} + +/*! + \brief Restore the widgets configuration from data stream info. + \return \c true in successful case. +*/ +bool QtxWorkstackArea::restoreState( QDataStream& stream, QMap& map ) +{ + int num = 0; + int cur = -1; + + stream >> num; + stream >> cur; + + QtxWorkstackChild* curChild = 0; + for ( int i = 0; i < num; i++ ) + { + int marker; + stream >> marker; + + if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::WidgetMarker ) + return false; + + QString name; + stream >> name; + + int id = -1; + stream >> id; + + uchar flags = 0; + stream >> flags; + + QtxWorkstackChild* c = map.contains( name ) ? map[name] : 0; + if ( !c ) + { + qWarning( "QtxWorkstack: Restored child widget \"%s\" not found.", (const char*)name.toLatin1() ); + return false; + } + + map.remove( name ); + + if ( id == cur ) + curChild = c; + + QApplication::postEvent( this, new RestoreEvent( (QEvent::Type)RestoreWidget, id, flags, c ) ); + } + + if ( curChild ) + QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)MakeCurrent, curChild ) ); + + return true; +} + +/*! + \brief Show/Hide tab bar. +*/ +void QtxWorkstackArea::showTabBar( bool visible) +{ + myTop->setVisible(visible); + myBar->setVisible(visible); +} + + /*! \brief Get rectangle to be drawn when highlighting drop area. \return area drop rectangle @@ -715,6 +963,11 @@ void QtxWorkstackArea::customEvent( QEvent* e ) { case ActivateWidget: myBar->updateActiveState(); + // IMN 27/03/2015: This workaround caused by the bug INT PAL 0052623: OCC view blinking when + // using polyline sketcher which is reproduced on Unix systems with qt-4.8.4. + myStack->setUpdatesEnabled( false ); + updateCurrent(); + myStack->setUpdatesEnabled( true ); emit activated( activeWidget() ); break; case FocusWidget: @@ -727,17 +980,30 @@ void QtxWorkstackArea::customEvent( QEvent* e ) if ( activeWidget()->focusWidget()->hasFocus() ) { QFocusEvent in( QEvent::FocusIn ); - QApplication::sendEvent( this, &in ); - } - else { + QApplication::sendEvent( this, &in ); + } + else + { activeWidget()->focusWidget()->setFocus(); - myBar->updateActiveState(); - } + myBar->updateActiveState(); + } } } break; - case RemoveWidget: - removeWidget( we->widget() ); + case MakeCurrent: + if ( we->child()->widget() ) + setActiveWidget( we->child()->widget() ); + break; + case RestoreWidget: + if ( we->child() ) + { + QtxWorkstackChild* c = we->child(); + RestoreEvent* re = (RestoreEvent*)we; + if ( c->widget() ) + c->widget()->setVisible( re->flags() & QtxWorkstack::Visible ); + c->setId( re->id() ); + insertChild( c ); + } break; default: break; @@ -807,19 +1073,7 @@ void QtxWorkstackArea::onDragActiveTab() */ void QtxWorkstackArea::onChildDestroyed( QObject* obj ) { - QtxWorkstackChild* child = (QtxWorkstackChild*)obj; - myStack->removeWidget( child ); - - QWidget* wid = 0; - for ( ChildMap::ConstIterator it = myChild.begin(); it != myChild.end() && !wid; ++it ) - { - if ( it.value() == child ) - wid = it.key(); - } - - myChild.remove( wid ); - - QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)RemoveWidget, wid ) ); + removeChild( (QtxWorkstackChild*)obj, false ); } /*! @@ -828,7 +1082,7 @@ void QtxWorkstackArea::onChildDestroyed( QObject* obj ) */ void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) { - setWidgetShown( c->widget(), true ); + updateState(); } /*! @@ -837,7 +1091,7 @@ void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) */ void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c ) { - setWidgetShown( c->widget(), false ); + updateState(); } /*! @@ -865,19 +1119,9 @@ void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c ) */ void QtxWorkstackArea::updateCurrent() { - QMap map; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) - { - map.insert( *it, isBlocked( *it ) ); - setBlocked( *it, true ); - } - - QWidget* cur = child( widget( myBar->tabId( myBar->currentIndex() ) ) ); + QWidget* cur = child( myBar->tabId( myBar->currentIndex() ) ); if ( cur ) myStack->setCurrentWidget( cur ); - - for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) - setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); } /*! @@ -901,13 +1145,9 @@ void QtxWorkstackArea::updateTab( QWidget* wid ) */ QWidget* QtxWorkstackArea::widget( const int id ) const { - QWidget* wid = 0; - for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !wid; ++it ) - { - if ( it.value().id == id ) - wid = it.key(); - } - return wid; + QtxWorkstackChild* c = child( id ); + + return c ? c->widget() : 0; } /*! @@ -917,23 +1157,9 @@ QWidget* QtxWorkstackArea::widget( const int id ) const */ int QtxWorkstackArea::widgetId( QWidget* wid ) const { - int id = -1; - if ( myInfo.contains( wid ) ) - id = myInfo[wid].id; - return id; -} + QtxWorkstackChild* c = child( wid ); -/*! - \brief Get child widget's visibility. - \param wid widget - \return \c true if widget is visible -*/ -bool QtxWorkstackArea::widgetVisibility( QWidget* wid ) const -{ - bool res = false; - if ( myInfo.contains( wid ) ) - res = myInfo[wid].vis; - return res; + return c ? c->id() : -1; } /*! @@ -949,20 +1175,6 @@ void QtxWorkstackArea::setWidgetActive( QWidget* wid ) myBar->setCurrentIndex( myBar->indexOf( id ) ); } -/*! - \brief Show/hide child widget. - \param wid widget - \param on new visibility state -*/ -void QtxWorkstackArea::setWidgetShown( QWidget* wid, const bool on ) -{ - if ( isBlocked( wid ) || !myInfo.contains( wid ) || myInfo[wid].vis == on ) - return; - - myInfo[wid].vis = on; - updateState(); -} - /*! \brief Update internal state. */ @@ -979,15 +1191,16 @@ void QtxWorkstackArea::updateState() QWidget* prev = activeWidget(); int idx = 0; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) + for ( ChildList::iterator it = myList.begin(); it != myList.end(); ++it ) { - QWidget* wid = *it; - int id = widgetId( wid ); + QtxWorkstackChild* cont = *it; + QWidget* wid = cont->widget();; + int id = cont->id(); if ( id < 0 ) continue; - bool vis = widgetVisibility( wid ); + bool vis = cont->visibility(); int cIdx = myBar->indexOf( id ); if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) ) @@ -998,11 +1211,6 @@ void QtxWorkstackArea::updateState() updateTab( wid ); - bool block = isBlocked( wid ); - setBlocked( wid, true ); - - QtxWorkstackChild* cont = child( wid ); - if ( !vis ) myStack->removeWidget( cont ); else if ( myStack->indexOf( cont ) < 0 ) @@ -1010,29 +1218,27 @@ void QtxWorkstackArea::updateState() if ( vis ) idx++; - - setBlocked( wid, block ); } int curId = widgetId( prev ); if ( myBar->indexOf( curId ) < 0 ) { - QWidget* wid = 0; - int pos = myList.indexOf( prev ); - for ( int i = pos - 1; i >= 0 && !wid; i-- ) + QtxWorkstackChild* c = 0; + int pos = myList.indexOf( child( prev ) ); + for ( int i = pos - 1; i >= 0 && !c; i-- ) { - if ( widgetVisibility( myList.at( i ) ) ) - wid = myList.at( i ); + if ( myList.at( i )->visibility() ) + c = myList.at( i ); } - for ( int j = pos + 1; j < (int)myList.count() && !wid; j++ ) + for ( int j = pos + 1; j < (int)myList.count() && !c; j++ ) { - if ( widgetVisibility( myList.at( j ) ) ) - wid = myList.at( j ); + if ( myList.at( j )->visibility() ) + c = myList.at( j ); } - if ( wid ) - curId = widgetId( wid ); + if ( c ) + curId = c->id(); } myBar->setCurrentIndex( myBar->indexOf( curId ) ); @@ -1076,8 +1282,8 @@ int QtxWorkstackArea::generateId() const { QMap map; - for ( WidgetInfoMap::const_iterator it = myInfo.begin(); it != myInfo.end(); ++it ) - map.insert( it.value().id, 0 ); + for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it ) + map.insert( (*it)->id(), 0 ); int id = 0; while ( map.contains( id ) ) @@ -1086,29 +1292,6 @@ int QtxWorkstackArea::generateId() const return id; } -/*! - \brief Check if the child wiget is blocked. - \param wid widget - \return \c true if the widget is blocked -*/ -bool QtxWorkstackArea::isBlocked( QWidget* wid ) const -{ - return myBlock.contains( wid ); -} - -/*! - \brief Block widget. - \param wid widget - \param on new blocked state -*/ -void QtxWorkstackArea::setBlocked( QWidget* wid, const bool on ) -{ - if ( on ) - myBlock.insert( wid, 0 ); - else - myBlock.remove( wid ); -} - /*! \brief Get child widget container. \param wid child widget @@ -1117,11 +1300,25 @@ void QtxWorkstackArea::setBlocked( QWidget* wid, const bool on ) QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const { QtxWorkstackChild* res = 0; - if ( myChild.contains( wid ) ) - res = myChild[wid]; + for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it ) + { + if ( (*it)->widget() == wid ) + res = *it; + } return res; } +QtxWorkstackChild* QtxWorkstackArea::child( const int id ) const +{ + QtxWorkstackChild* c = 0; + for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !c; ++it ) + { + if ( (*it)->id() == id ) + c = *it; + } + return c; +} + /*! \fn void QtxWorkstackArea::activated( QWidget* w ) \brief Emitted when child widget is activated. @@ -1155,15 +1352,23 @@ QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const */ QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f ) : QWidget( parent ), + myId( 0 ), myWidget( wid ) { - myWidget->setParent( this, f ); - myWidget->installEventFilter( this ); - QVBoxLayout* base = new QVBoxLayout( this ); - base->setMargin( 0 ); - base->addWidget( myWidget ); + if ( myWidget ) + { + myWidget->setParent( this, f ); + myWidget->installEventFilter( this ); + if ( myWidget->focusProxy() ) + myWidget->focusProxy()->installEventFilter( this ); + myWidget->setVisible( myWidget->isVisibleTo( myWidget->parentWidget() ) ); - connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + QVBoxLayout* base = new QVBoxLayout( this ); + base->setMargin( 0 ); + base->addWidget( myWidget ); + + connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + } } /*! @@ -1180,6 +1385,8 @@ QtxWorkstackChild::~QtxWorkstackChild() widget()->hide(); widget()->removeEventFilter( this ); + if ( widget()->focusProxy() ) + widget()->focusProxy()->removeEventFilter( this ); widget()->setParent( 0 ); } @@ -1193,6 +1400,43 @@ QWidget* QtxWorkstackChild::widget() const return myWidget; } +/*! + \brief Returns the id. +*/ +int QtxWorkstackChild::id() const +{ + return myId; +} + +/*! + \brief Sets the id. +*/ +void QtxWorkstackChild::setId( const int id ) +{ + myId = id; +} + +/*! + \brief Returns true if this child window should be visible. +*/ +bool QtxWorkstackChild::visibility() +{ + return myWidget ? myWidget->isVisibleTo( this ) : false; +} + +QtxWorkstackArea* QtxWorkstackChild::area() const +{ + QtxWorkstackArea* a = 0; + QWidget* w = parentWidget(); + while ( !a && w ) + { + a = ::qobject_cast( w ); + w = w->parentWidget(); + } + + return a; +} + /*! \brief Custom event filter. @@ -1227,10 +1471,6 @@ bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e ) */ void QtxWorkstackChild::onDestroyed( QObject* obj ) { - if ( obj != widget() ) - return; - - myWidget = 0; deleteLater(); } @@ -1284,7 +1524,7 @@ void QtxWorkstackChild::childEvent( QChildEvent* e ) */ QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent ) : QTabBar( parent ), - myId( -1 ) + myId( -1 ),myActive(false) { setDrawBase( true ); setElideMode( Qt::ElideNone ); @@ -1469,11 +1709,11 @@ void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool \brief Workstack widget. Organizes the child widgets in the tabbed space. - Allows splitting the working area to arrange the child widgets in + Allows splitting the working area to arrange the child widgets in arbitrary way. Any widgets can be moved to another working area with drag-n-drop operation. - This widget can be used as workspace of the application main window, + This widget can be used as workspace of the application main window, for example, as kind of implementation of multi-document interface. */ @@ -1508,8 +1748,7 @@ QtxWorkstack::QtxWorkstack( QWidget* parent ) QVBoxLayout* base = new QVBoxLayout( this ); base->setMargin( 0 ); - mySplit = new QSplitter( this ); - mySplit->setChildrenCollapsible( false ); + mySplit = new QtxWorkstackSplitter( this ); base->addWidget( mySplit ); } @@ -1521,9 +1760,9 @@ QtxWorkstack::~QtxWorkstack() } /*! - \brief Get list of all widgets in all areas or in specified area which given + \brief Get list of all widgets in all areas or in specified area which given widget belongs to - \param wid widget specifying area if it is equal to null when widgets of all + \param wid widget specifying area if it is equal to null when widgets of all areas are retuned \return list of widgets */ @@ -1534,7 +1773,7 @@ QWidgetList QtxWorkstack::windowList( QWidget* wid ) const { areas( mySplit, lst, true ); } - else + else { QtxWorkstackArea* area = wgArea( wid ); if ( area ) @@ -1570,6 +1809,16 @@ QWidget* QtxWorkstack::activeWindow() const return myWin; } +/*! + \brief Set active widget + \param wid widget to activate +*/ +void QtxWorkstack::setActiveWindow( QWidget* wid ) +{ + if ( activeArea() ) + activeArea()->setActiveWidget( wid ); +} + /*! \brief Split workstack. @@ -1643,7 +1892,6 @@ void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType QList allAreas; areas(mySplit, allAreas, true); - for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it ) { if ( (*it)->contains( wid ) ) @@ -1653,6 +1901,10 @@ void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType if ( !area ) return; + QWidget* curWid = area->activeWidget(); + if ( !curWid ) + return; + QWidgetList wids = area->widgetList(); if ( wids.count() < 2 ) return; @@ -1686,6 +1938,7 @@ void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType { area->removeWidget( wid_i ); newArea->insertWidget( wid_i ); + wid_i->showMaximized(); } } break; @@ -1699,16 +1952,21 @@ void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType { area->removeWidget( *itr ); newArea->insertWidget( *itr ); + (*itr)->showMaximized(); } } break; case SplitMove: area->removeWidget( wid ); newArea->insertWidget( wid ); + wid->showMaximized(); break; } distributeSpace( trg ); + + curWid->show(); + curWid->setFocus(); } /*! @@ -1748,6 +2006,8 @@ void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) if ( !area1 || !area2 ) return; + QSplitter* s1 = splitter( area1 ); + QWidget* curWid = area1->activeWidget(); if ( !curWid ) return; @@ -1759,6 +2019,8 @@ void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) // Set wid1 at first position, wid2 at second area1->insertWidget( wid1 ); area1->insertWidget( wid2, 1 ); + wid1->showMaximized(); + wid2->showMaximized(); } else { @@ -1768,6 +2030,7 @@ void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) QWidgetList wids1 = area1->widgetList(); for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind ); area1->insertWidget( wid2, wid1_ind + 1 ); + wid2->showMaximized(); } } else @@ -1787,6 +2050,7 @@ void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) area1->insertWidget( *itr2, wid1_ind + 1 ); else area1->insertWidget( *itr2, ind ); + (*itr2)->showMaximized(); } } else @@ -1794,10 +2058,18 @@ void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) // Set wid2 right after wid1 area2->removeWidget( wid2 ); area1->insertWidget( wid2, wid1_ind + 1 ); + wid2->showMaximized(); } } + distributeSpace( s1 ); + area1->setActiveWidget( curWid ); + + wid2->show(); + wid1->setFocus(); + curWid->show(); + curWid->setFocus(); } /*! @@ -1931,7 +2203,7 @@ int QtxWorkstack::accel( const int id ) const { int res = 0; if ( myActionsMap.contains( id ) ) - res = myActionsMap[id]->shortcut(); + res = myActionsMap[id]->shortcut()[0]; return res; } @@ -1966,8 +2238,8 @@ void QtxWorkstack::setIcon( const int id, const QIcon& icon ) /*! \brief Set actions to be visible in the context popup menu. - - Actions, which IDs are set in \a flags parameter, will be shown in the + + Actions, which IDs are set in \a flags parameter, will be shown in the context popup menu. Other actions will not be shown. \param flags ORed together actions flags @@ -1982,8 +2254,8 @@ void QtxWorkstack::setMenuActions( const int flags ) /*! \brief Set actions to be visible in the context popup menu. - - Actions, which IDs are set in \a flags parameter, will be shown in the + + Actions, which IDs are set in \a flags parameter, will be shown in the context popup menu. Other actions will not be shown. \param flags ORed together actions flags @@ -2331,8 +2603,7 @@ QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area ) QIntList szList = pSplit->sizes(); - QSplitter* wrap = new QSplitter( 0 ); - wrap->setChildrenCollapsible( false ); + QSplitter* wrap = new QtxWorkstackSplitter( 0 ); pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap ); wrap->setVisible( true ); wrap->addWidget( area ); @@ -2380,7 +2651,7 @@ void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after ) for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr ) { (*itr)->setParent( pWid ); - (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false ); + (*itr)->setVisible( map.contains( *itr ) ? map[*itr] : false ); } } @@ -2483,10 +2754,12 @@ void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p ) if ( lst.count() > 1 ) { - if ( myActionsMap[SplitVertical]->isEnabled() ) - pm->addAction( myActionsMap[SplitVertical] ); - if ( myActionsMap[SplitHorizontal]->isEnabled() ) - pm->addAction( myActionsMap[SplitHorizontal] ); + if ( !myActionsMap[SplitVertical]->isEnabled() ) + myActionsMap[SplitVertical]->setEnabled(true); + pm->addAction( myActionsMap[SplitVertical] ); + if ( !myActionsMap[SplitHorizontal]->isEnabled() ) + myActionsMap[SplitHorizontal]->setEnabled(true); + pm->addAction( myActionsMap[SplitHorizontal] ); pm->addSeparator(); } @@ -2662,7 +2935,7 @@ QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) ); connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ), - this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) ); + this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) ); connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) ); return area; @@ -2790,346 +3063,216 @@ void QtxWorkstack::updateState( QSplitter* split ) if ( areaList.isEmpty() && splitList.isEmpty() ) delete split; - else if ( vis ) - split->show(); else - split->hide(); + split->setVisible( vis ); } /*! - \brief Get splitter info (for debug purposes) - \param split splitter - \param info string to be filled with splitter data. + \brief Dump workstack configuration to the state description array. + \param version number + \return state byte array. */ -void QtxWorkstack::splitterInfo( QSplitter* split, QString& info ) const +QByteArray QtxWorkstack::saveState( int version ) const { - if ( !split ) - return; - - /*const QObjectList& objs = */split->children(); // VSR: is it needed ??? + QByteArray data; - QString sizesStr; - QList sizes = split->sizes(); - for ( QList::iterator sIt = sizes.begin(); sIt != sizes.end(); ++sIt ) - { - if ( *sIt > 1 ) // size 1 pixel usually means empty Workstack area, which will NOT be re-created, - sizesStr += QString( ":%1" ).arg( *sIt ); // so we don't need to store its size - } + QDataStream stream( &data, QIODevice::WriteOnly ); + stream << QtxWorkstack::VersionMarker; + stream << version; + saveState( stream ); - if ( !sizesStr.isEmpty() ) // cut the first ':' - sizesStr = sizesStr.right( sizesStr.length() - 1 ); - - info += QString( "(splitter orientation=%1 sizes=%3 " ).arg( split->orientation() ).arg( sizesStr ); - - for( int index = 0, count = split->count(); index < count; index++ ) - { - QObject* obj = split->widget( index ); - if ( obj->inherits( "QSplitter" ) ) - splitterInfo( (QSplitter*)obj, info ); - else if ( obj->inherits( "QtxWorkstackArea" ) ) - { - QtxWorkstackArea* area = (QtxWorkstackArea*)obj; - if ( area->isEmpty() ) - continue; - info += QString( "(views active='%1'" ).arg( area->activeWidget()->objectName() ); - QWidgetList views = area->widgetList(); - for ( QWidgetList::iterator wIt = views.begin(); wIt != views.end(); ++wIt ) - info += QString( " '%1'" ).arg( (*wIt)->objectName() ); - info += ')'; - } - } - - info += ')'; - printf( (const char*)QString( info + '\n' ).toLatin1() ); + return data; } /*! - \brief Remove round brackets symbols from the string. - \internal - \param parameters string to be processed + \brief Restore workstack configuration from the state description array. + \param version number + \return restore performing state */ -static void cutBrackets( QString& parameters ) +bool QtxWorkstack::restoreState( const QByteArray& state, int version ) { - QChar c1 = parameters[0]; - QChar c2 = parameters[int(parameters.length()-1)]; - if ( !parameters.isEmpty() && c1 == '(' && c2 == ')' ) - parameters = parameters.mid( 1, parameters.length()-2 ); -} + if ( state.isEmpty() ) + return false; -/*! - \brief Parse string to get some parameter value. - \internal + QByteArray sd = state; + QDataStream stream( &sd, QIODevice::ReadOnly ); + int marker, ver; + stream >> marker; + stream >> ver; + if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version ) + return false; - String \a str can contain the parameters description of kind "= ...". - For example: - \code - QString s = "splitter orientation=0 children=2 sizes=332:478"; - QString orient_val = getValue( s, "children" ); // orient_val contains "2" - QString size_val = getValue( s, "sizes" ); // val contains "332:478" - \endcode + return restoreState( stream ); +} - \param str string to be processed - \param valName parameter name - \return parameter value (or null QStrinhg if parameter is not found) -*/ -static QString getValue( const QString& str, const QString& valName ) +void QtxWorkstack::saveState( QDataStream& stream ) const +{ + mySplit->saveState( stream ); +} + +bool QtxWorkstack::restoreState( QDataStream& stream ) { - int i = str.indexOf( valName ); - if ( i != -1 ) + QMap map; + QList areaList; + areas( mySplit, areaList, true ); + for ( QList::const_iterator it = areaList.begin(); it != areaList.end(); ++it ) { - int equal_i = str.indexOf( '=', i ); - if ( equal_i != -1 ) + QtxWorkstackArea* area = *it; + QList childList = area->childList(); + for ( QList::iterator itr = childList.begin(); itr != childList.end(); ++itr ) { - int space_i = str.indexOf( ' ', ++equal_i ); - if ( space_i != -1 ) - return str.mid( equal_i, space_i - equal_i ); + QtxWorkstackChild* c = *itr; + if ( !c->widget() ) + continue; + + map.insert( c->widget()->objectName(), c ); + + qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() ); } } - return QString(); -} -/*! - \brief Check format of splitter parameters string. - \internal - \param parameters splitter parameters description - \return \c true on success and \c false on error -*/ -static bool checkFormat( const QString& parameters ) -{ - QString params( parameters ); - // 1. begins and ends with brackets - QChar c1 = params[0]; - QChar c2 = params[int(params.length()-1)]; - bool ok = ( c1 == '(' && c2 == ')' ); - if ( !ok ) return ok; - ::cutBrackets( params ); - // 2. has splitter word - ok = ( params.left( 8 ) == "splitter" ); - if ( !ok ) return ok; - // 3. has children? = '(' is found - int i = params.indexOf( '(' ); - ok = i != -1; - if ( !ok ) return ok; - params = params.left( i ); // cut all children, they will be checked later - // 4. has orientation word and correct value - ::getValue( params, "orientation" ).toInt( &ok ); - if ( !ok ) return ok; - // 5. has sizes word and values - ok = ! ::getValue( params, "sizes" ).isEmpty(); - if ( !ok ) return ok; - // 6. check children -> number of '(' == number of ')' in original string - ok = ( parameters.contains( '(' ) == parameters.contains( ')' ) ); - return ok; -} - -/*! - \brief Get splitter's children descriptions from the string. - \internal - - Child widgets descriptions are separated by '(' and ')' symbols. + int marker; + stream >> marker; + if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker ) + return false; - \param str string to be processed - \return child widgets descriptions -*/ -static QStringList getChildren( const QString& str ) -{ - QStringList lst; - if ( !str.startsWith( "(" ) ) - return lst; + QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this ); + if ( layout() ) + layout()->addWidget( split ); - int i = 1, - nOpen = 1, // count brackets: '(' increments nOpen, ')' decrements - start = 0; - while ( i < (int)str.length() ) + bool ok = split->restoreState( stream, map ); + if ( !ok ) + delete split; + else { - if ( str[i] == '(' ) - { - nOpen++; - if ( nOpen == 1 ) - start = i; - } - else if ( str[i] == ')' ) + mySplit->deleteLater(); + mySplit = split; + + QList aList; + areas( mySplit, aList, true ); + + QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0; + for ( QMap::const_iterator it = map.begin(); it != map.end(); ++it ) { - nOpen--; - if ( nOpen == 0 ) - lst.append( str.mid( start, i-start+1 ) ); + QtxWorkstackChild* c = it.value(); + if ( c->widget() ) + c->widget()->setVisible( false ); + if ( a ) + a->insertChild( c ); + else + c->setVisible( false ); } - i++; } - return lst; + return ok; } /*! - \brief Get view name by index. - \internal - - Example: - \code - QString s = "views active='AnotherView' 'GLView' 'AnotherView'"; - QString a0 = getViewName( s, 0 ); // --> a0 contains "GLView" - QString a1 = getViewName( s, 1 ); // --> a1 contains "AnotherView" - \endcode - - \param str string to be processed - \param i index - \return view name + \brief Set resize mode of all splitters opaque or transparent. + \param opaque opaque mode */ -static QString getViewName( const QString& str, int i ) +void QtxWorkstack::setOpaqueResize( bool opaque ) { - QRegExp exp( "\\s'\\w+'" ); - int start = 0; // start index of view name in the string - int num = 0 ; // index of found match - while ( ( start = exp.indexIn( str, start ) ) != -1 && num < i ) - { - start += exp.matchedLength(); - num ++; - } - if ( start != -1 ) // +2 and -3 avoid starting space and starting and ending ' symbols - return str.mid( start + 2, exp.matchedLength() - 3 ); - - return QString(); + QList splitList; + splitters( mySplit, splitList, true ); + splitList << mySplit; + foreach( QSplitter* split, splitList ) + split->setOpaqueResize( opaque ); } /*! - \brief Get child widget with specified name. - \internal - \param parent parent widget - \param aName child widget name - \return child widget or 0 if not found + \brief Get resize mode of all splitters: opaque (\c true) or transparent (\c false). + \return current opaque mode */ -static QWidget* getView( const QWidget* parent, const QString& aName ) +bool QtxWorkstack::opaqueResize() const { - QWidget* view = 0; - QList l = qFindChildren( parent->topLevelWidget(), aName ); - if ( !l.isEmpty() ) - view = ::qobject_cast( l.first() ); - return view; + return mySplit->opaqueResize(); } /*! - \brief Setup splitter according to the specified parameters string. - \param splitter splitter to be set up - \param parameters splitter parameters description - \param sMap map containing resulting child splitters sizes + \brief Show/hide splitter state and area. + \param wid widget (and parent area) will be shown/hidden + \param parent_list parent splitters list + \param split splitter will be shown/hidden + \param visible splitter */ -void QtxWorkstack::setSplitter( QSplitter* splitter, const QString& parameters, QMap >& sMap ) +void QtxWorkstack::splitterVisible(QWidget* wid, QList& parent_list, QSplitter* split, bool visible) { - printf( QString( parameters + '\n' ).toLatin1() ); - if ( !::checkFormat( parameters ) ) { - printf( "\nInvalid format of workstack parameters. Positions of viewers can not be restored.\n" ); - return; + QList recList; + splitters( split, recList, false ); + for ( QList::iterator itr = recList.begin(); itr != recList.end(); ++itr ) { + parent_list.prepend( *itr ); + splitterVisible( wid, parent_list, *itr, visible ); } - QString params( parameters ); - ::cutBrackets( params ); - - // get splitter sizes and store it in the map for future setting - QList sizes; - QStringList sizesLst = ::getValue( params, "sizes" ).split( ':', QString::SkipEmptyParts ); - QStringList::Iterator it; - for ( it = sizesLst.begin(); it != sizesLst.end(); ++it ) - sizes.append( (*it).toInt() ); - sMap[ splitter ] = sizes; - - // set orientation of splitter - int orient = ::getValue( params, "orientation" ).toInt(); - splitter->setOrientation( (Qt::Orientation)orient ); - - // get children - QString options = params.left( params.indexOf( '(' ) ); - QString childrenStr = params.right( params.length()-options.length() ); - QStringList children = ::getChildren( childrenStr ); - - // debug output.. - // printf (" splitter orient=%d, sizes_count=%d, children=%d\n", orient, sizes.count(), children.count() ); - // for ( QStringList::Iterator tit = children.begin(); tit != children.end(); ++tit ) - // printf (" |-> child = [%s]\n", (*tit).latin1() ); - - for ( it = children.begin(); it != children.end(); ++it ) - { - if ( (*it).startsWith( "(splitter" ) ) - { - QSplitter* newSplitter = new QSplitter( splitter ); - setSplitter( newSplitter, *it, sMap ); - } - else if ( (*it).startsWith( "(views" ) ) - { - QtxWorkstackArea* newArea = createArea( splitter ); - QString activeViewName = ::getValue( *it, "active" ); - QWidget* activeView = 0; - activeViewName = activeViewName.mid( 1, activeViewName.length()-2 ); // chop off ' symbols - int i = 0; - QString viewName = ::getViewName( *it, i ); - while ( !viewName.isEmpty() ) - { - if ( QWidget* view = ::getView( splitter, viewName ) ) - { - newArea->insertWidget( view ); - if ( activeViewName == view->objectName() ) - activeView = view; - } - viewName = ::getViewName( *it, ++i ); + QList areaList; + areas( split, areaList, false ); + for ( QList::const_iterator it = areaList.begin(); it != areaList.end(); ++it ) { + QtxWorkstackArea* area = *it; + bool isCurrentWidget = false; + + area->showTabBar(visible); + + // 1. Looking for the selected widget at the lowest level among all splitted areas. + QList childList = area->childList(); + for ( QList::iterator itr = childList.begin(); itr != childList.end(); ++itr ) { + QWidget* aCurWid = (*itr)->widget(); + if ( aCurWid == wid ) { + isCurrentWidget = true; + aCurWid->setVisible( true ); } - if ( activeView ) - newArea->setActiveWidget( activeView ); + else + aCurWid->setVisible( visible ); } - } -} -/*! - \brief Restore workstack configuration from the state description string. - \param parameters workstack state description - \return reference to this workstack -*/ -QtxWorkstack& QtxWorkstack::operator<<( const QString& parameters ) -{ - // clear the main splitter - remove all child splitters and empty areas from it - QList splitList; - QList areaList; - splitters( mySplit, splitList, false ); - areas( mySplit, areaList, false ); - for ( QList::iterator iter = splitList.begin(); iter != splitList.end(); ++iter ) - delete *iter; + // 2. Show/Hide other areas and widgets that don't contain the desired widget + if ( !isCurrentWidget || visible ) + area->setVisible( visible ); - for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) - { - if ( (*it)->isEmpty() ) - delete *it; - } + if ( !isCurrentWidget && !visible ) + continue; - // restore splitter recursively - QMap< QSplitter*, QList > sMap; - setSplitter( mySplit, parameters, sMap ); + // 3. Show/hide all parent widgets + QSplitter* pSplit = splitter( area ); + int count = pSplit->count(); + for ( int i = 0; i < count; i++ ) { + if ( pSplit->indexOf( area ) == i && !visible ) + continue; + pSplit->widget(i)->setVisible( visible ); + } - // now mySplit may contains empty area (where all views were located before restoring) - // in order setSize to work correctly we have to exclude this area - areaList.clear(); - areas( mySplit, areaList, false ); - for ( QList::iterator delIt = areaList.begin(); delIt != areaList.end(); ++delIt ) - { - if ( (*delIt)->isEmpty() ) - delete *delIt; + // 4. Show/hide all parent splitters don't contain the selected widget + if ( visible ) + pSplit->setVisible( true ); + + if ( isCurrentWidget && !visible ) { + for ( QList::iterator itr = parent_list.begin(); itr != parent_list.end() && pSplit != mySplit; ++itr ) { + if ( pSplit == *itr ) + continue; + QList splitList; + splitters( *itr, splitList, false ); + for ( QList::iterator iter = splitList.begin(); iter != splitList.end(); ++iter ) { + if ( pSplit == (*iter) ) { + pSplit = *itr; + continue; + } + (*iter)->setVisible( false ); + } + } + } } - - QApplication::instance()->processEvents(); - - // restore splitters' sizes (map of sizes is filled in setSplitters) - for ( QMap< QSplitter*, QList >::iterator itm = sMap.begin(); itm != sMap.end(); ++itm ) - itm.key()->setSizes( itm.value() ); - - return (*this); } /*! - \brief Dump workstack configuration to the state description string. - \param parameters resulting workstack state description - \return reference to this workstack + \brief Show/hide splitters state and area. + \param wid widget (and parent area) will be shown/hidden + \param visible splitters */ -QtxWorkstack& QtxWorkstack::operator>>( QString& outParameters ) +void QtxWorkstack::splittersVisible( QWidget* wid, bool visible ) { - splitterInfo( mySplit, outParameters ); - return (*this); + QList parent_list; + parent_list.append( mySplit ); + splitterVisible( wid, parent_list, mySplit, visible ); } /*! @@ -3164,9 +3307,9 @@ QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const \brief Moves the first widget to the same area which the second widget belongs to \param wid widget to be moved \param wid_to widget specified the destination area - \param before specifies whether the first widget has to be moved before or after + \param before specifies whether the first widget has to be moved before or after the second widget - \return TRUE if operation is completed successfully, FALSE otherwise + \return \c true if operation is completed successfully, \c false otherwise */ bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before ) { @@ -3192,6 +3335,7 @@ bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before ) idx++; area_src->removeWidget( wid, true ); area_to->insertWidget( wid, idx ); + wid->showMaximized(); return true; } } @@ -3201,7 +3345,7 @@ bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before ) /*! \brief Group all windows in one area - \return TRUE if operation is completed successfully, FALSE otherwise + \return \c true if operation is completed successfully, \c false otherwise */ void QtxWorkstack::stack() { @@ -3219,13 +3363,19 @@ void QtxWorkstack::stack() area_to = wgArea( *it ); area_src = area_to; } - else + else area_src = wgArea( *it ); if ( area_src != area_to ) { area_src->removeWidget( *it, true ); area_to->insertWidget( *it, -1 ); + (*it)->showMaximized(); } } } + +QAction* QtxWorkstack::action( const int id ) const +{ + return myActionsMap.contains( id ) ? myActionsMap[id] : 0; +}