From ca1b98328144ee242e93cade63cabe3f1980111f Mon Sep 17 00:00:00 2001 From: stv Date: Wed, 18 Feb 2009 09:59:52 +0000 Subject: [PATCH] Improve save/restore GUI state functionality. --- src/Qtx/QtxWorkstack.cxx | 1020 +++++++++++------------ src/Qtx/QtxWorkstack.h | 139 +-- src/STD/STD_TabDesktop.cxx | 4 +- src/SalomeApp/SalomeApp_VisualState.cxx | 152 ++-- 4 files changed, 668 insertions(+), 647 deletions(-) diff --git a/src/Qtx/QtxWorkstack.cxx b/src/Qtx/QtxWorkstack.cxx index f67e0cdb2..eca4c7852 100644 --- a/src/Qtx/QtxWorkstack.cxx +++ b/src/Qtx/QtxWorkstack.cxx @@ -31,7 +31,8 @@ #include #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 ) {}; - QWidget* widget() const { return myWidget; } + QtxWorkstackChild* child() const { return myChild; } private: - QWidget* myWidget; // event receiver widget + 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 ) {}; + + int id() const { return myId; } + int flags() const { return myFlags; } + +private: + 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(); } /*! @@ -357,6 +378,137 @@ void CloseButton::paintEvent( QPaintEvent* ) 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 @@ -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 ) ) ); + if ( myBar->indexOf( child->id() ) != -1 ) + myBar->removeTab( myBar->indexOf( child->id() ) ); - myStack->removeWidget( child( wid ) ); + myStack->removeWidget( child ); - 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,82 @@ 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 Get rectangle to be drawn when highlighting drop area. \return area drop rectangle @@ -727,17 +965,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 +1058,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 +1067,7 @@ void QtxWorkstackArea::onChildDestroyed( QObject* obj ) */ void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) { - setWidgetShown( c->widget(), true ); + updateState(); } /*! @@ -837,7 +1076,7 @@ void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) */ void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c ) { - setWidgetShown( c->widget(), false ); + updateState(); } /*! @@ -865,19 +1104,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() ) ) ); 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 +1130,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 +1142,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 +1160,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 +1176,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 +1196,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 +1203,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 +1267,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 +1277,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 +1285,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 +1337,21 @@ 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 ); + 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* ) ) ); + } } /*! @@ -1193,6 +1381,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. @@ -1469,11 +1694,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 +1733,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 +1745,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 +1758,7 @@ QWidgetList QtxWorkstack::windowList( QWidget* wid ) const { areas( mySplit, lst, true ); } - else + else { QtxWorkstackArea* area = wgArea( wid ); if ( area ) @@ -1966,8 +2190,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 +2206,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 +2555,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 ); @@ -2790,346 +3013,108 @@ 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 ??? - - 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 - } + QByteArray data; - if ( !sizesStr.isEmpty() ) // cut the first ':' - sizesStr = sizesStr.right( sizesStr.length() - 1 ); + QDataStream stream( &data, QIODevice::WriteOnly ); + stream << QtxWorkstack::VersionMarker; + stream << version; + saveState( stream ); - 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 ); -} - -/*! - \brief Parse string to get some parameter value. - \internal + if ( state.isEmpty() ) + 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 + 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; - \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 ) -{ - int i = str.indexOf( valName ); - if ( i != -1 ) - { - int equal_i = str.indexOf( '=', i ); - if ( equal_i != -1 ) - { - int space_i = str.indexOf( ' ', ++equal_i ); - if ( space_i != -1 ) - return str.mid( equal_i, space_i - equal_i ); - } - } - return QString(); + return restoreState( stream ); } -/*! - \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. - - \param str string to be processed - \return child widgets descriptions -*/ -static QStringList getChildren( const QString& str ) +void QtxWorkstack::saveState( QDataStream& stream ) const { - QStringList lst; - if ( !str.startsWith( "(" ) ) - return lst; - - int i = 1, - nOpen = 1, // count brackets: '(' increments nOpen, ')' decrements - start = 0; - while ( i < (int)str.length() ) - { - if ( str[i] == '(' ) - { - nOpen++; - if ( nOpen == 1 ) - start = i; - } - else if ( str[i] == ')' ) - { - nOpen--; - if ( nOpen == 0 ) - lst.append( str.mid( start, i-start+1 ) ); - } - i++; - } - - return lst; + mySplit->saveState( stream ); } -/*! - \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 -*/ -static QString getViewName( const QString& str, int i ) +bool QtxWorkstack::restoreState( QDataStream& stream ) { - 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 ) + QMap map; + QList areaList; + areas( mySplit, areaList, true ); + for ( QList::const_iterator it = areaList.begin(); it != areaList.end(); ++it ) { - 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 ); + QtxWorkstackArea* area = *it; + QList childList = area->childList(); + for ( QList::iterator itr = childList.begin(); itr != childList.end(); ++itr ) + { + QtxWorkstackChild* c = *itr; + if ( !c->widget() ) + continue; - return QString(); -} + map.insert( c->widget()->objectName(), c ); -/*! - \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 -*/ -static QWidget* getView( const QWidget* parent, const QString& aName ) -{ - QWidget* view = 0; - QList l = qFindChildren( parent->topLevelWidget(), aName ); - if ( !l.isEmpty() ) - view = ::qobject_cast( l.first() ); - return view; -} - -/*! - \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 -*/ -void QtxWorkstack::setSplitter( QSplitter* splitter, const QString& parameters, QMap >& sMap ) -{ - printf( QString( parameters + '\n' ).toLatin1() ); - if ( !::checkFormat( parameters ) ) { - printf( "\nInvalid format of workstack parameters. Positions of viewers can not be restored.\n" ); - return; + qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() ); + } } - 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; + int marker; + stream >> marker; + if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker ) + return false; - // set orientation of splitter - int orient = ::getValue( params, "orientation" ).toInt(); - splitter->setOrientation( (Qt::Orientation)orient ); + QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this ); + if ( layout() ) + layout()->addWidget( split ); - // get children - QString options = params.left( params.indexOf( '(' ) ); - QString childrenStr = params.right( params.length()-options.length() ); - QStringList children = ::getChildren( childrenStr ); + bool ok = split->restoreState( stream, map ); + if ( !ok ) + delete split; + else + { + mySplit->deleteLater(); + mySplit = split; - // 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() ); + QList aList; + areas( mySplit, aList, true ); - 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* a = !aList.isEmpty() ? aList.first() : 0; + for ( QMap::const_iterator it = map.begin(); it != map.end(); ++it ) { - 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 ); - } - if ( activeView ) - newArea->setActiveWidget( activeView ); + QtxWorkstackChild* c = it.value(); + if ( c->widget() ) + c->widget()->setVisible( false ); + if ( a ) + a->insertChild( c ); + else + c->setVisible( false ); } } -} - -/*! - \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; - - for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) - { - if ( (*it)->isEmpty() ) - delete *it; - } - - // restore splitter recursively - QMap< QSplitter*, QList > sMap; - setSplitter( mySplit, parameters, sMap ); - - // 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; - } - - 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 -*/ -QtxWorkstack& QtxWorkstack::operator>>( QString& outParameters ) -{ - splitterInfo( mySplit, outParameters ); - return (*this); + return ok; } /*! @@ -3164,9 +3149,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 TRUE if operation is completed successfully, FALSE otherwise */ bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before ) { @@ -3201,7 +3186,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 TRUE if operation is completed successfully, FALSE otherwise */ void QtxWorkstack::stack() { @@ -3219,7 +3204,7 @@ void QtxWorkstack::stack() area_to = wgArea( *it ); area_src = area_to; } - else + else area_src = wgArea( *it ); if ( area_src != area_to ) @@ -3229,3 +3214,8 @@ void QtxWorkstack::stack() } } } + +QAction* QtxWorkstack::action( const int id ) const +{ + return myActionsMap.contains( id ) ? myActionsMap[id] : 0; +} diff --git a/src/Qtx/QtxWorkstack.h b/src/Qtx/QtxWorkstack.h index 9d0a16bd5..c8abd3e7e 100644 --- a/src/Qtx/QtxWorkstack.h +++ b/src/Qtx/QtxWorkstack.h @@ -27,22 +27,26 @@ #include "Qtx.h" -#include +#include #include -#include #include -#include +#include +#include +#include +#include class QAction; -class QSplitter; -class QStackedWidget; +class QByteArray; +class QDataStream; class QRubberBand; +class QStackedWidget; class QAbstractButton; class QtxWorkstackArea; class QtxWorkstackDrag; class QtxWorkstackChild; class QtxWorkstackTabBar; +class QtxWorkstackSplitter; #ifdef WIN32 #pragma warning( disable:4251 ) @@ -58,10 +62,20 @@ public: SplitHorizontal = 0x02, //!< "Split horizontally" menu item Close = 0x04, //!< "Close" menu item Rename = 0x08, //!< "Rename" menu item - All = SplitVertical | SplitHorizontal | + All = SplitVertical | SplitHorizontal | Close | Rename //!< all menu items }; - + + enum { VersionMarker = 0x01, + SplitMarker = 0x02, + AreaMarker = 0x04, + WidgetMarker = 0x08 + }; + + enum { Horizontal = 0x01, + Visible = 0x02 + }; + //! Workstack splitting type enum SplitType { @@ -88,28 +102,27 @@ public: void setMenuActions( const int ); int menuActions() const; + void stack(); void split( const int ); bool move( QWidget* wid, QWidget* wid_to, const bool before ); - void stack(); QWidget* addWindow( QWidget*, Qt::WindowFlags = 0 ); + QByteArray saveState( int ) const; + bool restoreState( const QByteArray&, int ); + void Split( QWidget* wid, const Qt::Orientation o, const SplitType type ); void Attract( QWidget* wid1, QWidget* wid2, const bool all ); void SetRelativePosition( QWidget* wid, const Qt::Orientation o, const double pos ); void SetRelativePositionInSplitter( QWidget* wid, const double pos ); - // asv: Store/Restore visual parameters - geometry of inner windows - QtxWorkstack& operator<<( const QString& ); - QtxWorkstack& operator>>( QString& ); - signals: void windowActivated( QWidget* ); public slots: void splitVertical(); void splitHorizontal(); - + private slots: void onRename(); void onCloseWindow(); @@ -121,6 +134,11 @@ private slots: protected: virtual void customEvent( QEvent* ); + QAction* action( const int ) const; + + void saveState( QDataStream& ) const; + bool restoreState( QDataStream& ); + private: QSplitter* splitter( QtxWorkstackArea* ) const; void splitters( QSplitter*, QList&, const bool = false ) const; @@ -145,23 +163,37 @@ private: void updateState( QSplitter* ); void distributeSpace( QSplitter* ) const; + int setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o, const int need_pos, const int splitter_pos ); - - void splitterInfo( QSplitter*, QString& ) const; - void setSplitter( QSplitter*, const QString&, QMap< QSplitter*, QList >& ); - + private: - QWidget* myWin; //!< active widget - QtxWorkstackArea* myArea; //!< active workarea - QSplitter* mySplit; //!< tol-level splitter - QWidget* myWorkWin; //!< widget where popup menu is invoked (used internally) - QtxWorkstackArea* myWorkArea; //!< workarea where popup menu is invoked (used internally) + QWidget* myWin; //!< active widget + QtxWorkstackArea* myArea; //!< active workarea + QtxWorkstackSplitter* mySplit; //!< tol-level splitter + QWidget* myWorkWin; //!< widget where popup menu is invoked (used internally) + QtxWorkstackArea* myWorkArea; //!< workarea where popup menu is invoked (used internally) QMap myActionsMap; //!< actions map friend class QtxWorkstackArea; friend class QtxWorkstackDrag; + friend class QtxWorkstackAction; + friend class QtxWorkstackSplitter; +}; + +class QtxWorkstackSplitter : public QSplitter +{ + Q_OBJECT + +public: + QtxWorkstackSplitter( QWidget* = 0 ); + virtual ~QtxWorkstackSplitter(); + + QtxWorkstack* workstack() const; + + void saveState( QDataStream& ) const; + bool restoreState( QDataStream&, QMap& ); }; class QtxWorkstackArea : public QFrame @@ -169,6 +201,7 @@ class QtxWorkstackArea : public QFrame Q_OBJECT class WidgetEvent; + class RestoreEvent; public: QtxWorkstackArea( QWidget* ); @@ -177,15 +210,19 @@ public: bool isNull() const; bool isEmpty() const; - QWidget* insertWidget( QWidget*, const int = -1, Qt::WindowFlags = 0 ); + QtxWorkstackChild* insertWidget( QWidget*, const int = -1, Qt::WindowFlags = 0 ); void removeWidget( QWidget*, const bool = true ); + void insertChild( QtxWorkstackChild*, const int = -1 ); + void removeChild( QtxWorkstackChild*, const bool = true ); + QWidget* activeWidget() const; void setActiveWidget( QWidget* ); bool contains( QWidget* ) const; QWidgetList widgetList() const; + QList childList() const; bool isActive() const; void updateActiveState(); @@ -199,20 +236,18 @@ public: int tabAt( const QPoint& ) const; + void saveState( QDataStream& ) const; + bool restoreState( QDataStream&, QMap& ); + signals: void activated( QWidget* ); void contextMenuRequested( QWidget*, QPoint ); void deactivated( QtxWorkstackArea* ); -public slots: - virtual void setVisible( bool ); - private slots: void onClose(); void onCurrentChanged( int ); - void onWidgetDestroyed(); - void onChildDestroyed( QObject* ); void onChildShown( QtxWorkstackChild* ); void onChildHidden( QtxWorkstackChild* ); @@ -230,8 +265,9 @@ protected: private: //! Custom events enum { ActivateWidget = QEvent::User, //!< activate widget event - FocusWidget, //!< focus receiving widget event - RemoveWidget //!< widget removing event + FocusWidget, //!< focus receiving widget event + MakeCurrent, + RestoreWidget }; private: @@ -241,38 +277,22 @@ private: QWidget* widget( const int ) const; int widgetId( QWidget* ) const; - bool widgetVisibility( QWidget* ) const; + + QtxWorkstackChild* child( QWidget* ) const; + QtxWorkstackChild* child( const int ) const; void setWidgetActive( QWidget* ); - void setWidgetShown( QWidget*, const bool ); int generateId() const; - bool isBlocked( QWidget* ) const; - void setBlocked( QWidget*, const bool ); - - QtxWorkstackChild* child( QWidget* ) const; - private: - struct WidgetInfo - { - WidgetInfo() : id( 0 ), vis( false ) {} - int id; bool vis; - }; - - typedef QMap BlockMap; - typedef QMap ChildMap; - typedef QMap WidgetInfoMap; + typedef QList ChildList; private: QtxWorkstackTabBar* myBar; //!< workarea tab bar header + ChildList myList; //!< child widgets list QAbstractButton* myClose; //!< close button QStackedWidget* myStack; //!< widget stack - - QWidgetList myList; //!< child widgets list - WidgetInfoMap myInfo; //!< widgets states mp - ChildMap myChild; //!< child widget containers map - BlockMap myBlock; //!< blocked widgets }; class QtxWorkstackChild : public QWidget @@ -283,7 +303,15 @@ public: QtxWorkstackChild( QWidget*, QWidget* = 0, Qt::WindowFlags = 0 ); virtual ~QtxWorkstackChild(); - QWidget* widget() const; + QWidget* widget() const +; + + int id() const; + void setId( const int ); + + bool visibility(); + + QtxWorkstackArea* area() const; virtual bool eventFilter( QObject*, QEvent* ); @@ -300,7 +328,8 @@ protected: virtual void childEvent( QChildEvent* ); private: - QWidget* myWidget; //!< child widget + int myId; //!< id + QPointer myWidget; //!< child widget }; class QtxWorkstackTabBar : public QTabBar @@ -328,13 +357,11 @@ private slots: void onCurrentChanged( int ); protected: + virtual void changeEvent( QEvent* ); virtual void mouseMoveEvent( QMouseEvent* ); virtual void mousePressEvent( QMouseEvent* ); virtual void mouseReleaseEvent( QMouseEvent* ); virtual void contextMenuEvent( QContextMenuEvent* ); - virtual void changeEvent( QEvent* ); - -// virtual void paintLabel( QPainter*, const QRect&, QTab*, bool ) const; private: int myId; //!< current tab page index diff --git a/src/STD/STD_TabDesktop.cxx b/src/STD/STD_TabDesktop.cxx index f63f36e7e..4bbd251a6 100644 --- a/src/STD/STD_TabDesktop.cxx +++ b/src/STD/STD_TabDesktop.cxx @@ -51,7 +51,7 @@ myWorkstackAction( 0 ) myWorkstack = new QtxWorkstack( base ); main->addWidget( myWorkstack ); // setting Expanding size policy for central workstack. If there are several widgets - // in central area of Desktop, other widgets will be added below the workstack (CATHARE, TRIPOLI modules). + // in central area of Desktop, other widgets will be added below the workstack (CATHARE, TRIPOLI modules). // But the workstack must occupy as much space as possible -- set Expanding for it. myWorkstack->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); @@ -61,7 +61,7 @@ myWorkstackAction( 0 ) SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); if ( resMgr ) { - myWorkstack->setIcon( QtxWorkstack::SplitVertical, + myWorkstack->setIcon( QtxWorkstack::SplitVertical, resMgr->loadPixmap( "STD", tr( "ICON_DESK_WINDOW_VSPLIT" ) ) ); myWorkstack->setIcon( QtxWorkstack::SplitHorizontal, resMgr->loadPixmap( "STD", tr( "ICON_DESK_WINDOW_HSPLIT" ) ) ); diff --git a/src/SalomeApp/SalomeApp_VisualState.cxx b/src/SalomeApp/SalomeApp_VisualState.cxx index 0244b0ac4..8abfcaa27 100644 --- a/src/SalomeApp/SalomeApp_VisualState.cxx +++ b/src/SalomeApp/SalomeApp_VisualState.cxx @@ -49,7 +49,7 @@ SalomeApp_VisualState::SalomeApp_VisualState( SalomeApp_Application* app ) : QObject(), myApp( app ) { -} +} /*! Destructor. @@ -62,7 +62,7 @@ SalomeApp_VisualState::~SalomeApp_VisualState() Sets names of all view windows in given list. This is used in order to apply the same naming algorithm when saving and restoring view windows. Names of view windows must be the same before saving - workstack (splitters) information, and before its restoring! + workstack (splitters) information, and before its restoring! Naming rule: ViewerType_IndexOfViewerOfThisType_IndexOfViewInThisViewer VTKViewer_0_0 OCCViewer_0_0 OCCViewer_0_1 OCCViewer_0_2 @@ -70,33 +70,31 @@ SalomeApp_VisualState::~SalomeApp_VisualState() */ void nameViewWindows( const ViewManagerList& lst ) { - QMultiHash viewersCounter; // map viewerType - to - index_of_this_viewer_type - QListIterator it(lst); - SUIT_ViewManager* aVM = 0; - while ( it.hasNext() ) { - aVM = it.next(); - if ( !aVM ) continue; + QMap viewersCounter; + for ( QList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + { + SUIT_ViewManager* aVM = *it; + if ( !aVM ) + continue; int view_count = aVM->getViewsCount(); QString vType = aVM->getType(); if ( !view_count ) continue; //No views is opened in the viewer - - int viewerID = viewersCounter.value( vType ); - if ( !viewerID ) { - viewerID = 0; - viewersCounter.insert( vType, viewerID ); - } - else - ++viewerID; + + if ( !viewersCounter.contains( vType ) ) + viewersCounter.insert( vType, 0 ); + + int& viewerID = viewersCounter[vType]; QVector views = aVM->getViews(); - for ( int i = 0; i < view_count; i++ ) { + for ( int i = 0; i < view_count; i++ ) + { QString vName = QString( "%1_%2_%3" ).arg( vType ).arg( viewerID ).arg( i ); views[i]->setObjectName( vName ); } + viewerID++; } - viewersCounter.clear(); } /*! @@ -111,7 +109,7 @@ int SalomeApp_VisualState::storeState() int savePoint = 1; std::vector savePoints = study->getSavePoints(); //Calculate a new savePoint number = the last save point number + 1 - if ( savePoints.size() > 0) + if ( savePoints.size() > 0) savePoint = savePoints[savePoints.size()-1] + 1; _PTR(AttributeParameter) ap = study->studyDS()->GetCommonParameters( study->getVisualComponentName(), savePoint ); @@ -120,13 +118,13 @@ int SalomeApp_VisualState::storeState() ViewManagerList lst; myApp->viewManagers( lst ); - // setting unique names for view windows in order to save this view inside + // setting unique names for view windows in order to save this view inside // workstack's structure (see below). On restore the views with the same names will // be placed to the same place inside the workstack's splitters. nameViewWindows( lst ); // store active window's name - SUIT_ViewWindow* win = myApp->desktop()->activeWindow(); + SUIT_ViewWindow* win = myApp->desktop()->activeWindow(); if ( win ) ip->setProperty("AP_ACTIVE_VIEW", win->objectName().toStdString() ); @@ -138,12 +136,12 @@ int SalomeApp_VisualState::storeState() if ( !vm ) continue; int view_count = vm->getViewsCount(); - if ( !view_count ) + if ( !view_count ) continue; //No views is opened in the viewer - + std::string viewerEntry = QString( "%1_%2" ).arg( vm->getType() ).arg( ++viewerID ).toStdString(); ip->append("AP_VIEWERS_LIST", viewerEntry); - + QVector views = vm->getViews(); for(int i = 0; iappend( viewerEntry, views[i]->windowTitle().toStdString() ); @@ -152,19 +150,20 @@ int SalomeApp_VisualState::storeState() } //Save information about split areas - if ( myApp->desktop()->inherits( "STD_TabDesktop" ) ) { - QtxWorkstack* workstack = ((STD_TabDesktop*)myApp->desktop())->workstack(); + if ( myApp->desktop()->inherits( "STD_TabDesktop" ) ) + { QString workstackInfo; - (*workstack) >> workstackInfo; - ip->setProperty( "AP_WORKSTACK_INFO", workstackInfo.toStdString() ); + QtxWorkstack* workstack = ((STD_TabDesktop*)myApp->desktop())->workstack(); + QByteArray geomState = workstack->saveState( 0 ); + ip->setProperty( "AP_WORKSTACK_INFO", QString( geomState.toHex() ).toStdString() ); } - + //Save a name of the active module - if ( CAM_Module* activeModule = myApp->activeModule() ) + if ( CAM_Module* activeModule = myApp->activeModule() ) ip->setProperty( "AP_ACTIVE_MODULE", activeModule->moduleName().toStdString() ); //Store visual parameters of the modules - QList mlist; + QList mlist; myApp->modules( mlist ); QListIterator itM( mlist ); CAM_Module* module = 0; @@ -180,7 +179,7 @@ int SalomeApp_VisualState::storeState() // set default name of new savePoint study->setNameOfSavePoint( savePoint, QObject::tr( "SAVE_POINT_DEF_NAME" ) + QString::number( savePoint ) ); - + return savePoint; } @@ -199,65 +198,65 @@ void SalomeApp_VisualState::restoreState(int savePoint) qApp->installEventFilter( this ); //Remove all already existent veiwers and their views - ViewManagerList lst; - myApp->viewManagers( lst ); - QListIterator it(lst); - while ( it.hasNext() ) { - myApp->removeViewManager( it.next() ); - qApp->processEvents(); - } + myApp->clearViewManagers(); + //Restore the viewers and view windows int nbViewers = ip->nbValues( "AP_VIEWERS_LIST" ); SUIT_ViewWindow* viewWin = 0; // parameters of view windows are stored in a map for restoring after restoring of the workstack QMap viewersParameters; - - for ( int i = 0; i < nbViewers; i++ ) { + + for ( int i = 0; i < nbViewers; i++ ) + { std::string viewerEntry = ip->getValue( "AP_VIEWERS_LIST", i ); std::vector veiewerParams = ip->parseValue(viewerEntry,'_'); std::string type = veiewerParams[0]; std::string viewerID = veiewerParams[1]; SUIT_ViewManager* vm = myApp->newViewManager( type.c_str() ); - if ( !vm ) + if ( !vm ) continue; //Unknown viewer - + int nbViews = (ip->nbValues(viewerEntry))/2; - + //Create nbViews-1 view (-1 because 1 view is created by createViewManager) - for ( int i = 1; i< nbViews; i++ ) { + for ( int i = 1; i< nbViews; i++ ) + { SUIT_ViewWindow* aView = vm->createViewWindow(); aView->show(); } int viewCount = vm->getViewsCount(); - if (viewCount != nbViews) { + if ( viewCount != nbViews ) + { printf( "\nRestore visual state: Unknow error, Can't create a view!\n" ); continue; } //Resize the views, set their captions and apply visual parameters. - QVector views = vm->getViews(); - for (int i = 0, j = 0; i views = vm->getViews(); + for ( int i = 0, j = 0; iisVisible() ) - qApp->processEvents(); - - viewWin->setWindowTitle(ip->getValue(viewerEntry, j).c_str()); - + // while ( !vm->isVisible() ) + // qApp->processEvents(); + + viewWin->setWindowTitle( ip->getValue( viewerEntry, j ).c_str() ); + // printf ( "VP for viewWin \"%s\": %s\n", viewerEntry.c_str(), ip->getValue(viewerEntry, j+1).c_str() ); - viewersParameters[ viewWin ] = ip->getValue(viewerEntry, j+1).c_str(); + viewersParameters[ viewWin ] = ip->getValue( viewerEntry, j + 1 ).c_str(); //viewWin->setVisualParameters(ip->getValue(viewerEntry, j+1).c_str()); } } // restore modules' visual parameters - std::vector v = ip->getValues("AP_MODULES_LIST"); - for ( int i = 0; i < v.size(); i++ ) { + std::vector v = ip->getValues( "AP_MODULES_LIST" ); + for ( int i = 0; i < v.size(); i++ ) + { myApp->activateModule( v[i].c_str() ); if ( SalomeApp_Module* module = dynamic_cast( myApp->activeModule() ) ) module->restoreVisualParameters( savePoint ); @@ -265,39 +264,44 @@ void SalomeApp_VisualState::restoreState(int savePoint) // new view windows may have been created in module->restoreVisualParameters() [GAUSS] // so here we store their visual parameters for later restoring.. - lst.clear(); - myApp->viewManagers(lst); - QListIterator itVM( lst ); - SUIT_ViewManager* aVM = 0; - while ( itVM.hasNext() ) { - aVM = itVM.next(); - if ( !aVM ) continue; + QList lst; + myApp->viewManagers( lst ); + for ( QList::iterator itVM = lst.begin(); itVM != lst.end(); ++itVM ) + { + SUIT_ViewManager* aVM = *itVM; + if ( !aVM ) + continue; int view_count = aVM->getViewsCount(); QVector views = aVM->getViews(); - for ( int i = 0; i < view_count; i++ ) { - if ( !viewersParameters.contains( views[i] ) ) { + for ( int i = 0; i < view_count; i++ ) + { + if ( !viewersParameters.contains( views[i] ) ) + { viewersParameters[ views[i] ] = views[i]->getVisualParameters(); // printf ( "store VP for viewWin \"%s\": %s\n", views[i]->name(), views[i]->getVisualParameters().toLatin1().constData() ); } } - } + } // activate module that was active on save QString activeModuleName( ip->getProperty("AP_ACTIVE_MODULE" ).c_str() ); - if ( !activeModuleName.isEmpty() ) + if ( !activeModuleName.isEmpty() ) myApp->activateModule( activeModuleName ); - // setting unique names for view windows in order to restore positions of view windows inside - // workstack's structure (see below). During save the same naming algorithm was used, + // setting unique names for view windows in order to restore positions of view windows inside + // workstack's structure (see below). During save the same naming algorithm was used, // so the same views will get the same names. nameViewWindows( lst ); + qApp->processEvents(); + // restore workstack parameters. should be done after module's restoreVisualParameters(), because // some modules can create their own viewers (like VISU creates GaussViewers) - if ( myApp->desktop()->inherits( "STD_TabDesktop" ) ) { + if ( myApp->desktop()->inherits( "STD_TabDesktop" ) ) + { QtxWorkstack* workstack = ((STD_TabDesktop*)myApp->desktop())->workstack(); - (*workstack) << ip->getProperty( "AP_WORKSTACK_INFO" ).c_str(); + workstack->restoreState( QByteArray::fromHex( QByteArray( ip->getProperty( "AP_WORKSTACK_INFO" ).c_str() ) ), 0 ); } // restore visual parameters of view windows. it must be done AFTER restoring workstack. @@ -311,7 +315,7 @@ void SalomeApp_VisualState::restoreState(int savePoint) } qApp->removeEventFilter( this ); - + // for ( it.toFirst(); it.current(); ++it ) { // int view_count = it.current()->getViewsCount(); // QPtrVector views = it.current()->getViews(); @@ -345,6 +349,6 @@ bool SalomeApp_VisualState::eventFilter( QObject* o, QEvent* e ) aType == QEvent::KeyPress || aType == QEvent::KeyRelease ) return true; - + return QObject::eventFilter( o, e ); } -- 2.39.2