]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Improve save/restore GUI state functionality.
authorstv <stv@opencascade.com>
Wed, 18 Feb 2009 09:59:52 +0000 (09:59 +0000)
committerstv <stv@opencascade.com>
Wed, 18 Feb 2009 09:59:52 +0000 (09:59 +0000)
src/Qtx/QtxWorkstack.cxx
src/Qtx/QtxWorkstack.h
src/STD/STD_TabDesktop.cxx
src/SalomeApp/SalomeApp_VisualState.cxx

index f67e0cdb291380f5924448e6f4466eebd83f7cff..eca4c7852d0f8c30b303847f62da57c02b1e69ab 100644 (file)
@@ -31,7 +31,8 @@
 #include <QRegExp>
 #include <QLayout>
 #include <QPainter>
-#include <QSplitter>
+#include <QByteArray>
+#include <QDataStream>
 #include <QFocusEvent>
 #include <QMouseEvent>
 #include <QRubberBand>
 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<QtxWorkstack*>( 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<int> sz = sizes();
+  for ( QList<int>::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<QtxWorkstackSplitter*>( wid );
+    if ( split )
+      split->saveState( stream );
+    else
+    {
+      QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( 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<QString, QtxWorkstackChild*>& map )
+{
+  int num = 0;
+  uchar flags = 0;
+
+  stream >> flags;
+  stream >> num;
+
+  setOrientation( flags & QtxWorkstack::Horizontal ? Qt::Horizontal : Qt::Vertical );
+
+  QList<int> 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<QtxWorkstackChild*> 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<QWidget*, bool> 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<QtxWorkstack*>( 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<QString, QtxWorkstackChild*>& 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<QWidget*, bool> 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<int, int> 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<QtxWorkstackArea*>( 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<int> sizes = split->sizes();
-  for ( QList<int>::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 "<param>=<value> ...".
-  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<QString, QtxWorkstackChild*> map;
+  QList<QtxWorkstackArea*> areaList;
+  areas( mySplit, areaList, true );
+  for ( QList<QtxWorkstackArea*>::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<QtxWorkstackChild*> childList = area->childList();
+    for ( QList<QtxWorkstackChild*>::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<QWidget*> l = qFindChildren<QWidget*>( parent->topLevelWidget(), aName );
-  if ( !l.isEmpty() )
-    view = ::qobject_cast<QWidget*>( 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<QSplitter*, QList<int> >& 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<int> 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<QtxWorkstackArea*> 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<QString, QtxWorkstackChild*>::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<QSplitter*> splitList;
-  QList<QtxWorkstackArea*> areaList;
-  splitters( mySplit, splitList, false );
-  areas( mySplit, areaList, false );
-  for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end(); ++iter )
-    delete *iter;
-
-  for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
-  {
-    if ( (*it)->isEmpty() )
-      delete *it;
-  }
-
-  // restore splitter recursively
-  QMap< QSplitter*, QList<int> > 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<QtxWorkstackArea*>::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<int> >::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;
+}
index 9d0a16bd52a358d24b3f536c0ececed7d403f140..c8abd3e7ebc473808ed2fa884451d48b495d8e44 100644 (file)
 
 #include "Qtx.h"
 
-#include <QWidget>
+#include <QMap>
 #include <QFrame>
-#include <QTabBar>
 #include <QEvent>
-#include <QMap>
+#include <QWidget>
+#include <QTabBar>
+#include <QPointer>
+#include <QSplitter>
 
 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<QSplitter*>&, 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<int> >& );
-  
+
 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<int, QAction*> 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<QString, QtxWorkstackChild*>& );
 };
 
 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<QtxWorkstackChild*> 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<QString, QtxWorkstackChild*>& );
+
 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<QWidget*, bool>               BlockMap;
-  typedef QMap<QWidget*, QtxWorkstackChild*> ChildMap;
-  typedef QMap<QWidget*, WidgetInfo>         WidgetInfoMap;
+  typedef QList<QtxWorkstackChild*> 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<QWidget>   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
index f63f36e7ee85f5373c5edbf84393c6ed6ca90531..4bbd251a63ebe05b9a3c09537019fa77abd522fc 100644 (file)
@@ -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" ) ) );
index 0244b0ac4a57185a6a923e255bd875cce9cfeeb2..8abfcaa27c54164084cbec414431fac3959ceea7 100644 (file)
@@ -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<QString,int> viewersCounter; // map viewerType - to - index_of_this_viewer_type
-  QListIterator<SUIT_ViewManager*> it(lst);
-  SUIT_ViewManager* aVM = 0;
-  while ( it.hasNext() ) {
-    aVM = it.next();
-    if ( !aVM ) continue;
+  QMap<QString, int> viewersCounter;
+  for ( QList<SUIT_ViewManager*>::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<SUIT_ViewWindow*> 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<int> 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<SUIT_ViewWindow*> views = vm->getViews();
     for(int i = 0; i<view_count; i++) {
       ip->append( 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<CAM_Module*> mlist; 
+  QList<CAM_Module*> mlist;
   myApp->modules( mlist );
   QListIterator<CAM_Module*> 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<SUIT_ViewManager*> 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<SUIT_ViewWindow*, QString> 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<std::string> 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<SUIT_ViewWindow*> views = vm->getViews();  
-    for (int i = 0, j = 0; i<viewCount; i++, j+=2) {
+    QVector<SUIT_ViewWindow*> views = vm->getViews();
+    for ( int i = 0, j = 0; i<viewCount; i++, j+=2 )
+    {
       viewWin = views[i];
-      if ( !viewWin ) 
+      if ( !viewWin )
        continue;
 
       // wait untill the window is really shown.  This step fixes MANY bugs..
-      while ( !vm->isVisible() )
-       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<std::string> v = ip->getValues("AP_MODULES_LIST");
-  for ( int i = 0; i < v.size(); i++ ) {
+  std::vector<std::string> 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<SalomeApp_Module*>( 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<SUIT_ViewManager*> itVM( lst );
-  SUIT_ViewManager* aVM = 0;
-  while ( itVM.hasNext() ) {
-    aVM = itVM.next();
-    if ( !aVM ) continue;
+  QList<SUIT_ViewManager*> lst;
+  myApp->viewManagers( lst );
+  for ( QList<SUIT_ViewManager*>::iterator itVM = lst.begin(); itVM != lst.end(); ++itVM )
+  {
+    SUIT_ViewManager* aVM = *itVM;
+    if ( !aVM )
+      continue;
 
     int view_count = aVM->getViewsCount();
     QVector<SUIT_ViewWindow*> 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<SUIT_ViewWindow> 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 );
 }