From c79ba5d819122a3608d546e17f223ad525ac5271 Mon Sep 17 00:00:00 2001 From: asv Date: Tue, 7 Mar 2006 15:50:46 +0000 Subject: [PATCH] Merged with OCC_visual_parameters_2006 branch. It consists development of persistent visual parameters (GUI states) and Dump Python functionality. Developers: srn, asv. --- idl/SALOME_Session.idl | 5 +- src/GLViewer/GLViewer_ViewFrame.cxx | 34 +++ src/GLViewer/GLViewer_ViewFrame.h | 3 + src/LightApp/resources/LightApp_msg_en.po | 6 + src/OCCViewer/OCCViewer_ViewWindow.cxx | 108 ++++--- src/OCCViewer/OCCViewer_ViewWindow.h | 5 + src/Plot2d/Plot2d_ViewFrame.cxx | 40 +++ src/Plot2d/Plot2d_ViewFrame.h | 3 + src/Plot2d/Plot2d_ViewWindow.cxx | 14 + src/Plot2d/Plot2d_ViewWindow.h | 3 + src/Qtx/Makefile.in | 3 +- src/Qtx/QtxWorkstack.cxx | 262 +++++++++++++++++ src/Qtx/QtxWorkstack.h | 9 +- src/SUIT/SUIT_DataObject.cxx | 4 +- src/SUIT/SUIT_Study.cxx | 15 + src/SUIT/SUIT_Study.h | 3 + src/SUIT/SUIT_TreeSync.h | 6 +- src/SUIT/SUIT_ViewWindow.cxx | 9 + src/SUIT/SUIT_ViewWindow.h | 3 + src/SVTK/SVTK_ViewWindow.cxx | 96 +++++++ src/SVTK/SVTK_ViewWindow.h | 18 ++ src/SalomeApp/Makefile.in | 6 +- src/SalomeApp/SalomeApp_Application.cxx | 244 ++++++++++++++-- src/SalomeApp/SalomeApp_Application.h | 13 +- src/SalomeApp/SalomeApp_DataModel.cxx | 26 +- src/SalomeApp/SalomeApp_DataModel.h | 5 +- src/SalomeApp/SalomeApp_DataObject.cxx | 49 ++++ src/SalomeApp/SalomeApp_DataObject.h | 40 ++- src/SalomeApp/SalomeApp_Module.cxx | 34 +++ src/SalomeApp/SalomeApp_Module.h | 5 +- src/SalomeApp/SalomeApp_Study.cxx | 113 +++++++- src/SalomeApp/SalomeApp_Study.h | 7 + src/SalomeApp/SalomeApp_VisualState.cxx | 295 ++++++++++++++++++++ src/SalomeApp/SalomeApp_VisualState.h | 47 ++++ src/SalomeApp/resources/SalomeApp.xml | 3 +- src/SalomeApp/resources/SalomeApp_msg_en.po | 42 +++ src/Session/Session_Session_i.cxx | 24 ++ src/Session/Session_Session_i.hxx | 3 + src/VTKViewer/VTKViewer_ViewWindow.cxx | 51 ++++ src/VTKViewer/VTKViewer_ViewWindow.h | 3 + 40 files changed, 1561 insertions(+), 98 deletions(-) create mode 100644 src/SalomeApp/SalomeApp_VisualState.cxx create mode 100644 src/SalomeApp/SalomeApp_VisualState.h diff --git a/idl/SALOME_Session.idl b/idl/SALOME_Session.idl index 3086194ee..f067b753a 100644 --- a/idl/SALOME_Session.idl +++ b/idl/SALOME_Session.idl @@ -105,6 +105,9 @@ module SALOME Get Active study ID */ long GetActiveStudyId(); +/*! + Restores a state of the study at theSavePoint +*/ + boolean restoreVisualState(in long theSavePoint); } ; - } ; diff --git a/src/GLViewer/GLViewer_ViewFrame.cxx b/src/GLViewer/GLViewer_ViewFrame.cxx index 6600bb35f..a466d7b2f 100644 --- a/src/GLViewer/GLViewer_ViewFrame.cxx +++ b/src/GLViewer/GLViewer_ViewFrame.cxx @@ -547,3 +547,37 @@ void GLViewer_ViewFrame::wheelEvent( QWheelEvent* e ) break; } } + +/*! The method returns the visual parameters of this view as a formated string + */ +QString GLViewer_ViewFrame::getVisualParameters() +{ + QString retStr; + if ( myVP && myVP->inherits( "GLViewer_ViewPort2d" ) ) { + GLViewer_ViewPort2d* vp2d = (GLViewer_ViewPort2d*)myVP; + GLfloat xSc, ySc, xPan, yPan; + vp2d->getScale( xSc, ySc ); + vp2d->getPan( xPan, yPan ); + retStr.sprintf( "%.12e*%.12e*%.12e*%.12e", xSc, ySc, xPan, yPan ); + } + return retStr; +} + +/* The method restors visual parameters of this view from a formated string + */ +void GLViewer_ViewFrame::setVisualParameters( const QString& parameters ) +{ + QStringList paramsLst = QStringList::split( '*', parameters, true ); + if ( myVP && myVP->inherits( "GLViewer_ViewPort2d" ) && paramsLst.size() == 4) { + GLViewer_ViewPort2d* vp2d = (GLViewer_ViewPort2d*)myVP; + + GLfloat xSc, ySc, xPan, yPan; + xSc = paramsLst[0].toDouble(); + ySc = paramsLst[1].toDouble(); + xPan = paramsLst[2].toDouble(); + yPan = paramsLst[3].toDouble(); + + vp2d->getGLWidget()->setScale( xSc, ySc, 1. ); + vp2d->getGLWidget()->setPan( xPan, yPan, 0. ); + } +} diff --git a/src/GLViewer/GLViewer_ViewFrame.h b/src/GLViewer/GLViewer_ViewFrame.h index d90dfd3f5..8b9267a42 100644 --- a/src/GLViewer/GLViewer_ViewFrame.h +++ b/src/GLViewer/GLViewer_ViewFrame.h @@ -72,6 +72,9 @@ public: QSize sizeHint() const; virtual void onUpdate( int ); + + virtual QString getVisualParameters(); + virtual void setVisualParameters( const QString& parameters ); signals: void vfDrawExternal( QPainter* ); diff --git a/src/LightApp/resources/LightApp_msg_en.po b/src/LightApp/resources/LightApp_msg_en.po index c5b364d56..09f901332 100644 --- a/src/LightApp/resources/LightApp_msg_en.po +++ b/src/LightApp/resources/LightApp_msg_en.po @@ -322,3 +322,9 @@ msgstr "&Cancel" msgid "LightApp_ModuleDlg::ActivateComponent_DESCRIPTION" msgstr "Create, open or load study." + +msgid "LightApp_NameDlg::TLT_RENAME" +msgstr "Rename" + +msgid "LightApp_NameDlg::NAME_LBL" +msgstr "Name: " diff --git a/src/OCCViewer/OCCViewer_ViewWindow.cxx b/src/OCCViewer/OCCViewer_ViewWindow.cxx index 4900fd9de..dbd2618b6 100755 --- a/src/OCCViewer/OCCViewer_ViewWindow.cxx +++ b/src/OCCViewer/OCCViewer_ViewWindow.cxx @@ -851,37 +851,7 @@ void OCCViewer_ViewWindow::onClipping( bool on ) //**************************************************************** void OCCViewer_ViewWindow::onMemorizeView() { - double centerX, centerY, projX, projY, projZ, twist; - double atX, atY, atZ, eyeX, eyeY, eyeZ; - - Handle(V3d_View) aView3d = myViewPort->getView(); - - aView3d->Center( centerX, centerY ); - aView3d->Proj( projX, projY, projZ ); - aView3d->At( atX, atY, atZ ); - aView3d->Eye( eyeX, eyeY, eyeZ ); - twist = aView3d->Twist(); - - viewAspect params; - QString aName = QTime::currentTime().toString() + QString::fromLatin1( " h:m:s" ); - - params.scale = aView3d->Scale(); - params.centerX = centerX; - params.centerY = centerY; - params.projX = projX; - params.projY = projY; - params.projZ = projZ; - params.twist = twist; - params.atX = atX; - params.atY = atY; - params.atZ = atZ; - params.eyeX = eyeX; - params.eyeY = eyeY; - params.eyeZ = eyeZ; - params.name = aName; - - myModel->appendViewAspect( params ); - + myModel->appendViewAspect( getViewParams() ); } //**************************************************************** @@ -904,11 +874,11 @@ void OCCViewer_ViewWindow::performRestoring( const viewAspect& anItem ) Standard_Boolean prev = aView3d->SetImmediateUpdate( Standard_False ); aView3d->SetScale( anItem.scale ); aView3d->SetCenter( anItem.centerX, anItem.centerY ); - aView3d->SetProj( anItem.projX, anItem.projY, anItem.projZ ); aView3d->SetTwist( anItem.twist ); aView3d->SetAt( anItem.atX, anItem.atY, anItem.atZ ); aView3d->SetImmediateUpdate( prev ); aView3d->SetEye( anItem.eyeX, anItem.eyeY, anItem.eyeZ ); + aView3d->SetProj( anItem.projX, anItem.projY, anItem.projZ ); myRestoreFlag = 0; } @@ -980,3 +950,77 @@ void OCCViewer_ViewWindow::setCuttingPlane( bool on, const double x, const dou v->Update(); v->Redraw(); } + +/*! The method returns the visual parameters of this view as a viewAspect object + */ +viewAspect OCCViewer_ViewWindow::getViewParams() const +{ + double centerX, centerY, projX, projY, projZ, twist; + double atX, atY, atZ, eyeX, eyeY, eyeZ; + + Handle(V3d_View) aView3d = myViewPort->getView(); + + aView3d->Center( centerX, centerY ); + aView3d->Proj( projX, projY, projZ ); + aView3d->At( atX, atY, atZ ); + aView3d->Eye( eyeX, eyeY, eyeZ ); + twist = aView3d->Twist(); + + QString aName = QTime::currentTime().toString() + QString::fromLatin1( " h:m:s" ); + + viewAspect params; + params.scale = aView3d->Scale(); + params.centerX = centerX; + params.centerY = centerY; + params.projX = projX; + params.projY = projY; + params.projZ = projZ; + params.twist = twist; + params.atX = atX; + params.atY = atY; + params.atZ = atZ; + params.eyeX = eyeX; + params.eyeY = eyeY; + params.eyeZ = eyeZ; + params.name = aName; + + return params; +} + + +/*! The method returns the visual parameters of this view as a formated string + */ +QString OCCViewer_ViewWindow::getVisualParameters() +{ + viewAspect params = getViewParams(); + QString retStr; + retStr.sprintf( "%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e", params.scale, + params.centerX, params.centerY, params.projX, params.projY, params.projZ, params.twist, + params.atX, params.atY, params.atZ, params.eyeX, params.eyeY, params.eyeZ ); + return retStr; +} + +/* The method restors visual parameters of this view from a formated string + */ +void OCCViewer_ViewWindow::setVisualParameters( const QString& parameters ) +{ + QStringList paramsLst = QStringList::split( '*', parameters, true ); + if ( paramsLst.size() == 13 ) { + viewAspect params; + params.scale = paramsLst[0].toDouble(); + params.centerX = paramsLst[1].toDouble(); + params.centerY = paramsLst[2].toDouble(); + params.projX = paramsLst[3].toDouble(); + params.projY = paramsLst[4].toDouble(); + params.projZ = paramsLst[5].toDouble(); + params.twist = paramsLst[6].toDouble(); + params.atX = paramsLst[7].toDouble(); + params.atY = paramsLst[8].toDouble(); + params.atZ = paramsLst[9].toDouble(); + params.eyeX = paramsLst[10].toDouble(); + params.eyeY = paramsLst[11].toDouble(); + params.eyeZ = paramsLst[12].toDouble(); + + performRestoring( params ); + } +} diff --git a/src/OCCViewer/OCCViewer_ViewWindow.h b/src/OCCViewer/OCCViewer_ViewWindow.h index b4f2bc8db..b6bda965a 100755 --- a/src/OCCViewer/OCCViewer_ViewWindow.h +++ b/src/OCCViewer/OCCViewer_ViewWindow.h @@ -62,6 +62,9 @@ public: void setCuttingPlane( bool on, const double x = 0 , const double y = 0 , const double z = 0, const double dx = 0, const double dy = 0, const double dz = 1); + + virtual QString getVisualParameters(); + virtual void setVisualParameters( const QString& parameters ); public slots: void onFrontView(); @@ -119,6 +122,8 @@ protected: virtual OperationType getButtonState(QMouseEvent* theEvent); + viewAspect getViewParams() const; + OperationType myOperation; OCCViewer_Viewer* myModel; OCCViewer_ViewPort3d* myViewPort; diff --git a/src/Plot2d/Plot2d_ViewFrame.cxx b/src/Plot2d/Plot2d_ViewFrame.cxx index 30a25e808..35f4b5888 100755 --- a/src/Plot2d/Plot2d_ViewFrame.cxx +++ b/src/Plot2d/Plot2d_ViewFrame.cxx @@ -1918,3 +1918,43 @@ bool Plot2d_ViewFrame::print( const QString& file, const QString& format ) const return res; #endif } + +QString Plot2d_ViewFrame::getVisualParameters() +{ + double xmin, xmax, ymin, ymax, y2min, y2max; + getFitRanges( xmin, xmax, ymin, ymax, y2min, y2max ); + QString retStr; + retStr.sprintf( "%d*%d*%d*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e", myXMode, + myYMode, mySecondY, xmin, xmax, ymin, ymax, y2min, y2max ); + return retStr; +} + +void Plot2d_ViewFrame::setVisualParameters( const QString& parameters ) +{ + QStringList paramsLst = QStringList::split( '*', parameters, true ); + if ( paramsLst.size() == 9 ) { + double xmin, xmax, ymin, ymax, y2min, y2max; + myXMode = paramsLst[0].toInt(); + myYMode = paramsLst[1].toInt(); + mySecondY = (bool)paramsLst[2].toInt(); + xmin = paramsLst[3].toDouble(); + xmax = paramsLst[4].toDouble(); + ymin = paramsLst[5].toDouble(); + ymax = paramsLst[6].toDouble(); + y2min = paramsLst[7].toDouble(); + y2max = paramsLst[8].toDouble(); + + if (mySecondY) + setTitle( myY2TitleEnabled, myY2Title, Y2Title, false ); + setHorScaleMode( myXMode, /*update=*/false ); + setVerScaleMode( myYMode, /*update=*/false ); + + if (mySecondY) { + QwtDiMap yMap2 = myPlot->canvasMap( QwtPlot::yRight ); + myYDistance2 = yMap2.d2() - yMap2.d1(); + } + + fitData( 0, xmin, xmax, ymin, ymax, y2min, y2max ); + fitData( 0, xmin, xmax, ymin, ymax, y2min, y2max ); + } +} diff --git a/src/Plot2d/Plot2d_ViewFrame.h b/src/Plot2d/Plot2d_ViewFrame.h index 51faa0898..5d1faccb5 100755 --- a/src/Plot2d/Plot2d_ViewFrame.h +++ b/src/Plot2d/Plot2d_ViewFrame.h @@ -118,6 +118,9 @@ public: virtual bool print( const QString& file, const QString& format ) const; + QString getVisualParameters(); + void setVisualParameters( const QString& parameters ); + protected: int testOperation( const QMouseEvent& ); void readPreferences(); diff --git a/src/Plot2d/Plot2d_ViewWindow.cxx b/src/Plot2d/Plot2d_ViewWindow.cxx index 5c558ea0f..017e8fada 100755 --- a/src/Plot2d/Plot2d_ViewWindow.cxx +++ b/src/Plot2d/Plot2d_ViewWindow.cxx @@ -465,3 +465,17 @@ QString Plot2d_ViewWindow::filter() const { return SUIT_ViewWindow::filter() + ";;" + tr( "POSTSCRIPT_FILES" ); } + +/*! The method returns the visual parameters of this view as a formated string + */ +QString Plot2d_ViewWindow::getVisualParameters() +{ + return myViewFrame->getVisualParameters(); +} + +/* The method restors visual parameters of this view from a formated string + */ +void Plot2d_ViewWindow::setVisualParameters( const QString& parameters ) +{ + myViewFrame->setVisualParameters( parameters ); +} diff --git a/src/Plot2d/Plot2d_ViewWindow.h b/src/Plot2d/Plot2d_ViewWindow.h index 571d692bf..ec0e5bf64 100755 --- a/src/Plot2d/Plot2d_ViewWindow.h +++ b/src/Plot2d/Plot2d_ViewWindow.h @@ -46,6 +46,9 @@ public: QToolBar* getToolBar() { return myToolBar; }; void contextMenuPopup( QPopupMenu* thePopup ); + virtual QString getVisualParameters(); + virtual void setVisualParameters( const QString& parameters ); + protected: virtual QImage dumpView(); virtual QString filter() const; diff --git a/src/Qtx/Makefile.in b/src/Qtx/Makefile.in index aa682b59d..02f58984b 100755 --- a/src/Qtx/Makefile.in +++ b/src/Qtx/Makefile.in @@ -1,4 +1,5 @@ -# File : Makefile.in # Author : Vladimir Klyachin (OCN) +# File : Makefile.in +# Author : Vladimir Klyachin (OCN) # Module : suit # $Header$ diff --git a/src/Qtx/QtxWorkstack.cxx b/src/Qtx/QtxWorkstack.cxx index c267236f2..5e01f08e8 100644 --- a/src/Qtx/QtxWorkstack.cxx +++ b/src/Qtx/QtxWorkstack.cxx @@ -36,8 +36,10 @@ #include #include #include +#include #define DARK_COLOR_LIGHT 250 + /*! Class: QtxWorkstack [Public] Descr: @@ -1131,6 +1133,266 @@ void QtxWorkstack::updateState( QSplitter* split ) split->hide(); } +void QtxWorkstack::splitterInfo( QSplitter* split, QString& info ) const +{ + if ( !split ) + return; + + const QObjectList* objs = split->children(); + if ( objs ) + { + // make up a sizes string: integer values are separated by ':' char + QValueList sizes = split->sizes(); + QString sizesStr; + for ( QValueList::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 + } + if ( !sizesStr.isEmpty() ) // cut the first ':' + sizesStr = sizesStr.right( sizesStr.length()-1 ); + + // count all QSplitter-s and QtxWorkstackArea-s + // int nChilds( 0 ); + // QObjectListIt it( *objs ); + // for ( ; it.current(); ++it ) + // { + // if ( it.current()->inherits( "QSplitter" ) || + // it.current()->inherits( "QtxWorkstackArea" ) ) + // nChilds++; + // } + + info += QString( "(splitter orientation=%1 sizes=%3 " ).arg( split->orientation() ).arg( sizesStr ); + + for ( QObjectListIt it( *objs ); it.current(); ++it ) + { + if ( it.current()->inherits( "QSplitter" ) ) + splitterInfo( (QSplitter*)it.current(), info ); + else if ( it.current()->inherits( "QtxWorkstackArea" ) ) { + QtxWorkstackArea* area = (QtxWorkstackArea*)it.current(); + if ( area->isEmpty() ) + continue; + info += QString( "(views active='%1'" ).arg( area->activeWidget()->name() ); + QWidgetList views = area->widgetList(); + for ( QWidgetListIt wIt( views ); wIt.current(); ++wIt ) + info += QString( " '%1'" ).arg( wIt.current()->name() ); + info += ')'; + } + } + } + info += ')'; +} + + +// cuts starting '(' symbol and ending '(' symbol +void cutBrackets( QString& parameters ) +{ + if ( !parameters.isEmpty() && parameters[0] == '(' && parameters[parameters.length()-1] == ')' ) + parameters = parameters.mid( 1, parameters.length()-2 ); +} + +// for strings like "(splitter orientation=0 children=2 sizes=332:478" returns values of +// parameters. For example, getValue( example, "children" ) returns "2" +// getValue( example, "sizes" ) returns "332:478" +QString getValue( const QString& str, const QString& valName ) +{ + int i = str.find( valName ); + if ( i != -1 ) { + int equal_i = str.find( '=', i ); + if ( equal_i != -1 ) { + int space_i = str.find( ' ', ++equal_i ); + if ( space_i != -1 ) + return str.mid( equal_i, space_i-equal_i ); + } + } + return QString( "" ); +} + +// checks format of splitter parameters string +bool checkFormat( const QString& parameters ) +{ + QString params( parameters ); + // 1. begins and ends with brackets + bool ok = ( params[0] == '(' && params[params.length()-1] == ')' ); + 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.find( '(' ); + 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; +} + +// returns children of splitter in a list. Children are separated by '(' and ')' symbols +QStringList getChildren( const QString& str ) +{ + QStringList lst; + if ( !str.startsWith( "(" ) ) + return lst; + + int i = 1, + nOpen = 1, // count brackets: '(' increments nOpen, ')' decrements + start = 0; + while ( i < 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; +} + +// for a string like "views active='AnotherView' 'GLView' 'AnotherView'" +// getViewName( example, 0 ) returns "GLView", +// getViewName( example, 1 ) -> "AnotherView", etc. +QString getViewName( const QString& str, int i ) +{ + 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.search( str, start ) ) != -1 && num < i ) { + start += exp.matchedLength(); + num ++; + } + if ( start != -1 ) // +2 and -3 avoid starting space and starting and ending ' symbols + return str.mid( start+2, exp.matchedLength()-3 ); + + return QString( "" ); +} + +// returns widget with given name +QWidget* getView( const QWidget* parent, const QString& aName ) +{ + QWidget* view = 0; + QObjectList *l = parent->topLevelWidget()->queryList( "QWidget", aName, false, true ); + if ( !l->isEmpty() ) + view = dynamic_cast( l->first() ); + delete l; + return view; +} + +// installs a splitter described by given parameters string +void QtxWorkstack::setSplitter( QSplitter* splitter, const QString& parameters, QMap< QSplitter*, QValueList >& sMap ) +{ + if ( !::checkFormat( parameters ) ) { + printf( "\nInvalid format of workstack parameters. Positions of viewers can not be restored.\n" ); + return; + } + + QString params( parameters ); + ::cutBrackets( params ); + + // get splitter sizes and store it in the map for future setting + QValueList sizes; + QStringList sizesLst = QStringList::split( ':', ::getValue( params, "sizes" ) ); + for ( QStringList::Iterator it = sizesLst.begin(); it != sizesLst.end(); ++it ) + sizes.append( (*it).toInt() ); + sMap[ splitter ] = sizes; + + // set orientation of splitter + int orient = ::getValue( params, "orientation" ).toInt(); + splitter->setOrientation( (Qt::Orientation)orient ); + + // get children + QString options = params.left( params.find( '(' ) ); + QString childrenStr = params.right( params.length()-options.length() ); + QStringList children = ::getChildren( childrenStr ); + + // debug output.. + // printf (" splitter orient=%d, sizes_count=%d, children=%d\n", orient, sizes.count(), children.count() ); + // for ( QStringList::Iterator tit = children.begin(); tit != children.end(); ++tit ) + // printf (" |-> child = [%s]\n", (*tit).latin1() ); + + for ( QStringList::Iterator it = children.begin(); it != children.end(); ++it ) { + if ( (*it).startsWith( "(splitter" ) ) { + QSplitter* newSplitter = new QSplitter( splitter ); + setSplitter( newSplitter, *it, sMap ); + } + else if ( (*it).startsWith( "(views" ) ) { + QtxWorkstackArea* newArea = createArea( splitter ); + QString activeViewName = ::getValue( *it, "active" ); + QWidget* activeView( 0 ); + activeViewName = activeViewName.mid( 1, activeViewName.length()-2 ); // chop off ' symbols + int i = 0; + QString viewName = ::getViewName( *it, i ); + while ( !viewName.isEmpty() ) { + if ( QWidget* view = ::getView( splitter, viewName ) ) { + newArea->insertWidget( view ); + if ( activeViewName == view->name() ) + activeView = view; + } + viewName = ::getViewName( *it, ++i ); + } + if ( activeView ) + newArea->setActiveWidget( activeView ); + } + } +} + +// Restore workstack's configuration stored in 'parameters' string +QtxWorkstack& QtxWorkstack::operator<<( const QString& parameters ) +{ + // clear the main splitter - remove all child splitters and empty areas from it + QPtrList splitList; + QPtrList areaList; + splitters( mySplit, splitList, false ); + areas( mySplit, areaList, false ); + for ( QPtrListIterator iter( splitList ); iter.current(); ++iter ) + delete iter.current(); + for ( QPtrListIterator it( areaList ); it.current(); ++it ) + if ( it.current()->isEmpty() ) + delete it.current(); + + // restore splitter recursively + QMap< QSplitter*, QValueList > 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 ( QPtrListIterator delIt( areaList ); delIt.current(); ++delIt ) + if ( delIt.current()->isEmpty() ) + delete delIt.current(); + + qApp->processEvents(); + + // restore splitters' sizes (map of sizes is filled in setSplitters) + for ( QMap< QSplitter*, QValueList >::Iterator it = sMap.begin(); it != sMap.end(); ++it ) + it.key()->setSizes( it.data() ); + + return (*this); +} + +// Example of string produced by operator>> : +// "(splitter orientation=0 sizes=186:624 (views active='OCCViewer_0_0' 'OCCViewer_0_0') +// (views active='VTKViewer_0_0' 'VTKViewer_0_0'))" +QtxWorkstack& QtxWorkstack::operator>>( QString& outParameters ) +{ + splitterInfo( mySplit, outParameters ); + return (*this); +} + + /*! Class: QtxWorkstackArea [Internal] Descr: diff --git a/src/Qtx/QtxWorkstack.h b/src/Qtx/QtxWorkstack.h index 8157a2a81..36b4382bd 100644 --- a/src/Qtx/QtxWorkstack.h +++ b/src/Qtx/QtxWorkstack.h @@ -81,6 +81,10 @@ public: 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* ); @@ -125,7 +129,10 @@ private: 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*,QValueList >& ); + private: QWidget* myWin; QtxWorkstackArea* myArea; diff --git a/src/SUIT/SUIT_DataObject.cxx b/src/SUIT/SUIT_DataObject.cxx index afc3446f3..ddb393817 100755 --- a/src/SUIT/SUIT_DataObject.cxx +++ b/src/SUIT/SUIT_DataObject.cxx @@ -22,8 +22,6 @@ #include "SUIT_DataObjectKey.h" -#include // for cout in dump() - /*! Constructor */ @@ -491,7 +489,7 @@ SUIT_DataObjectKey* SUIT_DataObject::key() const void SUIT_DataObject::dump( const int indent ) const { QString strIndent = QString().fill( ' ', indent ); // indentation string - std::cout << strIndent << name() << std::endl; // dump to cout + printf( "%s%s\n", strIndent.latin1(), name().latin1() ); for ( DataObjectListIterator it( myChildren ); it.current(); ++it ) // iterate all children it.current()->dump( indent + 2 ); // dump every child with indent + 2 spaces } diff --git a/src/SUIT/SUIT_Study.cxx b/src/SUIT/SUIT_Study.cxx index 2f83179c4..995aede9e 100755 --- a/src/SUIT/SUIT_Study.cxx +++ b/src/SUIT/SUIT_Study.cxx @@ -510,3 +510,18 @@ bool SUIT_Study::hasTransaction() const { return false; } + +/*! + * \brief Stores the study state +*/ +int SUIT_Study::storeState() +{ + return -1; +} + +/*! + * \brief Restores the study state +*/ +void SUIT_Study::restoreState(int savePoint) +{ +} diff --git a/src/SUIT/SUIT_Study.h b/src/SUIT/SUIT_Study.h index c1163cc6c..da090c8a0 100755 --- a/src/SUIT/SUIT_Study.h +++ b/src/SUIT/SUIT_Study.h @@ -75,6 +75,9 @@ public: bool suspend( SUIT_Operation* ); bool resume( SUIT_Operation* ); + virtual int storeState(); + virtual void restoreState(int savePoint); + signals: void studyModified( SUIT_Study* ); diff --git a/src/SUIT/SUIT_TreeSync.h b/src/SUIT/SUIT_TreeSync.h index d38f6fcdf..19bdf4edd 100644 --- a/src/SUIT/SUIT_TreeSync.h +++ b/src/SUIT/SUIT_TreeSync.h @@ -38,10 +38,12 @@ const typename QValueList::const_iterator findEqual( const QValueList TrgItem synchronize( const SrcItem& r1, const TrgItem& r2, const TreeData& td ) { - // printf( "--- synchronize : %d ---\n", ++gSync ); - if( td.isEqual( r1, r2 ) ) { + // update items themselves + td.updateItem( r2 ); + + // iterate 'siblings' (direct children) QValueList< DiffItem< SrcItem, TrgItem > > d; diffSiblings( r1, r2, d, td ); diff --git a/src/SUIT/SUIT_ViewWindow.cxx b/src/SUIT/SUIT_ViewWindow.cxx index bd4c32e69..3b013f679 100755 --- a/src/SUIT/SUIT_ViewWindow.cxx +++ b/src/SUIT/SUIT_ViewWindow.cxx @@ -158,3 +158,12 @@ void SUIT_ViewWindow::onAccelAction( int _action ) void SUIT_ViewWindow::action( const int ) { } + +QString SUIT_ViewWindow::getVisualParameters() +{ + return "empty"; +} + +void SUIT_ViewWindow::setVisualParameters( const QString& parameters ) +{ +} diff --git a/src/SUIT/SUIT_ViewWindow.h b/src/SUIT/SUIT_ViewWindow.h index 1ac79a504..200deb1c4 100755 --- a/src/SUIT/SUIT_ViewWindow.h +++ b/src/SUIT/SUIT_ViewWindow.h @@ -52,6 +52,9 @@ public: void onAccelAction( int ); + virtual QString getVisualParameters(); + virtual void setVisualParameters( const QString& parameters ); + public slots: virtual void onDumpView(); diff --git a/src/SVTK/SVTK_ViewWindow.cxx b/src/SVTK/SVTK_ViewWindow.cxx index 2e536541b..69e5eae4a 100755 --- a/src/SVTK/SVTK_ViewWindow.cxx +++ b/src/SVTK/SVTK_ViewWindow.cxx @@ -597,3 +597,99 @@ SVTK_ViewWindow myMainWindow->InvokeEvent( anEvent, 0 ); } } + +/*! The method returns the visual parameters of this view as a formated string + */ +QString +SVTK_ViewWindow +::getVisualParameters() +{ + double pos[3], focalPnt[3], viewUp[3], parScale, scale[3]; + + vtkCamera* camera = getRenderer()->GetActiveCamera(); + camera->GetPosition( pos ); + camera->GetFocalPoint( focalPnt ); + camera->GetViewUp( viewUp ); + parScale = camera->GetParallelScale(); + GetScale( scale ); + + QString retStr; + retStr.sprintf( "%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e", + pos[0], pos[1], pos[2], focalPnt[0], focalPnt[1], focalPnt[2], viewUp[0], viewUp[1], + viewUp[2], parScale, scale[0], scale[1], scale[2] ); + return retStr; +} + +/* The method restores visual parameters of this view or postpones it untill the view is shown + */ +void +SVTK_ViewWindow +::setVisualParameters( const QString& parameters ) +{ + SVTK_RenderWindowInteractor* anInteractor = getMainWindow()->GetInteractor(); + if ( anInteractor->isVisible() ) { + doSetVisualParameters( parameters ); + } + else { + myVisualParams = parameters; + anInteractor->installEventFilter(this); + } +} + +/* The method restores visual parameters of this view from a formated string + */ +void +SVTK_ViewWindow +::doSetVisualParameters( const QString& parameters ) +{ + QStringList paramsLst = QStringList::split( '*', parameters, true ); + if ( paramsLst.size() == 13 ) { + // 'reading' list of parameters + double pos[3], focalPnt[3], viewUp[3], parScale, scale[3]; + pos[0] = paramsLst[0].toDouble(); + pos[1] = paramsLst[1].toDouble(); + pos[2] = paramsLst[2].toDouble(); + focalPnt[0] = paramsLst[3].toDouble(); + focalPnt[1] = paramsLst[4].toDouble(); + focalPnt[2] = paramsLst[5].toDouble(); + viewUp[0] = paramsLst[6].toDouble(); + viewUp[1] = paramsLst[7].toDouble(); + viewUp[2] = paramsLst[8].toDouble(); + parScale = paramsLst[9].toDouble(); + scale[0] = paramsLst[10].toDouble(); + scale[1] = paramsLst[11].toDouble(); + scale[2] = paramsLst[12].toDouble(); + + // applying parameters + vtkCamera* camera = getRenderer()->GetActiveCamera(); + camera->SetPosition( pos ); + camera->SetFocalPoint( focalPnt ); + camera->SetViewUp( viewUp ); + camera->SetParallelScale( parScale ); + SetScale( scale ); + + // resize( size() ); + + // getRenderer()->ResetCameraClippingRange(); + // Repaint(); + // getMainWindow()->GetRenderer()->GetTransform()->SetMatrixScale( scale[0], scale[1], scale[2] ); + } +} + + +//================================================================ +// Function : eventFilter +/*! Purpose : delayed setVisualParameters +*/ +//================================================================ +bool SVTK_ViewWindow::eventFilter( QObject* theWatched, QEvent* theEvent ) +{ + if ( theEvent->type() == QEvent::Show && theWatched->inherits( "SVTK_RenderWindowInteractor" ) ) { + SVTK_RenderWindowInteractor* anInteractor = (SVTK_RenderWindowInteractor*)theWatched; + if ( anInteractor->isVisible() ) { + doSetVisualParameters( myVisualParams ); + anInteractor->removeEventFilter( this ); // theWatched = RenderWindowInteractor + } + } + return SUIT_ViewWindow::eventFilter( theWatched, theEvent ); +} diff --git a/src/SVTK/SVTK_ViewWindow.h b/src/SVTK/SVTK_ViewWindow.h index 1eb88a773..51e50ac45 100755 --- a/src/SVTK/SVTK_ViewWindow.h +++ b/src/SVTK/SVTK_ViewWindow.h @@ -242,6 +242,19 @@ class SVTK_EXPORT SVTK_ViewWindow : public SUIT_ViewWindow void SetSelectionTolerance(const double& theTolNodes = 0.025, const double& theTolCell = 0.001); + + //! Methods to save/restore visual parameters of a view (pan, zoom, etc.) + virtual + QString + getVisualParameters(); + + virtual + void + setVisualParameters( const QString& parameters ); + + virtual + bool + eventFilter( QObject*, QEvent* ); public slots: virtual @@ -326,12 +339,17 @@ protected: Initialize(SVTK_View* theView, SVTK_ViewModelBase* theModel); + void + doSetVisualParameters( const QString& ); + QImage dumpView(); virtual void action( const int ); SVTK_View* myView; SVTK_MainWindow* myMainWindow; SVTK_ViewModelBase* myModel; + + QString myVisualParams; // used for delayed setting of view parameters }; #ifdef WIN32 diff --git a/src/SalomeApp/Makefile.in b/src/SalomeApp/Makefile.in index cb3ce909e..8913a2b44 100755 --- a/src/SalomeApp/Makefile.in +++ b/src/SalomeApp/Makefile.in @@ -25,7 +25,8 @@ EXPORT_HEADERS= SalomeApp.h \ SalomeApp_Filter.h \ SalomeApp_TypeFilter.h \ SalomeApp_StudyPropertiesDlg.h \ - SalomeApp_CheckFileDlg.h + SalomeApp_CheckFileDlg.h \ + SalomeApp_VisualState.h # .po files to transform in .qm PO_FILES = SalomeApp_images.po \ @@ -48,7 +49,8 @@ LIB_SRC= SalomeApp_Module.cxx \ SalomeApp_TypeFilter.cxx \ SalomeApp_StudyPropertiesDlg.cxx \ SalomeApp_ListView.cxx \ - SalomeApp_CheckFileDlg.cxx + SalomeApp_CheckFileDlg.cxx \ + SalomeApp_VisualState.cxx LIB_MOC = SalomeApp_Application.h \ SalomeApp_DataModel.h \ diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index afe4b2b87..76cabcd3f 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -11,15 +11,15 @@ #include "SalomeApp_DataModel.h" #include "SalomeApp_DataObject.h" #include "SalomeApp_EventFilter.h" +#include "SalomeApp_VisualState.h" #include "SalomeApp_StudyPropertiesDlg.h" -#include "SalomeApp_CheckFileDlg.h" - #include "LightApp_Application.h" #include "LightApp_Preferences.h" #include "LightApp_WidgetContainer.h" #include "LightApp_SelectionMgr.h" +#include "LightApp_NameDlg.h" #include "STD_LoadStudiesDlg.h" @@ -48,6 +48,13 @@ #include #include #include +#include +#include +#include + +#include "SALOMEDS_StudyManager.hxx" +#include "SALOMEDS_SObject.hxx" +#include "SALOMEDS_IParameters.hxx" #include "SALOME_ListIteratorOfListIO.hxx" #include "SALOME_ListIO.hxx" @@ -98,6 +105,11 @@ void SalomeApp_Application::createActions() SUIT_Desktop* desk = desktop(); + //! Save GUI state + createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIconSet(), + tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ), + 0, desk, false, this, SLOT( onSaveGUIState() ) ); + //! Dump study createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIconSet(), tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ), @@ -125,6 +137,7 @@ void SalomeApp_Application::createActions() int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 ); + createMenu( SaveGUIStateId, fileMenu, 10, -1 ); createMenu( DumpStudyId, fileMenu, 10, -1 ); createMenu( separator(), fileMenu, -1, 15, -1 ); createMenu( LoadScriptId, fileMenu, 10, -1 ); @@ -361,8 +374,12 @@ void SalomeApp_Application::onSelectionChanged() _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry()); if ( so ) { - canCopy = studyMgr()->CanCopy(so); - canPaste = studyMgr()->CanPaste(so); + SALOMEDS_SObject* aSO = dynamic_cast(so.get()); + + if ( aSO ) { + canCopy = studyMgr()->CanCopy(so); + canPaste = studyMgr()->CanPaste(so); + } } } } @@ -454,14 +471,41 @@ void SalomeApp_Application::updateCommandsStatus() if ( a ) a->setEnabled( activeStudy() ); + // Properties menu a = action( PropertiesId ); if( a ) a->setEnabled( activeStudy() ); + // Save GUI state menu + a = action( SaveGUIStateId ); + if( a ) + a->setEnabled( activeStudy() ); + // update state of Copy/Paste menu items onSelectionChanged(); } +/* + Class : DumpStudyFileDlg + Description : Private class used in Dump Study operation. Consists 2 check boxes: + "Publish in study" and "Save GUI parameters" +*/ +class DumpStudyFileDlg : public SUIT_FileDlg +{ +public: + DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true ) + { + QHBox* hB = new QHBox( this ); + myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY"), hB ); + mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE"), hB ); + QPushButton* pb = new QPushButton(this); + addWidgets( new QLabel("", this), hB, pb ); + pb->hide(); + } + QCheckBox* myPublishChk; + QCheckBox* mySaveGUIChk; +}; + /*!Private SLOT. On dump study.*/ void SalomeApp_Application::onDumpStudy( ) { @@ -472,23 +516,34 @@ void SalomeApp_Application::onDumpStudy( ) QStringList aFilters; aFilters.append( tr( "PYTHON_FILES_FILTER" ) ); - SalomeApp_CheckFileDlg* fd = new SalomeApp_CheckFileDlg( desktop(), false, tr("PUBLISH_IN_STUDY"), true, true); + DumpStudyFileDlg* fd = new DumpStudyFileDlg( desktop() ); fd->setCaption( tr( "TOT_DESK_FILE_DUMP_STUDY" ) ); fd->setFilters( aFilters ); - fd->SetChecked(true); + fd->myPublishChk->setChecked( true ); + fd->mySaveGUIChk->setChecked( true ); fd->exec(); QString aFileName = fd->selectedFile(); - bool toPublish = fd->IsChecked(); + bool toPublish = fd->myPublishChk->isChecked(); + bool toSaveGUI = fd->mySaveGUIChk->isChecked(); delete fd; - if(!aFileName.isEmpty()) { + if ( !aFileName.isEmpty() ) { QFileInfo aFileInfo(aFileName); - bool res = aStudy->DumpStudy( aFileInfo.dirPath( true ).latin1(), aFileInfo.baseName().latin1(), toPublish ); + int savePoint; + if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method + SALOMEDS_IParameters::setDumpPython(appStudy->studyDS()); + savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point + //prefix = SALOMEDS_IParameters::getStudyScript(appStudy->studyDS(), appStudy->getVisualComponentName(), savePoint); + + } + bool res = aStudy->DumpStudy( aFileInfo.dirPath( true ).latin1(), aFileInfo.baseName().latin1(), toPublish); + if ( toSaveGUI ) + appStudy->removeSavePoint(savePoint); //SRN: remove the created temporary save point. if ( !res ) - SUIT_MessageBox::warn1 ( desktop(), - QObject::tr("WRN_WARNING"), - tr("WRN_DUMP_STUDY_FAILED"), - QObject::tr("BUT_OK") ); + SUIT_MessageBox::warn1 ( desktop(), + QObject::tr("WRN_WARNING"), + tr("WRN_DUMP_STUDY_FAILED"), + QObject::tr("BUT_OK") ); } } @@ -524,6 +579,16 @@ void SalomeApp_Application::onLoadScript( ) } } +/*!Private SLOT. On save GUI state.*/ +void SalomeApp_Application::onSaveGUIState() +{ + SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); + if ( !appStudy ) return; + + SalomeApp_VisualState( this ).storeState(); + updateObjectBrowser( false ); +} + /*!Gets file filter. *\retval QString "(*.hdf)" */ @@ -584,6 +649,11 @@ void SalomeApp_Application::createPreferences( LightApp_Preferences* pref ) LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_%d", i ) ); } pref->setItemProperty( defCols, "columns", 1 ); + + // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources.. + int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat ); + int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab ); + pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" ); } /*!Update desktop title.*/ @@ -691,6 +761,15 @@ void SalomeApp_Application::contextMenuPopup( const QString& type, QPopupMenu* t LightApp_SelectionMgr* mgr = selectionMgr(); mgr->selectedObjects( aList, QString::null, false ); + // add GUI state commands: restore, rename + if ( aList.Extent() == 1 && aList.First()->hasEntry() && + QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) { + thePopup->insertSeparator(); + thePopup->insertItem( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) ); + thePopup->insertItem( tr( "MEN_RENAME_VS" ), this, SLOT( onRenameGUIState() ) ); + thePopup->insertItem( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) ); + } + // "Delete reference" item should appear only for invalid references // isInvalidRefs will be true, if at least one of selected objects is invalid reference @@ -725,6 +804,10 @@ void SalomeApp_Application::contextMenuPopup( const QString& type, QPopupMenu* t if (aList.Extent() != 1) return; Handle(SALOME_InteractiveObject) aIObj = aList.First(); + // check if item is a "GUI state" item (also a first level object) + QString entry( aIObj->getEntry() ); + if ( entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) + return; QString aModuleName(aIObj->getComponentDataType()); QString aModuleTitle = moduleTitle(aModuleName); CAM_Module* currentModule = activeModule(); @@ -733,10 +816,63 @@ void SalomeApp_Application::contextMenuPopup( const QString& type, QPopupMenu* t thePopup->insertItem( tr( "MEN_OPENWITH" ), this, SLOT( onOpenWith() ) ); } +/*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/ +void updateSavePointDataObjects( OB_Browser* ob, SalomeApp_Study* study ) +{ + if ( !study || !ob ) + return; + + // find GUI states root object + SUIT_DataObject* guiRootObj = 0; + DataObjectList ch; + study->root()->children( ch ); + DataObjectList::const_iterator it = ch.begin(), last = ch.end(); + for ( ; it != last ; ++it ) { + if ( dynamic_cast( *it ) ) + guiRootObj = *it; + } + std::vector savePoints = study->getSavePoints(); + // case 1: no more save points but they existed in study's tree + if ( savePoints.empty() && guiRootObj ) { + delete guiRootObj; + return; + } + // case 2: no more save points but root does not exist either + if ( savePoints.empty() && !guiRootObj ) + return; + // case 3: save points but no root for them - create it + if ( !savePoints.empty() && !guiRootObj ) + guiRootObj = new SalomeApp_SavePointRootObject( study->root() ); + // case 4: everything already exists.. nothing to do.. + + // store data objects in a map id-to-DataObject + QMap mapDO; + ch.clear(); + guiRootObj->children( ch ); + for( it = ch.begin(), last = ch.end(); it != last ; ++it ) { + SalomeApp_SavePointObject* dobj = dynamic_cast( *it ); + if ( dobj ) + mapDO[dobj->getId()] = dobj; + } + + // iterate new save points. if DataObject with such ID not found in map - create DataObject + // if in the map - remove it from map. + for ( int i = 0; i < savePoints.size(); i++ ) + if ( !mapDO.contains( savePoints[i] ) ) + new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study ); + else { + ob->updateTree( mapDO[ savePoints[i] ] ); + mapDO.remove( savePoints[i] ); + } + // delete DataObjects that are still in the map -- their IDs were not found in data model + for ( QMap::Iterator it = mapDO.begin(); it != mapDO.end(); ++it ) + delete it.data(); +} + /*!Update obect browser: 1.if 'updateModels' true, update existing data models; 2. update "non-existing" (not loaded yet) data models; - 3. update object browser if it existing */ + 3. update object browser if it exists */ void SalomeApp_Application::updateObjectBrowser( const bool updateModels ) { // update "non-existing" (not loaded yet) data models @@ -761,16 +897,16 @@ void SalomeApp_Application::updateObjectBrowser( const bool updateModels ) //SalomeApp_DataModel::BuildTree( aComponent, study->root(), study, /*skipExisitng=*/true ); } } + // create data objects that correspond to GUI state save points + ::updateSavePointDataObjects( objectBrowser(), study ); } // update existing data models (already loaded SComponents) LightApp_Application::updateObjectBrowser( updateModels ); -/* if ( objectBrowser() ) - { - objectBrowser()->updateGeometry(); - objectBrowser()->updateTree(); - }*/ + // -- debug -- + // if ( study && study->root() ) + // study->root()->dump(); } /*!Display Catalog Genenerator dialog */ @@ -832,3 +968,73 @@ void SalomeApp_Application::onDblClick( QListViewItem* it ) } } } + +SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type) +{ + return createViewManager(type); +} + + +/*!Global utility funciton, returns selected GUI Save point object's ID */ +int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr ) +{ + SALOME_ListIO aList; + selMgr->selectedObjects( aList ); + Handle(SALOME_InteractiveObject) aIObj = aList.First(); + QString entry( aIObj->getEntry() ); + QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" ); + if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object + return -1; + bool ok; // conversion to integer is ok? + int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok ); + return ok ? savePoint : -1; +} + +/*!Called on Restore GUI State popup command*/ +void SalomeApp_Application::onRestoreGUIState() +{ + int savePoint = ::getSelectedSavePoint( selectionMgr() ); + if ( savePoint == -1 ) + return; + SalomeApp_VisualState( this ).restoreState( savePoint ); +} + +/*!Called on Rename GUI State popup command*/ +void SalomeApp_Application::onRenameGUIState() +{ + int savePoint = ::getSelectedSavePoint( selectionMgr() ); + if ( savePoint == -1 ) + return; + SalomeApp_Study* study = dynamic_cast( activeStudy() ); + if ( !study ) + return; + + QString newName = LightApp_NameDlg::getName( desktop(), study->getNameOfSavePoint( savePoint ) ); + if ( !newName.isNull() && !newName.isEmpty() ) { + study->setNameOfSavePoint( savePoint, newName ); + updateSavePointDataObjects( objectBrowser(), study ); + } +} + + +/*!Called on Delete GUI State popup command*/ +void SalomeApp_Application::onDeleteGUIState() +{ + int savePoint = ::getSelectedSavePoint( selectionMgr() ); + if ( savePoint == -1 ) + return; + SalomeApp_Study* study = dynamic_cast( activeStudy() ); + if ( !study ) + return; + + study->removeSavePoint( savePoint ); + updateSavePointDataObjects( objectBrowser(), study ); +} + +/*!Called on Save study operation*/ +void SalomeApp_Application::onStudySaved( SUIT_Study* study ) +{ + updateObjectBrowser( false ); + LightApp_Application::onStudySaved( study ); +} + diff --git a/src/SalomeApp/SalomeApp_Application.h b/src/SalomeApp/SalomeApp_Application.h index 2462e557b..1ea58679e 100644 --- a/src/SalomeApp/SalomeApp_Application.h +++ b/src/SalomeApp/SalomeApp_Application.h @@ -46,7 +46,7 @@ class SALOMEAPP_EXPORT SalomeApp_Application : public LightApp_Application public: enum { DumpStudyId = LightApp_Application::UserID, LoadScriptId, PropertiesId, - CatalogGenId, RegDisplayId, UserID }; + CatalogGenId, RegDisplayId, SaveGUIStateId, UserID }; public: SalomeApp_Application(); @@ -66,6 +66,8 @@ public: static SALOME_LifeCycleCORBA* lcc(); static QString defaultEngineIOR(); + SUIT_ViewManager* newViewManager(const QString&); + public slots: virtual bool onOpenDoc( const QString& ); virtual void onLoadDoc(); @@ -73,6 +75,9 @@ public slots: virtual void onCopy(); virtual void onPaste(); +protected slots: + void onStudySaved( SUIT_Study* ); + protected: virtual void createActions(); virtual SUIT_Study* createNewStudy(); @@ -83,17 +88,21 @@ protected: virtual void createPreferences( LightApp_Preferences* ); virtual void updateDesktopTitle(); - + private slots: void onDeleteInvalidReferences(); void onDblClick( QListViewItem* ); void onProperties(); void onDumpStudy(); void onLoadScript(); + void onSaveGUIState(); + void onDeleteGUIState(); void onCatalogGen(); void onRegDisplay(); void onOpenWith(); + void onRestoreGUIState(); + void onRenameGUIState(); }; #ifdef WIN32 diff --git a/src/SalomeApp/SalomeApp_DataModel.cxx b/src/SalomeApp/SalomeApp_DataModel.cxx index 5fcae7b7b..b31708a57 100644 --- a/src/SalomeApp/SalomeApp_DataModel.cxx +++ b/src/SalomeApp/SalomeApp_DataModel.cxx @@ -285,31 +285,7 @@ SUIT_DataObject* SalomeApp_DataModel::synchronize( const _PTR( SComponent )& sob SalomeApp_DataModelSync sync( study->studyDS(), study->root() ); - // QString srcName = sobj ? sobj->GetName().c_str() : ""; - // QString trgName = ( suitObj && !suitObj->name().isNull() ) ? suitObj->name() : ""; - // printf( "--- SalomeApp_DataModel::syncronize() calls synchronize()_1: src = %s, trg = %s ---\n", srcName.latin1(), trgName.latin1() ); - - SUIT_DataObject* o = ::synchronize( sobj, suitObj, sync ); -// showTree( o ); - return o; -} - -//================================================================ -// Function : synchronize -/*! Purpose : synchronizes kernel tree and suit data tree starting from 'sobj' and 'obj' correspondly */ -//================================================================ -SUIT_DataObject* SalomeApp_DataModel::synchronize( const _PTR( SObject )& sobj, SUIT_DataObject* obj, - SalomeApp_Study* study ) -{ - if( !study ) - return 0; - SalomeApp_DataModelSync sync( study->studyDS(), study->root() ); - - // QString srcName = sobj ? sobj->GetName().c_str() : ""; - // QString trgName = ( obj && !obj->name().isNull() ) ? obj->name() : ""; - // printf( "--- SalomeApp_DataModel::syncronize() calls synchronize()_2: src = s, trg = %s ---\n", srcName.latin1(), trgName.latin1() ); - - return ::synchronize( sobj, obj, sync ); + return ::synchronize( sobj, suitObj, sync ); } //================================================================ diff --git a/src/SalomeApp/SalomeApp_DataModel.h b/src/SalomeApp/SalomeApp_DataModel.h index 62e649bc3..7452cd366 100644 --- a/src/SalomeApp/SalomeApp_DataModel.h +++ b/src/SalomeApp/SalomeApp_DataModel.h @@ -27,10 +27,9 @@ class SALOMEAPP_EXPORT SalomeApp_DataModel : public LightApp_DataModel public: static SUIT_DataObject* synchronize( const _PTR( SComponent )&, SalomeApp_Study* ); - static SUIT_DataObject* synchronize( const _PTR( SObject )&, SUIT_DataObject*, SalomeApp_Study* ); - SalomeApp_DataModel ( CAM_Module* theModule ); - virtual ~SalomeApp_DataModel(); + SalomeApp_DataModel ( CAM_Module* theModule ); + virtual ~SalomeApp_DataModel(); virtual bool open( const QString&, CAM_Study*, QStringList ); virtual bool create( CAM_Study* ); diff --git a/src/SalomeApp/SalomeApp_DataObject.cxx b/src/SalomeApp/SalomeApp_DataObject.cxx index ef7b8df7b..5bb857865 100644 --- a/src/SalomeApp/SalomeApp_DataObject.cxx +++ b/src/SalomeApp/SalomeApp_DataObject.cxx @@ -21,6 +21,8 @@ #include "SalomeApp_Study.h" #include "LightApp_RootObject.h" +#include + #include #include #include @@ -371,3 +373,50 @@ QString SalomeApp_ModuleObject::name() const return SalomeApp_DataObject::name(); } +/* + Class: SalomeApp_SavePointObject + Level: Public +*/ + +/*!Constructor.Initialize by \a parent.*/ +SalomeApp_SavePointObject::SalomeApp_SavePointObject( SUIT_DataObject* _parent, const int id, SalomeApp_Study* study ) + : LightApp_DataObject( _parent ), CAM_DataObject( _parent ), // IMPORTANT TO CALL ALL VIRTUAL CONSTRUCTORS! + myId( id ), + myStudy( study ) +{ +} + +/*!Destructor. Do nothing.*/ +SalomeApp_SavePointObject::~SalomeApp_SavePointObject() +{ +} + +/*!Returns save points ID */ +int SalomeApp_SavePointObject::getId() const +{ + return myId; +} + +/*!Returns "invalid" entry, which does not correspond to any object in data structure + but indicates that it is a save point object */ +QString SalomeApp_SavePointObject::entry() const +{ + return QObject::tr( "SAVE_POINT_DEF_NAME" ) + QString::number( myId ); +} + +/*!Returns displayed name of object */ +QString SalomeApp_SavePointObject::name() const +{ + return myStudy->getNameOfSavePoint( myId ); +} + +QPixmap SalomeApp_SavePointObject::icon() const +{ + return QPixmap(); +} + +QString SalomeApp_SavePointObject::toolTip() const +{ + return QObject::tr( "SAVE_POINT_OBJECT_TOOLTIP" ).arg( name() ); +} + diff --git a/src/SalomeApp/SalomeApp_DataObject.h b/src/SalomeApp/SalomeApp_DataObject.h index 15a1d96bf..33cf78d67 100644 --- a/src/SalomeApp/SalomeApp_DataObject.h +++ b/src/SalomeApp/SalomeApp_DataObject.h @@ -82,7 +82,45 @@ public: SalomeApp_ModuleObject( CAM_DataModel*, const _PTR(SObject)&, SUIT_DataObject* = 0 ); virtual ~SalomeApp_ModuleObject(); - virtual QString name() const; + virtual QString name() const; +}; + +/*! + * SalomeApp_SavePointObject - class that represents persistent visual_state object + * these objects are stored in data model, but NOT in SObjects structure, so we + * must handle them separately using this special class for them + */ + +class SALOMEAPP_EXPORT SalomeApp_SavePointObject : public virtual LightApp_DataObject +{ +public: + SalomeApp_SavePointObject( SUIT_DataObject* parent, const int, SalomeApp_Study* study ); + virtual ~SalomeApp_SavePointObject(); + + virtual QString entry() const; + + virtual QString name() const; + virtual QPixmap icon() const; + virtual QString toolTip() const; + + int getId() const; + +private: + int myId; + SalomeApp_Study* myStudy; +}; + +/*! + * SalomeApp_SavePointRootObject - class that represents parent object for visual_state objects + */ + +class SALOMEAPP_EXPORT SalomeApp_SavePointRootObject : public SUIT_DataObject +{ +public: + SalomeApp_SavePointRootObject( SUIT_DataObject* parent ) : SUIT_DataObject( parent ) {} + + virtual QString name() const { return QObject::tr( "SAVE_POINT_ROOT_NAME" ); } + virtual QString toolTip() const{ return QObject::tr( "SAVE_POINT_ROOT_TOOLTIP" ); } }; #endif diff --git a/src/SalomeApp/SalomeApp_Module.cxx b/src/SalomeApp/SalomeApp_Module.cxx index 9284a5792..b22992cf4 100644 --- a/src/SalomeApp/SalomeApp_Module.cxx +++ b/src/SalomeApp/SalomeApp_Module.cxx @@ -11,6 +11,7 @@ #include "LightApp_Selection.h" #include "LightApp_Operation.h" #include "LightApp_Preferences.h" +//#include "LightApp_Displayer.h" #include "CAM_DataModel.h" @@ -19,12 +20,24 @@ #include #include #include +//#include + +//#include "SALOMEDS_IParameters.hxx" #include +#include + +#include +//#include +//#include +//#include #include #include +//#include +//#include + /*!Constructor.*/ SalomeApp_Module::SalomeApp_Module( const QString& name ) : LightApp_Module( name ) @@ -97,3 +110,24 @@ void SalomeApp_Module::extractContainers( const SALOME_ListIO& source, SALOME_Li dest.Append( obj ); } } + +/*! + * \brief Virtual public + * + * This method is called just before the study document is saved, so the module has a possibility + * to store visual parameters in AttributeParameter attribue(s) + */ +void SalomeApp_Module::storeVisualParameters(int savePoint) +{ +} + +/*! + * \brief Virtual public + * + * This method is called after the study document is opened, so the module has a possibility to restore + * visual parameters + */ +void SalomeApp_Module::restoreVisualParameters(int savePoint) +{ +} + diff --git a/src/SalomeApp/SalomeApp_Module.h b/src/SalomeApp/SalomeApp_Module.h index 433d918fd..7346e8537 100644 --- a/src/SalomeApp/SalomeApp_Module.h +++ b/src/SalomeApp/SalomeApp_Module.h @@ -10,8 +10,6 @@ #include -#include - class CAM_DataModel; class SalomeApp_Application; class LightApp_Operation; @@ -41,6 +39,9 @@ public: SalomeApp_Application* getApp() const; + virtual void storeVisualParameters(int savePoint); + virtual void restoreVisualParameters(int savePoint); + protected: virtual CAM_DataModel* createDataModel(); virtual LightApp_Selection* createSelection() const; diff --git a/src/SalomeApp/SalomeApp_Study.cxx b/src/SalomeApp/SalomeApp_Study.cxx index f3de08660..3a41ac01a 100644 --- a/src/SalomeApp/SalomeApp_Study.cxx +++ b/src/SalomeApp/SalomeApp_Study.cxx @@ -23,6 +23,7 @@ #include "SalomeApp_DataObject.h" #include "SalomeApp_Application.h" #include "SalomeApp_Engine_i.hxx" +#include "SalomeApp_VisualState.h" #include "LightApp_RootObject.h" @@ -31,16 +32,25 @@ #include #include +#include +#include #include "utilities.h" -#include "string.h" -#include "vector.h" +#include +#include +#include + +#include #include "SALOMEDS_Tool.hxx" +#include "SALOMEDS_IParameters.hxx" + #include #include CORBA_SERVER_HEADER(SALOME_Exception) +using namespace std; + /*! Constructor. */ @@ -130,6 +140,14 @@ bool SalomeApp_Study::openDocument( const QString& theFileName ) emit opened( this ); study->IsSaved(true); + + bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true ); + if ( restore ) { + std::vector savePoints = getSavePoints(); + if ( savePoints.size() > 0 ) + SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] ); + } + return res; } @@ -167,6 +185,13 @@ bool SalomeApp_Study::loadDocument( const QString& theStudyName ) bool res = CAM_Study::openDocument( theStudyName ); emit opened( this ); + bool restore = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true ); + if ( restore ) { + std::vector savePoints = getSavePoints(); + if ( savePoints.size() > 0 ) + SalomeApp_VisualState( (SalomeApp_Application*)application() ).restoreState( savePoints[savePoints.size()-1] ); + } + //SRN: BugID IPAL9021: End return res; @@ -178,6 +203,10 @@ bool SalomeApp_Study::loadDocument( const QString& theStudyName ) //======================================================================= bool SalomeApp_Study::saveDocumentAs( const QString& theFileName ) { + bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true ); + if ( store ) + SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState(); + ModelList list; dataModels( list ); SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first(); @@ -214,6 +243,10 @@ bool SalomeApp_Study::saveDocumentAs( const QString& theFileName ) //======================================================================= bool SalomeApp_Study::saveDocument() { + bool store = application()->resourceMgr()->booleanValue( "Study", "store_visual_state", true ); + if ( store ) + SalomeApp_VisualState( (SalomeApp_Application*)application() ).storeState(); + ModelList list; dataModels( list ); SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first(); @@ -221,7 +254,7 @@ bool SalomeApp_Study::saveDocument() for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() ) { listOfFiles.clear(); aModel->save(listOfFiles); - if ( !listOfFiles.isEmpty() ) + if ( !listOfFiles.isEmpty() ) saveModuleData(aModel->module()->name(), listOfFiles); } @@ -629,3 +662,77 @@ void SalomeApp_Study::components( QStringList& comps ) const comps.append( aComponent->ComponentDataType().c_str() ); } } + +//================================================================ +// Function : getSavePoints +/*! Purpose : returns a list of saved points' IDs +*/ +//================================================================ +std::vector SalomeApp_Study::getSavePoints() +{ + std::vector v; + + _PTR(SObject) so = studyDS()->FindComponent("Interface Applicative"); + if(!so) return v; + + _PTR(StudyBuilder) builder = studyDS()->NewBuilder(); + _PTR(ChildIterator) anIter ( studyDS()->NewChildIterator( so ) ); + for(; anIter->More(); anIter->Next()) + { + _PTR(SObject) val( anIter->Value() ); + _PTR(GenericAttribute) genAttr; + if(builder->FindAttribute(val, genAttr, "AttributeParameter")) v.push_back(val->Tag()); + } + + return v; +} + +//================================================================ +// Function :removeSavePoint +/*! Purpose : remove a given save point +*/ +//================================================================ +void SalomeApp_Study::removeSavePoint(int savePoint) +{ + if(savePoint <= 0) return; + _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint); + _PTR(SObject) so = AP->GetSObject(); + _PTR(StudyBuilder) builder = studyDS()->NewBuilder(); + builder->RemoveObjectWithChildren(so); +} + +//================================================================ +// Function : getNameOfSavePoint +/*! Purpose : returns a name of save point +*/ +//================================================================ +QString SalomeApp_Study::getNameOfSavePoint(int savePoint) +{ + _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint); + SALOMEDS_IParameters ip(AP); + return ip.getProperty("AP_SAVEPOINT_NAME"); +} + +//================================================================ +// Function : setNameOfSavePoint +/*! Purpose : sets a name of save point +*/ +//================================================================ +void SalomeApp_Study::setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint) +{ + _PTR(AttributeParameter) AP = studyDS()->GetCommonParameters(getVisualComponentName(), savePoint); + SALOMEDS_IParameters ip(AP); + ip.setProperty("AP_SAVEPOINT_NAME", nameOfSavePoint.latin1()); +} + +//================================================================ +// Function : getVisualComponentName +/*! Purpose : returns a name of the component where visual + * parameters are stored +*/ +//================================================================ +std::string SalomeApp_Study::getVisualComponentName() +{ + return "Interface Applicative"; +} + diff --git a/src/SalomeApp/SalomeApp_Study.h b/src/SalomeApp/SalomeApp_Study.h index c07d20528..b3edd2564 100644 --- a/src/SalomeApp/SalomeApp_Study.h +++ b/src/SalomeApp/SalomeApp_Study.h @@ -22,6 +22,7 @@ #include "SalomeApp.h" #include +#include #ifdef WIN32 #pragma warning( disable:4251 ) @@ -66,6 +67,12 @@ public: virtual void children( const QString&, QStringList& ) const; virtual void components( QStringList& ) const; + std::vector getSavePoints(); + void removeSavePoint(int savePoint); + QString getNameOfSavePoint(int savePoint); + void setNameOfSavePoint(int savePoint, const QString& nameOfSavePoint); + virtual std::string getVisualComponentName(); + protected: virtual void saveModuleData ( QString theModuleName, QStringList theListOfFiles ); virtual void openModuleData ( QString theModuleName, QStringList& theListOfFiles ); diff --git a/src/SalomeApp/SalomeApp_VisualState.cxx b/src/SalomeApp/SalomeApp_VisualState.cxx new file mode 100644 index 000000000..ff00dbc88 --- /dev/null +++ b/src/SalomeApp/SalomeApp_VisualState.cxx @@ -0,0 +1,295 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ +// +#include "SalomeApp_VisualState.h" + +#include "SalomeApp_Module.h" +#include "SalomeApp_Study.h" +#include "SalomeApp_Application.h" + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +/*! + Constructor. +*/ +SalomeApp_VisualState::SalomeApp_VisualState( SalomeApp_Application* app ) + : myApp( app ) +{ +} + +/*! + Destructor. +*/ +SalomeApp_VisualState::~SalomeApp_VisualState() +{ +} + +//================================================================ +// Function : nameViewWindows +/*! Purpose : set 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! +// Naming rule: ViewerType_IndexOfViewerOfThisType_IndexOfViewInThisViewer +// VTKViewer_0_0 +// OCCViewer_0_0 OCCViewer_0_1 OCCViewer_0_2 +// VTKViewer_1_0 +*/ +//================================================================ +void nameViewWindows( const ViewManagerList& lst ) +{ + QDict viewersCounter; // map viewerType - to - index_of_this_viewer_type + viewersCounter.setAutoDelete( true ); + for ( QPtrListIterator it(lst); it.current(); ++it) { + int view_count = it.current()->getViewsCount(); + QString vType = it.current()->getType(); + if ( !view_count ) + continue; //No views is opened in the viewer + + int* viewerID = viewersCounter[ vType ]; + if ( !viewerID ) { + viewerID = new int( 0 ); + viewersCounter.insert( vType, viewerID ); + } + else + ++(*viewerID); + + QPtrVector views = it.current()->getViews(); + for ( int i = 0; i < view_count; i++ ) { + QString vName = QString( "%1_%2_%3" ).arg( vType ).arg( *viewerID ).arg( i ); + views[i]->setName( vName ); + } + } +} + +//================================================================ +// Function : storeState +/*! Purpose : store the visual parameters of the viewers +*/ +//================================================================ +int SalomeApp_VisualState::storeState() +{ + SalomeApp_Study* study = dynamic_cast( myApp->activeStudy() ); + if ( !study ) + return -1; + + int savePoint = 1; + std::vector savePoints = study->getSavePoints(); + //Calculate a new savePoint number = the last save point number + 1 + if ( savePoints.size() > 0) + savePoint = savePoints[savePoints.size()-1] + 1; + + _PTR(AttributeParameter) ap = study->studyDS()->GetCommonParameters( study->getVisualComponentName(), savePoint ); + SALOMEDS_IParameters ip( ap ); + + ViewManagerList lst; + myApp->viewManagers( lst ); + + // 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(); + if ( win ) + ip.setProperty("AP_ACTIVE_VIEW", win->name() ); + + int viewerID = 0; + SUIT_ViewManager* vm = 0; + for (QPtrListIterator it( lst ); it.current(); ++it ) { + vm = it.current(); + int view_count = vm->getViewsCount(); + if ( !view_count ) + continue; //No views is opened in the viewer + + std::string viewerEntry = QString( "%1_%2" ).arg( vm->getType() ).arg( ++viewerID ).latin1(); + ip.append("AP_VIEWERS_LIST", viewerEntry); + + QPtrVector views = vm->getViews(); + for(int i = 0; icaption() ); + ip.append( viewerEntry, views[i]->getVisualParameters().latin1() ); + } + } + + //Save information about split areas + if ( myApp->desktop()->inherits( "STD_TabDesktop" ) ) { + QtxWorkstack* workstack = ((STD_TabDesktop*)myApp->desktop())->workstack(); + QString workstackInfo; + (*workstack) >> workstackInfo; + ip.setProperty( "AP_WORKSTACK_INFO", workstackInfo.latin1() ); + } + + //Save a name of the active module + if ( CAM_Module* activeModule = myApp->activeModule() ) + ip.setProperty( "AP_ACTIVE_MODULE", activeModule->moduleName().latin1() ); + + //Store visual parameters of the modules + QPtrList mlist; + myApp->modules( mlist ); + CAM_Module* module = 0; + for ( module = mlist.first(); module; module = mlist.next() ) { + if ( SalomeApp_Module* sModule = dynamic_cast( module ) ) { + ip.append( "AP_MODULES_LIST", sModule->moduleName().latin1() ); + sModule->storeVisualParameters( savePoint ); + } + } + + // set default name of new savePoint + study->setNameOfSavePoint( savePoint, QObject::tr( "SAVE_POINT_DEF_NAME" ) + QString::number( savePoint ) ); + + return savePoint; +} + +//================================================================ +// Function : restoreState +/*! Purpose : restore the visual parameters of the viewers +*/ +//================================================================ +void SalomeApp_VisualState::restoreState(int savePoint) +{ + SalomeApp_Study* study = dynamic_cast( myApp->activeStudy() ); + if ( !study ) + return; + + _PTR(AttributeParameter) ap = study->studyDS()->GetCommonParameters( study->getVisualComponentName(), savePoint ); + SALOMEDS_IParameters ip(ap); + + //Remove all already existent veiwers and their views + ViewManagerList lst; + myApp->viewManagers( lst ); + for ( QPtrListIterator it(lst); it.current(); ++it ) + myApp->removeViewManager( it.current() ); + + //Restore the viewers and view windows + int nbViewers = ip.nbValues( "AP_VIEWERS_LIST" ); + SUIT_ViewWindow* viewWin = 0; + + 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 ) + 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++ ) { + SUIT_ViewWindow* aView = vm->createViewWindow(); + aView->show(); + } + + int viewCount = vm->getViewsCount(); + 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. + QPtrVector views = vm->getViews(); + for (int i = 0, j = 0; iisVisible() ) + qApp->processEvents(); + + viewWin->setCaption(ip.getValue(viewerEntry, j).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++ ) { + myApp->activateModule( v[i].c_str() ); + if ( SalomeApp_Module* module = dynamic_cast( myApp->activeModule() ) ) + module->restoreVisualParameters( savePoint ); + } + + // activate module that was active on save + QString activeModuleName( ip.getProperty("AP_ACTIVE_MODULE" ).c_str() ); + 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, + // so the same views will get the same names. + lst.clear(); + myApp->viewManagers(lst); + nameViewWindows( lst ); + + // work-around to bug of setting visual parameters of views: all view windows now have + // correct visual parameters, bug after restoring the workstack the visual parameters + // are messted, and must be re-set again. So here we store them in a map and set them + // later back again. why we don't store these parameters in a map on views creation? + // because 1) names of view windows are not set at that time 2) some view windows + // are created by modules' restoreVisualParameters (like Gauss Viewers), which is NOT here.. + QMap viewersParameters; + QPtrListIterator it( lst ); + for ( ; it.current(); ++it ) { + int view_count = it.current()->getViewsCount(); + QPtrVector views = it.current()->getViews(); + for ( int i = 0; i < view_count; i++ ) + viewersParameters[ views[i]->name() ] = views[i]->getVisualParameters(); + } + + // 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" ) ) { + QtxWorkstack* workstack = ((STD_TabDesktop*)myApp->desktop())->workstack(); + (*workstack) << ip.getProperty( "AP_WORKSTACK_INFO" ).c_str(); + } + + // restore visual parameters of view windows. it must be done AFTER restoring workstack. + for ( it.toFirst(); it.current(); ++it ) { + int view_count = it.current()->getViewsCount(); + QPtrVector views = it.current()->getViews(); + for ( int i = 0; i < view_count; i++ ) + views[i]->setVisualParameters( viewersParameters[ views[i]->name() ] ); + } + + // set focus to previously saved active view window + std::string activeViewName = ip.getProperty("AP_ACTIVE_VIEW"); + for ( it.toFirst(); it.current(); ++it ) { + int view_count = it.current()->getViewsCount(); + QPtrVector views = it.current()->getViews(); + for ( int i = 0; i < view_count; i++ ) { + if ( activeViewName == views[i]->name() ) + views[i]->setFocus(); + } + } +} diff --git a/src/SalomeApp/SalomeApp_VisualState.h b/src/SalomeApp/SalomeApp_VisualState.h new file mode 100644 index 000000000..aa96a8383 --- /dev/null +++ b/src/SalomeApp/SalomeApp_VisualState.h @@ -0,0 +1,47 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ +// +#ifndef SALOMEAPP_VISUALSTATE_H +#define SALOMEAPP_VISUALSTATE_H + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +#include "SalomeApp.h" + +class SalomeApp_Application; + +class SALOMEAPP_EXPORT SalomeApp_VisualState +{ +public: + SalomeApp_VisualState( SalomeApp_Application* ); + virtual ~SalomeApp_VisualState(); + + virtual int storeState(); + virtual void restoreState( int savePoint ); + +protected: + SalomeApp_Application* myApp; +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/SalomeApp/resources/SalomeApp.xml b/src/SalomeApp/resources/SalomeApp.xml index 1d965463b..3fa77b587 100644 --- a/src/SalomeApp/resources/SalomeApp.xml +++ b/src/SalomeApp/resources/SalomeApp.xml @@ -59,7 +59,8 @@
- + +
diff --git a/src/SalomeApp/resources/SalomeApp_msg_en.po b/src/SalomeApp/resources/SalomeApp_msg_en.po index a739779d2..0e484c4e9 100644 --- a/src/SalomeApp/resources/SalomeApp_msg_en.po +++ b/src/SalomeApp/resources/SalomeApp_msg_en.po @@ -42,6 +42,15 @@ msgstr "&Dump study..." msgid "SalomeApp_Application::PRP_DESK_FILE_DUMP_STUDY" msgstr "Dumps study to the python script" +msgid "SalomeApp_Application::TOT_DESK_FILE_SAVE_GUI_STATE" +msgstr "Save GUI state" + +msgid "SalomeApp_Application::MEN_DESK_FILE_SAVE_GUI_STATE" +msgstr "Save GUI state..." + +msgid "SalomeApp_Application::PRP_DESK_FILE_SAVE_GUI_STATE" +msgstr "Saves current state of viewers, displayed objects, etc." + msgid "SalomeApp_Application::TOT_DESK_FILE_LOAD_SCRIPT" msgstr "Load python script" @@ -102,6 +111,17 @@ msgstr "Activate Module" msgid "SalomeApp_Application::MEN_DELETE_INVALID_REFERENCE" msgstr "Delete Invalid Reference" +msgid "SalomeApp_Application::PREF_STORE_VISUAL_STATE" +msgstr "Store/restore last GUI state" + +//======================================================================================= + +msgid "PUBLISH_IN_STUDY" +msgstr "Publish in study" + +msgid "SAVE_GUI_STATE" +msgstr "Save GUI state" + //======================================================================================= msgid "SalomeApp_Application::MEN_WINDOWS_NEW" @@ -190,3 +210,25 @@ msgstr "Publish in study" msgid "SalomeApp_Application::WRN_DUMP_STUDY_FAILED" msgstr "Dump study failed" +msgid "SAVE_POINT_OBJECT_TOOLTIP" +msgstr "Saved GUI state: %1" + +msgid "SAVE_POINT_DEF_NAME" +msgstr "GUI state: " + +msgid "SAVE_POINT_ROOT_TOOLTIP" +msgstr "Persistent GUI states" + +msgid "SAVE_POINT_ROOT_NAME" +msgstr "GUI states" + +//======================================================================================= + +msgid "SalomeApp_Application::MEN_RESTORE_VS" +msgstr "Restore" + +msgid "SalomeApp_Application::MEN_RENAME_VS" +msgstr "Rename" + +msgid "SalomeApp_Application::MEN_DELETE_VS" +msgstr "Delete" diff --git a/src/Session/Session_Session_i.cxx b/src/Session/Session_Session_i.cxx index 41869b4d3..1a9662eea 100755 --- a/src/Session/Session_Session_i.cxx +++ b/src/Session/Session_Session_i.cxx @@ -213,3 +213,27 @@ CORBA::Long SALOME_Session_i::GetActiveStudyId() } return aStudyId; } + +bool SALOME_Session_i::restoreVisualState(CORBA::Long theSavePoint) +{ + class TEvent: public SALOME_Event { + int _savePoint; + public: + TEvent(int savePoint) { _savePoint = savePoint; } + virtual void Execute() { + SUIT_Study* study = SUIT_Session::session()->activeApplication()->activeStudy(); + if ( study ) { + study->restoreState(_savePoint); + } + } + }; + + if(SUIT_Session::session() && SUIT_Session::session()->activeApplication() ) { + SUIT_Study* study = SUIT_Session::session()->activeApplication()->activeStudy(); + if(!study) SUIT_Session::session()->activeApplication()->createEmptyStudy(); + ProcessVoidEvent( new TEvent(theSavePoint) ); + return true; + } + + return false; +} diff --git a/src/Session/Session_Session_i.hxx b/src/Session/Session_Session_i.hxx index c9815a42d..6a7f40361 100755 --- a/src/Session/Session_Session_i.hxx +++ b/src/Session/Session_Session_i.hxx @@ -67,6 +67,9 @@ public: void ping(){}; + //! Restors a visual state of the study at theSavePoint + bool restoreVisualState(CORBA::Long theSavePoint); + protected: //! Naming service interface diff --git a/src/VTKViewer/VTKViewer_ViewWindow.cxx b/src/VTKViewer/VTKViewer_ViewWindow.cxx index d4500095a..144590803 100755 --- a/src/VTKViewer/VTKViewer_ViewWindow.cxx +++ b/src/VTKViewer/VTKViewer_ViewWindow.cxx @@ -559,3 +559,54 @@ QImage VTKViewer_ViewWindow::dumpView() QPixmap px = QPixmap::grabWindow( myRenderWindow->winId() ); return px.convertToImage(); } + +/*! The method returns the visual parameters of this view as a formated string + */ +QString VTKViewer_ViewWindow::getVisualParameters() +{ + double pos[3], focalPnt[3], viewUp[3], parScale, scale[3]; + + vtkCamera* camera = myRenderer->GetActiveCamera(); + camera->GetPosition( pos ); + camera->GetFocalPoint( focalPnt ); + camera->GetViewUp( viewUp ); + parScale = camera->GetParallelScale(); + GetScale( scale ); + + QString retStr; + retStr.sprintf( "%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e*%.12e", + pos[0], pos[1], pos[2], focalPnt[0], focalPnt[1], focalPnt[2], viewUp[0], viewUp[1], + viewUp[2], parScale, scale[0], scale[1], scale[2] ); + return retStr; +} + +/* The method restors visual parameters of this view from a formated string + */ +void VTKViewer_ViewWindow::setVisualParameters( const QString& parameters ) +{ + QStringList paramsLst = QStringList::split( '*', parameters, true ); + if ( paramsLst.size() == 13 ) { + double pos[3], focalPnt[3], viewUp[3], parScale, scale[3]; + pos[0] = paramsLst[0].toDouble(); + pos[1] = paramsLst[1].toDouble(); + pos[2] = paramsLst[2].toDouble(); + focalPnt[0] = paramsLst[3].toDouble(); + focalPnt[1] = paramsLst[4].toDouble(); + focalPnt[2] = paramsLst[5].toDouble(); + viewUp[0] = paramsLst[6].toDouble(); + viewUp[1] = paramsLst[7].toDouble(); + viewUp[2] = paramsLst[8].toDouble(); + parScale = paramsLst[9].toDouble(); + scale[0] = paramsLst[10].toDouble(); + scale[1] = paramsLst[11].toDouble(); + scale[2] = paramsLst[12].toDouble(); + + vtkCamera* camera = myRenderer->GetActiveCamera(); + camera->SetPosition( pos ); + camera->SetFocalPoint( focalPnt ); + camera->SetViewUp( viewUp ); + camera->SetParallelScale( parScale ); + myTransform->SetMatrixScale( scale[0], scale[1], scale[2] ); + myRWInteractor->Render(); + } +} diff --git a/src/VTKViewer/VTKViewer_ViewWindow.h b/src/VTKViewer/VTKViewer_ViewWindow.h index 951d96d4c..5c02b79a6 100755 --- a/src/VTKViewer/VTKViewer_ViewWindow.h +++ b/src/VTKViewer/VTKViewer_ViewWindow.h @@ -70,6 +70,9 @@ public: void AddActor( VTKViewer_Actor*, bool update = false ); void RemoveActor( VTKViewer_Actor*, bool update = false); + virtual QString getVisualParameters(); + virtual void setVisualParameters( const QString& parameters ); + public slots: void onFrontView(); void onBackView(); -- 2.39.2