From 2ffbafb3376a9fcbf823ac17b4f31ebccc403323 Mon Sep 17 00:00:00 2001 From: ouv Date: Wed, 28 Jan 2009 16:28:49 +0000 Subject: [PATCH] Merge from BR_DumpPython_Extension branch (from tag mergeto_BR_V5_Dev_28Jan09) --- doc/salome/gui/images/notebook1.png | Bin 0 -> 16052 bytes doc/salome/gui/images/studymanagement.png | Bin 6707 -> 13062 bytes .../gui/input/study_management_chapter.doc | 2 + doc/salome/gui/input/using_notebook.doc | 26 + src/SalomeApp/Makefile.am | 15 +- src/SalomeApp/SalomeApp_Application.cxx | 49 +- src/SalomeApp/SalomeApp_Application.h | 10 +- src/SalomeApp/SalomeApp_DataObject.cxx | 40 +- src/SalomeApp/SalomeApp_DoubleSpinBox.cxx | 352 ++++++ src/SalomeApp/SalomeApp_DoubleSpinBox.h | 91 ++ src/SalomeApp/SalomeApp_IntSpinBox.cxx | 310 +++++ src/SalomeApp/SalomeApp_IntSpinBox.h | 85 ++ src/SalomeApp/SalomeApp_NoteBookDlg.cxx | 1082 +++++++++++++++++ src/SalomeApp/SalomeApp_NoteBookDlg.h | 172 +++ src/SalomeApp/SalomeApp_Study.cxx | 10 + src/SalomeApp/SalomeApp_Study.h | 1 + src/SalomeApp/resources/SalomeApp_msg_en.ts | 97 ++ 17 files changed, 2336 insertions(+), 6 deletions(-) create mode 100644 doc/salome/gui/images/notebook1.png create mode 100644 doc/salome/gui/input/using_notebook.doc create mode 100644 src/SalomeApp/SalomeApp_DoubleSpinBox.cxx create mode 100644 src/SalomeApp/SalomeApp_DoubleSpinBox.h create mode 100644 src/SalomeApp/SalomeApp_IntSpinBox.cxx create mode 100644 src/SalomeApp/SalomeApp_IntSpinBox.h create mode 100644 src/SalomeApp/SalomeApp_NoteBookDlg.cxx create mode 100644 src/SalomeApp/SalomeApp_NoteBookDlg.h diff --git a/doc/salome/gui/images/notebook1.png b/doc/salome/gui/images/notebook1.png new file mode 100644 index 0000000000000000000000000000000000000000..a984085ccb940b9d800093b5d0c9411e5cf273e7 GIT binary patch literal 16052 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 To confirm your choice click \b Save. +Notebook - allows to manage study variables using \subpage using_notebook "NoteBook". + Load Script - allows to load a saved Python Script. \image html loadscript.png diff --git a/doc/salome/gui/input/using_notebook.doc b/doc/salome/gui/input/using_notebook.doc new file mode 100644 index 000000000..d48fe8fcb --- /dev/null +++ b/doc/salome/gui/input/using_notebook.doc @@ -0,0 +1,26 @@ +/*! + +\page using_notebook Using NoteBook + +SALOME NoteBook is destined for managing numerical and boolean +parameters (variables) which are used to create and modify objects in +different components. + +To open the NoteBook choose File > Notebook, the following +dialog box will appear: + +\image html notebook1.png + +Here you can add new variables, remove and rename existing variables and +change their values. + +If you have modified some variables, which are already used in the current +study, you should click Update Study button to apply your changes +to the study. + +\note The dialog will not be validated until at least one of variables in +the table has invalid name or value (marked by red color). Names of +variables should be unique and their values should be numerical (integer or +double) or boolean ("True" / "False"). + +*/ \ No newline at end of file diff --git a/src/SalomeApp/Makefile.am b/src/SalomeApp/Makefile.am index 5c599a38d..cd4a634ea 100755 --- a/src/SalomeApp/Makefile.am +++ b/src/SalomeApp/Makefile.am @@ -51,7 +51,10 @@ salomeinclude_HEADERS = \ SalomeApp_StudyPropertiesDlg.h \ SalomeApp_CheckFileDlg.h \ SalomeApp_VisualState.h \ - SalomeApp_ExitDlg.h + SalomeApp_ExitDlg.h \ + SalomeApp_NoteBookDlg.h \ + SalomeApp_DoubleSpinBox.h \ + SalomeApp_IntSpinBox.h dist_libSalomeApp_la_SOURCES = \ SalomeApp_Module.cxx \ @@ -70,7 +73,10 @@ dist_libSalomeApp_la_SOURCES = \ SalomeApp_ListView.cxx \ SalomeApp_CheckFileDlg.cxx \ SalomeApp_VisualState.cxx \ - SalomeApp_ExitDlg.cxx + SalomeApp_ExitDlg.cxx \ + SalomeApp_NoteBookDlg.cxx \ + SalomeApp_DoubleSpinBox.cxx \ + SalomeApp_IntSpinBox.cxx MOC_FILES = \ SalomeApp_Application_moc.cxx \ @@ -81,7 +87,10 @@ MOC_FILES = \ SalomeApp_StudyPropertiesDlg_moc.cxx \ SalomeApp_ListView_moc.cxx \ SalomeApp_CheckFileDlg_moc.cxx \ - SalomeApp_ExitDlg_moc.cxx + SalomeApp_ExitDlg_moc.cxx \ + SalomeApp_NoteBookDlg_moc.cxx \ + SalomeApp_DoubleSpinBox_moc.cxx \ + SalomeApp_IntSpinBox_moc.cxx nodist_libSalomeApp_la_SOURCES = $(MOC_FILES) diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index 35623a149..2c66cbdd7 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -31,6 +31,8 @@ #include "SalomeApp_VisualState.h" #include "SalomeApp_StudyPropertiesDlg.h" #include "SalomeApp_LoadStudiesDlg.h" +#include "SalomeApp_NoteBookDlg.h" + #include "SalomeApp_ExitDlg.h" #include @@ -137,10 +139,11 @@ extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication() /*!Constructor.*/ SalomeApp_Application::SalomeApp_Application() -: LightApp_Application() + : LightApp_Application() { connect( desktop(), SIGNAL( message( const QString& ) ), this, SLOT( onDesktopMessage( const QString& ) ) ); + setNoteBook(0); } /*!Destructor. @@ -238,6 +241,11 @@ void SalomeApp_Application::createActions() tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ), Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) ); + //! NoteBook + createAction(NoteBookId, tr( "TOT_DESK_FILE_NOTEBOOK" ), QIcon(), + tr( "MEN_DESK_FILE_NOTEBOOK" ), tr( "PRP_DESK_FILE_NOTEBOOK" ), + Qt::CTRL+Qt::Key_K, desk, false, this, SLOT(onNoteBook())); + //! Load script createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(), tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ), @@ -275,6 +283,7 @@ void SalomeApp_Application::createActions() createMenu( FileLoadId, fileMenu, 0 ); //SRN: BugID IPAL9021, add a menu item "Load" createMenu( DumpStudyId, fileMenu, 10, -1 ); + createMenu( NoteBookId, fileMenu, 10, -1 ); createMenu( separator(), fileMenu, -1, 10, -1 ); createMenu( LoadScriptId, fileMenu, 10, -1 ); createMenu( separator(), fileMenu, -1, 10, -1 ); @@ -470,6 +479,8 @@ void SalomeApp_Application::onCloseDoc( bool ask ) } LightApp_Application::onCloseDoc( ask ); + if(myNoteBook && myNoteBook->isVisible()) + myNoteBook->hide(); } /*!Sets enable or disable some actions on selection changed.*/ @@ -579,6 +590,11 @@ void SalomeApp_Application::updateCommandsStatus() if ( a ) a->setEnabled( activeStudy() ); + // Note Book + a = action(NoteBookId); + if( a ) + a->setEnabled( activeStudy() ); + // Load script menu a = action( LoadScriptId ); if ( a ) @@ -704,6 +720,25 @@ void SalomeApp_Application::onDumpStudy( ) } } +/*!Private SLOT. On NoteBook*/ +void SalomeApp_Application::onNoteBook() +{ + SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); + if ( appStudy ) { + _PTR(Study) aStudy = appStudy->studyDS(); + if(!myNoteBook) { + myNoteBook = new SalomeApp_NoteBookDlg(desktop(),aStudy); + } + else if(!myNoteBook->isVisible()){ + myNoteBook->Init(aStudy); + myNoteBook->adjustSize(); + myNoteBook->move((int)(desktop()->x() + desktop()->width()/2 - myNoteBook->frameGeometry().width()/2), + (int)(desktop()->y() + desktop()->height()/2 - myNoteBook->frameGeometry().height()/2)); + } + myNoteBook->show(); + } +} + /*!Private SLOT. On load script.*/ void SalomeApp_Application::onLoadScript( ) { @@ -1443,3 +1478,15 @@ void SalomeApp_Application::objectBrowserColumnsVisibility() objectBrowser()->treeView()->setColumnHidden( i, !shown ); } } + +/*! Set SalomeApp_NoteBookDlg pointer */ +void SalomeApp_Application::setNoteBook(SalomeApp_NoteBookDlg* theNoteBook){ + myNoteBook = theNoteBook; +} + +/*! Return SalomeApp_NoteBookDlg pointer */ +SalomeApp_NoteBookDlg* SalomeApp_Application::getNoteBook() const +{ + return myNoteBook; +} + diff --git a/src/SalomeApp/SalomeApp_Application.h b/src/SalomeApp/SalomeApp_Application.h index 35b803dd2..3f18e6806 100644 --- a/src/SalomeApp/SalomeApp_Application.h +++ b/src/SalomeApp/SalomeApp_Application.h @@ -43,6 +43,7 @@ class LightApp_Preferences; class SalomeApp_Study; +class SalomeApp_NoteBookDlg; class SUIT_DataObject; class SALOME_LifeCycleCORBA; @@ -64,7 +65,7 @@ class SALOMEAPP_EXPORT SalomeApp_Application : public LightApp_Application public: enum { MenuToolsId = 5 }; enum { DumpStudyId = LightApp_Application::UserID, LoadScriptId, PropertiesId, - CatalogGenId, RegDisplayId, SaveGUIStateId, FileLoadId, UserID }; + CatalogGenId, RegDisplayId, SaveGUIStateId, FileLoadId, NoteBookId, UserID }; protected: enum { OpenRefresh = LightApp_Application::OpenReload + 1 }; @@ -98,6 +99,9 @@ public: virtual bool useStudy( const QString& ); virtual void updateDesktopTitle(); + + virtual void setNoteBook(SalomeApp_NoteBookDlg* theNoteBook); + virtual SalomeApp_NoteBookDlg* getNoteBook() const; public slots: virtual void onLoadDoc(); @@ -141,6 +145,7 @@ private slots: void onDblClick( SUIT_DataObject* ); void onProperties(); void onDumpStudy(); + void onNoteBook(); void onLoadScript(); void onDeleteGUIState(); @@ -150,6 +155,9 @@ private slots: void onCatalogGen(); void onRegDisplay(); void onOpenWith(); + + private: + SalomeApp_NoteBookDlg* myNoteBook; }; #ifdef WIN32 diff --git a/src/SalomeApp/SalomeApp_DataObject.cxx b/src/SalomeApp/SalomeApp_DataObject.cxx index 13d537177..7f31277ae 100644 --- a/src/SalomeApp/SalomeApp_DataObject.cxx +++ b/src/SalomeApp/SalomeApp_DataObject.cxx @@ -421,7 +421,45 @@ QString SalomeApp_DataObject::value( const _PTR(SObject)& obj ) const QString val; _PTR(GenericAttribute) attr; - if ( obj->FindAttribute( attr, "AttributeInteger" ) ) + if ( obj->FindAttribute( attr, "AttributeString" ) ) + { + _PTR(AttributeString) strAttr = attr; + std::string str = strAttr->Value(); + QString aStrings = QString( str.c_str() ); + + //Special case to show NoteBook variables in the "Value" column of the OB + if ( LightApp_RootObject* aRoot = dynamic_cast( root() ) ) + { + if ( SalomeApp_Study* aStudy = dynamic_cast( aRoot->study() ) ) + { + _PTR(Study) studyDS( aStudy->studyDS() ); + + bool ok = false; + QStringList aSectionList = aStrings.split( "|" ); + if ( !aSectionList.isEmpty() ) + { + QString aLastSection = aSectionList.last(); + QStringList aStringList = aLastSection.split( ":" ); + if ( !aStringList.isEmpty() ) + { + ok = true; + for ( int i = 0, n = aStringList.size(); i < n; i++ ) + { + QString aStr = aStringList[i]; + if ( studyDS->IsVariable( aStr.toStdString() ) ) + val.append( aStr + ", " ); + } + + if ( !val.isEmpty() ) + val.remove( val.length() - 2, 2 ); + } + } + if( !ok ) + val = aStrings; + } + } + } + else if ( obj->FindAttribute( attr, "AttributeInteger" ) ) { _PTR(AttributeInteger) intAttr = attr; if ( intAttr ) diff --git a/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx b/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx new file mode 100644 index 000000000..42cf9e48d --- /dev/null +++ b/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx @@ -0,0 +1,352 @@ +// 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_DoubleSpinBox.cxx +// Author: Oleg UVAROV + +#include "SalomeApp_DoubleSpinBox.h" +#include "SalomeApp_Application.h" +#include "SalomeApp_Study.h" + +#include + +#include "SALOMEDSClient_ClientFactory.hxx" +#include CORBA_SERVER_HEADER(SALOMEDS) + +#include +#include + +/*! + \class SalomeApp_DoubleSpinBox +*/ + +/*! + \brief Constructor. + + Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, + a step value of 1.0 and a precision of 2 decimal places. + The value is initially set to 0.00. + + \param parent parent object +*/ +SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( QWidget* parent ) +: QtxDoubleSpinBox( parent ), + myDefaultValue( 0.0 ), + myIsRangeSet( false ), + myMinimum( 0.0 ), + myMaximum( 99.99 ) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Constructor. + + Constructs a spin box with specified minimum, maximum and step value. + The precision is set to 2 decimal places. + The value is initially set to the minimum value. + + \param min spin box minimum possible value + \param max spin box maximum possible value + \param step spin box increment/decrement value + \param parent parent object +*/ +SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( double min, double max, double step, QWidget* parent ) +: QtxDoubleSpinBox( min, max, step, parent ), + myDefaultValue( 0.0 ), + myIsRangeSet( false ), + myMinimum( min ), + myMaximum( max ) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Constructor. + + Constructs a spin box with specified minimum, maximum and step value. + The precision is set to 2 decimal places. + The value is initially set to the minimum value. + + \param min spin box minimum possible value + \param max spin box maximum possible value + \param step spin box increment/decrement value + \param parent parent object +*/ +SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( double min, double max, double step, int prec, int dec, QWidget* parent ) +: QtxDoubleSpinBox( min, max, step, prec, dec, parent ), + myDefaultValue( 0.0 ), + myIsRangeSet( false ), + myMinimum( min ), + myMaximum( max ) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Destructor. +*/ +SalomeApp_DoubleSpinBox::~SalomeApp_DoubleSpinBox() +{ +} + +/*! + \brief Connect signals and slots. +*/ +void SalomeApp_DoubleSpinBox::connectSignalsAndSlots() +{ + connect( this, SIGNAL( editingFinished() ), + this, SLOT( onEditingFinished() ) ); + + connect( this, SIGNAL( valueChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& )), + this, SIGNAL( textChanged( const QString& ) ) ); +} + +/*! + \brief This function is called when editing is finished. +*/ +void SalomeApp_DoubleSpinBox::onEditingFinished() +{ + if( myTextValue.isNull() ) + myTextValue = text(); + + setText( myTextValue ); +} + +/*! + \brief This function is called when value is changed. +*/ +void SalomeApp_DoubleSpinBox::onTextChanged( const QString& text ) +{ + myTextValue = text; + + double value = 0; + if( isValid( text, value ) == Acceptable ) + myCorrectValue = text; +} + +/*! + \brief Interpret text entered by the user as a value. + \param text text entered by the user + \return mapped value + \sa textFromValue() +*/ +double SalomeApp_DoubleSpinBox::valueFromText( const QString& text ) const +{ + double value = 0; + if( isValid( text, value ) == Acceptable ) + return value; + + return defaultValue(); +} + +/*! + \brief This function is used by the spin box whenever it needs to display + the given value. + + \param val spin box value + \return text representation of the value + \sa valueFromText() +*/ +QString SalomeApp_DoubleSpinBox::textFromValue( double val ) const +{ + return QtxDoubleSpinBox::textFromValue( val ); +} + +/*! + \brief This function is used to determine whether input is valid. + \param str currently entered value + \param pos cursor position in the string + \return validating operation result +*/ +QValidator::State SalomeApp_DoubleSpinBox::validate( QString& str, int& pos ) const +{ + return QValidator::Acceptable; +} + +/*! + \brief This function is used to determine whether input is valid. + \return validating operation result +*/ +bool SalomeApp_DoubleSpinBox::isValid( QString& msg, bool toCorrect ) +{ + double value; + State aState = isValid( text(), value ); + + if( aState != Acceptable ) + { + if( toCorrect ) + { + if( aState == Incompatible ) + msg += tr( "ERR_INCOMPATIBLE_TYPE" ).arg( text() ) + "\n"; + else if( aState == NoVariable ) + msg += tr( "ERR_NO_VARIABLE" ).arg( text() ) + "\n"; + else if( aState == Invalid ) + msg += tr( "ERR_INVALID_VALUE" ) + "\n"; + + setText( myCorrectValue ); + } + return false; + } + + return true; +} + +/*! + \brief This function is used to set a default value for this spinbox. + \param value default value +*/ +void SalomeApp_DoubleSpinBox::setDefaultValue( const double value ) +{ + myDefaultValue = value; +} + +/*! + \brief This function is used to set minimum and maximum values for this spinbox. + \param min minimum value + \param max maximum value +*/ +void SalomeApp_DoubleSpinBox::setRange( const double min, const double max ) +{ + QtxDoubleSpinBox::setRange( min, max ); + + myIsRangeSet = true; + myMinimum = min; + myMaximum = max; +} + +/*! + \brief This function is used to set a current value for this spinbox. + \param value current value +*/ +void SalomeApp_DoubleSpinBox::setValue( const double value ) +{ + QtxDoubleSpinBox::setValue( value ); + + myCorrectValue = QString::number( value ); + myTextValue = myCorrectValue; +} + +/*! + \brief This function is used to set a text for this spinbox. + \param value current value +*/ +void SalomeApp_DoubleSpinBox::setText( const QString& value ) +{ + lineEdit()->setText(value); +} + +/*! + \brief This function is used to determine whether input is valid. + \return validating operation result +*/ +SalomeApp_DoubleSpinBox::State SalomeApp_DoubleSpinBox::isValid( const QString& text, double& value ) const +{ + SearchState aSearchState = findVariable( text, value ); + if( aSearchState == NotFound ) + { + bool ok = false; + value = text.toDouble( &ok ); + if( !ok ) + return NoVariable; + } + else if( aSearchState == IncorrectType ) + return Incompatible; + + if( !checkRange( value ) ) + return Invalid; + + return Acceptable; +} + +/*! + \brief This function return a default acceptable value (commonly, 0.0). + \return default acceptable value +*/ +double SalomeApp_DoubleSpinBox::defaultValue() const +{ + if( myMinimum > myDefaultValue || myMaximum < myDefaultValue ) + return myMinimum; + + return myDefaultValue; +} + +/*! + \brief This function is used to check that string value lies within predefined range. + \return check status +*/ +bool SalomeApp_DoubleSpinBox::checkRange( const double value ) const +{ + if( !myIsRangeSet ) + return true; + + return value >= myMinimum && value <= myMaximum; +} + +/*! + \brief This function is used to determine whether input is a variable name and to get its value. + \return status of search operation +*/ +SalomeApp_DoubleSpinBox::SearchState SalomeApp_DoubleSpinBox::findVariable( const QString& name, double& value ) const +{ + value = 0; + if( SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ) ) + { + if( SalomeApp_Study* study = dynamic_cast( app->activeStudy() ) ) + { + _PTR(Study) studyDS = study->studyDS(); + + std::string aName = name.toStdString(); + if( studyDS->IsVariable( aName ) ) + { + if( studyDS->IsReal( aName ) || studyDS->IsInteger( aName ) ) + { + value = studyDS->GetReal( aName ); + return Found; + } + return IncorrectType; + } + } + } + return NotFound; +} + +/*! + \brief This function is called when the spinbox recieves key press event. +*/ +void SalomeApp_DoubleSpinBox::keyPressEvent( QKeyEvent* e ) +{ + if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) + QWidget::keyPressEvent( e ); + else + QtxDoubleSpinBox::keyPressEvent( e ); +} + +/*! + \brief This function is called when the spinbox recieves show event. +*/ +void SalomeApp_DoubleSpinBox::showEvent( QShowEvent* ) +{ + setText( myTextValue ); +} diff --git a/src/SalomeApp/SalomeApp_DoubleSpinBox.h b/src/SalomeApp/SalomeApp_DoubleSpinBox.h new file mode 100644 index 000000000..c5b6539ca --- /dev/null +++ b/src/SalomeApp/SalomeApp_DoubleSpinBox.h @@ -0,0 +1,91 @@ +// 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_DoubleSpinBox.h +// Author: Oleg UVAROV + +#ifndef SALOMEAPP_DOUBLESPINBOX_H +#define SALOMEAPP_DOUBLESPINBOX_H + +#include "SalomeApp.h" + +#include + +#include + +class SALOMEAPP_EXPORT SalomeApp_DoubleSpinBox : public QtxDoubleSpinBox +{ + Q_OBJECT + + enum State { Invalid = 0, NoVariable, Incompatible, Acceptable }; + enum SearchState { NotFound = 0, IncorrectType, Found }; + +public: + SalomeApp_DoubleSpinBox( QWidget* = 0 ); + SalomeApp_DoubleSpinBox( double, double, double = 1, QWidget* = 0 ); + SalomeApp_DoubleSpinBox( double, double, double, int, int, QWidget* = 0 ); + virtual ~SalomeApp_DoubleSpinBox(); + + virtual double valueFromText( const QString& ) const; + virtual QString textFromValue( double ) const; + + virtual QValidator::State validate( QString&, int& ) const; + + virtual bool isValid( QString& msg, bool = false ); + + virtual void setDefaultValue( const double ); + + virtual void setRange( double, double ); + virtual void setValue( double ); + + virtual void setText(const QString& ); + +signals: + void textChanged( const QString& ); + +protected: + State isValid( const QString&, double& ) const; + + double defaultValue() const; + bool checkRange( const double ) const; + + SearchState findVariable( const QString&, double& ) const; + +protected: + virtual void keyPressEvent( QKeyEvent* ); + virtual void showEvent( QShowEvent* ); + +protected slots: + void onEditingFinished(); + void onTextChanged( const QString& ); + +private: + void connectSignalsAndSlots(); + +private: + double myDefaultValue; + + bool myIsRangeSet; + double myMinimum; + double myMaximum; + + QString myCorrectValue; + QString myTextValue; +}; + +#endif diff --git a/src/SalomeApp/SalomeApp_IntSpinBox.cxx b/src/SalomeApp/SalomeApp_IntSpinBox.cxx new file mode 100644 index 000000000..4d3460a3b --- /dev/null +++ b/src/SalomeApp/SalomeApp_IntSpinBox.cxx @@ -0,0 +1,310 @@ +// 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_IntSpinBox.cxx +// Author: Oleg UVAROV + +#include "SalomeApp_IntSpinBox.h" +#include "SalomeApp_Application.h" +#include "SalomeApp_Study.h" + +#include + +#include "SALOMEDSClient_ClientFactory.hxx" +#include CORBA_SERVER_HEADER(SALOMEDS) + +#include +#include + +/*! + \class SalomeApp_IntSpinBox +*/ + +/*! + \brief Constructor. + + Constructs a spin box with 0 as minimum value and 99 as maximum value, + a step value of 1. The value is initially set to 0. + + \param parent parent object +*/ +SalomeApp_IntSpinBox::SalomeApp_IntSpinBox( QWidget* parent ) +: QtxIntSpinBox( parent ), + myDefaultValue( 0 ) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Constructor. + + Constructs a spin box with specified minimum, maximum and step value. + The value is initially set to the minimum value. + + \param min spin box minimum possible value + \param max spin box maximum possible value + \param step spin box increment/decrement value + \param parent parent object +*/ +SalomeApp_IntSpinBox::SalomeApp_IntSpinBox( int min, int max, int step, QWidget* parent ) +: QtxIntSpinBox( min, max, step, parent ), + myDefaultValue( 0 ) +{ + connectSignalsAndSlots(); +} + +/*! + \brief Destructor. +*/ +SalomeApp_IntSpinBox::~SalomeApp_IntSpinBox() +{ +} + +/*! + \brief Connect signals and slots. +*/ +void SalomeApp_IntSpinBox::connectSignalsAndSlots() +{ + connect( this, SIGNAL( editingFinished() ), + this, SLOT( onEditingFinished() ) ); + + connect( this, SIGNAL( valueChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& )), + this, SIGNAL( textChanged( const QString& ) ) ); +} + +/*! + \brief This function is called when editing is finished. +*/ +void SalomeApp_IntSpinBox::onEditingFinished() +{ + if( myTextValue.isNull() ) + myTextValue = text(); + + setText( myTextValue ); +} + +/*! + \brief This function is called when value is changed. +*/ +void SalomeApp_IntSpinBox::onTextChanged( const QString& text ) +{ + myTextValue = text; + + int value = 0; + if( isValid( text, value ) == Acceptable ) + myCorrectValue = text; +} + +/*! + \brief Interpret text entered by the user as a value. + \param text text entered by the user + \return mapped value + \sa textFromValue() +*/ +int SalomeApp_IntSpinBox::valueFromText( const QString& text ) const +{ + int value = 0; + if( isValid( text, value ) == Acceptable ) + return value; + + return defaultValue(); +} + +/*! + \brief This function is used by the spin box whenever it needs to display + the given value. + + \param val spin box value + \return text representation of the value + \sa valueFromText() +*/ +QString SalomeApp_IntSpinBox::textFromValue( int val ) const +{ + return QtxIntSpinBox::textFromValue( val ); +} + +/*! + \brief This function is used to determine whether input is valid. + \param str currently entered value + \param pos cursor position in the string + \return validating operation result +*/ +QValidator::State SalomeApp_IntSpinBox::validate( QString& str, int& pos ) const +{ + return QValidator::Acceptable; +} + +/*! + \brief This function is used to determine whether input is valid. + \return validating operation result +*/ +bool SalomeApp_IntSpinBox::isValid( QString& msg, bool toCorrect ) +{ + int value; + State aState = isValid( text(), value ); + + if( aState != Acceptable ) + { + if( toCorrect ) + { + if( aState == Incompatible ) + msg += tr( "ERR_INCOMPATIBLE_TYPE" ).arg( text() ) + "\n"; + else if( aState == NoVariable ) + msg += tr( "ERR_NO_VARIABLE" ).arg( text() ) + "\n"; + else if( aState == Invalid ) + msg += tr( "ERR_INVALID_VALUE" ) + "\n"; + + setText( myCorrectValue ); + } + return false; + } + + return true; +} + +/*! + \brief This function is used to set a default value for this spinbox. + \param value default value +*/ +void SalomeApp_IntSpinBox::setDefaultValue( const int value ) +{ + myDefaultValue = value; +} + +/*! + \brief This function is used to set a current value for this spinbox. + \param value current value +*/ +void SalomeApp_IntSpinBox::setValue( const int value ) +{ + QtxIntSpinBox::setValue( value ); + + myCorrectValue = QString::number( value ); + myTextValue = myCorrectValue; +} + +/*! + \brief This function is used to set a text for this spinbox. + \param value current value +*/ +void SalomeApp_IntSpinBox::setText( const QString& value ) +{ + lineEdit()->setText(value); +} + +/*! + \brief This function is used to determine whether input is valid. + \return validating operation result +*/ +SalomeApp_IntSpinBox::State SalomeApp_IntSpinBox::isValid( const QString& text, int& value ) const +{ + SearchState aSearchState = findVariable( text, value ); + if( aSearchState == NotFound ) + { + bool ok = false; + value = text.toInt( &ok ); + if( !ok ) + { + text.toDouble( &ok ); + if( ok ) + return Invalid; + return NoVariable; + } + } + else if( aSearchState == IncorrectType ) + return Incompatible; + + if( !checkRange( value ) ) + return Invalid; + + return Acceptable; +} + +/*! + \brief This function return a default acceptable value (commonly, 0). + \return default acceptable value +*/ +int SalomeApp_IntSpinBox::defaultValue() const +{ + if( minimum() > myDefaultValue || maximum() < myDefaultValue ) + return minimum(); + + return myDefaultValue; +} + +/*! + \brief This function is used to check that string value lies within predefined range. + \return check status +*/ +bool SalomeApp_IntSpinBox::checkRange( const int value ) const +{ + return value >= minimum() && value <= maximum(); +} + +/*! + \brief This function is used to determine whether input is a variable name and to get its value. + \return status of search operation +*/ +SalomeApp_IntSpinBox::SearchState SalomeApp_IntSpinBox::findVariable( const QString& name, int& value ) const +{ + value = 0; + if( SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ) ) + { + if( SalomeApp_Study* study = dynamic_cast( app->activeStudy() ) ) + { + _PTR(Study) studyDS = study->studyDS(); + + std::string aName = name.toStdString(); + if( studyDS->IsVariable( aName ) ) + { + if( studyDS->IsInteger( aName ) ) + { + value = studyDS->GetInteger( aName ); + return Found; + } + return IncorrectType; + } + } + } + return NotFound; +} + +/*! + \brief This function is called when the spinbox recieves key press event. +*/ +void SalomeApp_IntSpinBox::keyPressEvent( QKeyEvent* e ) +{ + if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) + QWidget::keyPressEvent( e ); + else + QtxIntSpinBox::keyPressEvent( e ); +} + +/*! + \brief This function is called when the spinbox recieves show event. +*/ +void SalomeApp_IntSpinBox::showEvent( QShowEvent* ) +{ + setText( myTextValue ); +} diff --git a/src/SalomeApp/SalomeApp_IntSpinBox.h b/src/SalomeApp/SalomeApp_IntSpinBox.h new file mode 100644 index 000000000..d15fe99c1 --- /dev/null +++ b/src/SalomeApp/SalomeApp_IntSpinBox.h @@ -0,0 +1,85 @@ +// 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_IntSpinBox.h +// Author: Oleg UVAROV + +#ifndef SALOMEAPP_INTSPINBOX_H +#define SALOMEAPP_INTSPINBOX_H + +#include "SalomeApp.h" + +#include + +#include + +class SALOMEAPP_EXPORT SalomeApp_IntSpinBox : public QtxIntSpinBox +{ + Q_OBJECT + + enum State { Invalid = 0, NoVariable, Incompatible, Acceptable }; + enum SearchState { NotFound = 0, IncorrectType, Found }; + +public: + SalomeApp_IntSpinBox( QWidget* = 0 ); + SalomeApp_IntSpinBox( int, int, int = 1, QWidget* = 0 ); + virtual ~SalomeApp_IntSpinBox(); + + virtual int valueFromText( const QString& ) const; + virtual QString textFromValue( int ) const; + + virtual QValidator::State validate( QString&, int& ) const; + + virtual bool isValid( QString& msg, bool = false ); + + virtual void setDefaultValue( const int ); + + virtual void setValue( int ); + + virtual void setText(const QString& ); + +signals: + void textChanged( const QString& ); + +protected: + State isValid( const QString&, int& ) const; + + int defaultValue() const; + bool checkRange( const int ) const; + + SearchState findVariable( const QString&, int& ) const; + +protected: + virtual void keyPressEvent( QKeyEvent* ); + virtual void showEvent( QShowEvent* ); + +protected slots: + void onEditingFinished(); + void onTextChanged( const QString& ); + +private: + void connectSignalsAndSlots(); + +private: + int myDefaultValue; + + QString myCorrectValue; + QString myTextValue; +}; + +#endif diff --git a/src/SalomeApp/SalomeApp_NoteBookDlg.cxx b/src/SalomeApp/SalomeApp_NoteBookDlg.cxx new file mode 100644 index 000000000..6005d889a --- /dev/null +++ b/src/SalomeApp/SalomeApp_NoteBookDlg.cxx @@ -0,0 +1,1082 @@ +// Copyright (C) 2008 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_NoteBookDlg.cxx +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. +// Module : GUI + +#include "SalomeApp_NoteBookDlg.h" +#include "SalomeApp_Application.h" +#include "SalomeApp_Study.h" +#include "SalomeApp_VisualState.h" + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +#define DEFAULT_MARGIN 11 +#define DEFAULT_SPACING 6 +#define SPACER_SIZE 120 +#define COLUMN_SIZE 180 + +#define NAME_COLUMN 0 +#define VALUE_COLUMN 1 + + +/////////////////////////////////////////////////////////////////////////// +// NoteBook_TableRow class // +/////////////////////////////////////////////////////////////////////////// +//============================================================================ +/*! Function : NoteBook_TableRow + * Purpose : Constructor + */ +//============================================================================ +NoteBook_TableRow::NoteBook_TableRow(int index, QWidget* parent): + QWidget(parent), + myIndex(index), + myRowHeader(new QTableWidgetItem()), + myVariableName(new QTableWidgetItem()), + myVariableValue(new QTableWidgetItem()) +{ +} + +//============================================================================ +/*! Function : ~NoteBook_TableRow + * Purpose : Destructor + */ +//============================================================================ +NoteBook_TableRow::~NoteBook_TableRow() +{ +} + +//============================================================================ +/*! Function : AddToTable + * Purpose : Add this row to the table theTable + */ +//============================================================================ +void NoteBook_TableRow::AddToTable(QTableWidget *theTable) +{ + int aPosition = theTable->rowCount(); + int aRowCount = aPosition+1; + theTable->setRowCount(aRowCount); + myRowHeader->setText(QString::number(aRowCount)); + + theTable->setVerticalHeaderItem(aPosition,myRowHeader); + theTable->setItem(aPosition, NAME_COLUMN, myVariableName); + theTable->setItem(aPosition, VALUE_COLUMN, myVariableValue); +} + +//============================================================================ +/*! Function : SetName + * Purpose : + */ +//============================================================================ +void NoteBook_TableRow::SetName(const QString theName) +{ + myVariableName->setText(theName); +} + +//============================================================================ +/*! Function : SetValue + * Purpose : + */ +//============================================================================ +void NoteBook_TableRow::SetValue(const QString theValue) +{ + myVariableValue->setText(theValue); +} + +//============================================================================ +/*! Function : GetName + * Purpose : Return variable name + */ +//============================================================================ +QString NoteBook_TableRow::GetName() const +{ + return myVariableName->text(); +} + +//============================================================================ +/*! Function : GetValue + * Purpose : Return variable value + */ +//============================================================================ +QString NoteBook_TableRow::GetValue() const +{ + return myVariableValue->text(); +} + +//============================================================================ +/*! Function : CheckName + * Purpose : Return true if variable name correct, otherwise return false + */ +//============================================================================ +bool NoteBook_TableRow::CheckName() +{ + QString aName = GetName(); + int aPos = 0; + QRegExpValidator aValidator( QRegExp("^([a-zA-Z]+)([a-zA-Z0-9_]*)$"), 0 ); + if( aName.isEmpty() || !aValidator.validate( aName, aPos ) ) + return false; + return true; +} + +//============================================================================ +/*! Function : CheckValue + * Purpose : Return true if variable value correct, otherwise return false + */ +//============================================================================ +bool NoteBook_TableRow::CheckValue() +{ + bool aResult = false; + QString aValue = GetValue(); + if( (!aValue.isEmpty()) && + (IsRealValue(aValue)) || + IsIntegerValue(aValue)|| + IsBooleanValue(aValue)) + aResult = true; + + return aResult; +} + +//============================================================================ +/*! Function : GetVariableItem + * Purpose : + */ +//============================================================================ +QTableWidgetItem* NoteBook_TableRow::GetVariableItem() +{ + return myVariableValue; +} + +//============================================================================ +/*! Function : GetNameItem + * Purpose : + */ +//============================================================================ +QTableWidgetItem* NoteBook_TableRow::GetNameItem() +{ + return myVariableName; +} + +//============================================================================ +/*! Function : GetHeaderItem + * Purpose : + */ +//============================================================================ +QTableWidgetItem* NoteBook_TableRow::GetHeaderItem() +{ + return myRowHeader; +} + +//============================================================================ +/*! Function : IsRealValue + * Purpose : Return true if theValue string is real value, otherwise return + * false + */ +//============================================================================ +bool NoteBook_TableRow::IsRealValue(const QString theValue, double* theResult) +{ + bool aResult = false; + double aDResult = theValue.toDouble(&aResult); + if(theResult) + *theResult = aDResult; + + return aResult; +} + +//============================================================================ +/*! Function : IsBooleanValue + * Purpose : Return true if theValue String is boolean value, otherwise return + * false + */ +//============================================================================ +bool NoteBook_TableRow::IsBooleanValue(const QString theValue, bool* theResult){ + bool aResult = false; + bool aBResult; + if(theValue.compare("True") == 0) { + aBResult = true; + aResult = true; + } + else if(theValue.compare("False") == 0) { + aBResult = false; + aResult = true; + } + if(theResult) + *theResult = aBResult; + + return aResult; +} + +//============================================================================ +/*! Function : IsIntegerValue + * Purpose : Return true if theValue string is integer value, otherwise return + * false + */ +//============================================================================ +bool NoteBook_TableRow::IsIntegerValue(const QString theValue, int* theResult) +{ + bool aResult = false; + int anIResult; + anIResult = theValue.toInt(&aResult); + + if(theResult) + *theResult = anIResult; + + return aResult; +} + + +/////////////////////////////////////////////////////////////////////////// +// NoteBook_Table class // +/////////////////////////////////////////////////////////////////////////// +//============================================================================ +/*! Function : NoteBook_Table + * Purpose : Constructor + */ +//============================================================================ +NoteBook_Table::NoteBook_Table(QWidget * parent) + :QTableWidget(parent), + isProcessItemChangedSignal(false), + myIsModified(false) +{ + setColumnCount(2); + setSelectionMode(QAbstractItemView::SingleSelection); + + //Add Headers Columns + QFont aFont = QFont(); + aFont.setBold(true); + aFont.setPointSize(10); + + //"Name" column + QTableWidgetItem * aNameHeader = new QTableWidgetItem(); + aNameHeader->setText(tr("VARNAME_COLUMN")); + aNameHeader->setFont(aFont); + setHorizontalHeaderItem(0,aNameHeader); + setColumnWidth ( 0, COLUMN_SIZE); + + //"Value" Column + QTableWidgetItem * aValueHeader = new QTableWidgetItem(); + aValueHeader->setText(tr("VARVALUE_COLUMN")); + aValueHeader->setFont(aFont); + setHorizontalHeaderItem(1,aValueHeader); + setColumnWidth ( 1, COLUMN_SIZE); + setSortingEnabled(false); + + connect(this,SIGNAL(itemChanged(QTableWidgetItem*)),this,SLOT(onItemChanged(QTableWidgetItem*))); +} + +//============================================================================ +/*! Function : ~NoteBook_Table + * Purpose : Destructor + */ +//============================================================================ +NoteBook_Table::~NoteBook_Table(){} + +//============================================================================ +/*! Function : getUniqueIndex + * Purpose : Get a unique index for the new row + */ +//============================================================================ +int NoteBook_Table::getUniqueIndex() const +{ + int anIndex = 0; + if( !myRows.isEmpty() ) + if( NoteBook_TableRow* aRow = myRows.last() ) + anIndex = aRow->GetIndex(); + + int aMaxRemovedRow = 0; + for( QListIterator anIter( myRemovedRows ); anIter.hasNext(); ) + { + int aRemovedRow = anIter.next(); + aMaxRemovedRow = qMax( aRemovedRow, aMaxRemovedRow ); + } + + anIndex = qMax( anIndex, aMaxRemovedRow ) + 1; + return anIndex; +} + +//============================================================================ +/*! Function : Init + * Purpose : Add variables in the table from theStudy + */ +//============================================================================ +void NoteBook_Table::Init(_PTR(Study) theStudy) +{ + isProcessItemChangedSignal = false; + + int aNumRows = myRows.count(); + if( aNumRows > 0 ) + { + for( int i = 0; i < myRows.size(); i++ ) + { + NoteBook_TableRow* aRow = myRows[ i ]; + if( aRow ) + { + delete aRow; + aRow = 0; + } + } + myRows.clear(); + } + setRowCount( 0 ); + + myRemovedRows.clear(); + myVariableMapRef.clear(); + myVariableMap.clear(); + + //Add all variables into the table + vector aVariables = theStudy->GetVariableNames(); + for(int iVar = 0; iVar < aVariables.size(); iVar++ ) { + AddRow(QString(aVariables[iVar].c_str()), + Variable2String(aVariables[iVar],theStudy)); + } + + //Add empty row + AddEmptyRow(); + isProcessItemChangedSignal = true; + + ResetMaps(); + + myStudy = theStudy; +} + +//============================================================================ +/*! Function : Variable2String + * Purpose : Convert variable values to QString + */ +//============================================================================ +QString NoteBook_Table::Variable2String(const string& theVarName, + _PTR(Study) theStudy) +{ + QString aResult; + if( theStudy->IsReal(theVarName) ) + aResult = QString::number(theStudy->GetReal(theVarName)); + else if( theStudy->IsInteger(theVarName) ) + aResult = QString::number(theStudy->GetInteger(theVarName)); + else if( theStudy->IsBoolean(theVarName) ) + aResult = theStudy->GetBoolean(theVarName) ? QString("True") : QString("False"); + + return aResult; +} + +//============================================================================ +/*! Function : IsValid + * Purpose : Check validity of the table data + */ +//============================================================================ +bool NoteBook_Table::IsValid() const +{ + int aNumRows = myRows.count(); + if( aNumRows == 0 ) + return true; + + bool aLastRowIsEmpty = myRows[ aNumRows - 1 ]->GetName().isEmpty() && + myRows[ aNumRows - 1 ]->GetValue().isEmpty(); + + for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ ) + if( !myRows[i]->CheckName() || !IsUniqueName( myRows[i] ) || !myRows[i]->CheckValue() ) + return false; + + return true; +} + +//============================================================================ +/*! Function : RenamberRowItems + * Purpose : renumber row items + */ +//============================================================================ +void NoteBook_Table::RenamberRowItems(){ + for(int i=0; iGetHeaderItem()->setText(QString::number(i+1)); + } +} + +//============================================================================ +/*! Function : AddRow + * Purpose : Add a row into the table + */ +//============================================================================ +void NoteBook_Table::AddRow(const QString& theName, const QString& theValue) +{ + int anIndex = getUniqueIndex(); + NoteBook_TableRow* aRow = new NoteBook_TableRow(anIndex, this); + aRow->SetName(theName); + aRow->SetValue(theValue); + aRow->AddToTable(this); + myRows.append(aRow); + + myVariableMap.insert( anIndex, NoteBoox_Variable( theName, theValue ) ); +} + +//============================================================================ +/*! Function : AddEmptyRow + * Purpose : Add an empty row into the end of the table + */ +//============================================================================ +void NoteBook_Table::AddEmptyRow() +{ + isProcessItemChangedSignal = false; + AddRow(); + isProcessItemChangedSignal = true; +} + +//============================================================================ +/*! Function : GetRowByItem + * Purpose : + */ +//============================================================================ +NoteBook_TableRow* NoteBook_Table::GetRowByItem(const QTableWidgetItem* theItem) const +{ + int aCurrentRow = row(theItem); + + if( (myRows.size() <= aCurrentRow ) && (aCurrentRow < 0)) + return NULL; + else + return myRows.at(aCurrentRow); +} + +//============================================================================ +/*! Function : IsLastRow + * Purpose : Return true if theRow is last row in the table + */ +//============================================================================ +bool NoteBook_Table::IsLastRow(const NoteBook_TableRow* theRow) const +{ + return (myRows.last() == theRow); +} + +//============================================================================ +/*! Function : onItemChanged + * Purpose : [slot] called then table item changed + */ +//============================================================================ +void NoteBook_Table::onItemChanged(QTableWidgetItem* theItem) +{ + if(isProcessItemChangedSignal) { + bool isModified = true; + NoteBook_TableRow* aRow = GetRowByItem(theItem); + if(aRow) { + int aCurrentColumn = column(theItem); + bool IsCorrect = true, IsVariableComplited = false; + QString aMsg; + + if(aCurrentColumn == NAME_COLUMN) { + int anIndex = aRow->GetIndex(); + if( myVariableMap.contains( anIndex ) ) + { + const NoteBoox_Variable& aVariable = myVariableMap[ anIndex ]; + if( !aVariable.Name.isEmpty() && myStudy->IsVariableUsed( string( aVariable.Name.toLatin1().constData() ) ) ) + { + if( QMessageBox::warning( parentWidget(), tr( "WARNING" ), + tr( "RENAME_VARIABLE_IS_USED" ).arg( aVariable.Name ), + QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No ) + { + bool isBlocked = blockSignals( true ); + aRow->SetName( aVariable.Name ); + blockSignals( isBlocked ); + return; + } + } + } + } + + //Case then varible name changed. + if(aCurrentColumn == NAME_COLUMN) { + if(!aRow->CheckName()) { + IsCorrect = false; + aMsg = tr( "VARNAME_INCORRECT" ).arg(aRow->GetName()); + } + else if(!IsUniqueName(aRow)) { + IsCorrect = false; + aMsg = tr( "VARNAME_EXISTS" ).arg(aRow->GetName()); + } + else + IsVariableComplited = aRow->CheckValue(); + } + + //Case then varible value changed. + else if(aCurrentColumn == VALUE_COLUMN){ + if(!aRow->CheckValue()) { + IsCorrect = false; + aMsg = tr( "VARVALUE_INCORRECT" ).arg(aRow->GetName()); + } + else + IsVariableComplited = aRow->CheckName() && IsUniqueName(aRow); + } + + if(!IsCorrect && !aMsg.isEmpty()) + SUIT_MessageBox::warning( parentWidget(), tr( "WARNING" ), aMsg ); + + bool isBlocked = blockSignals( true ); + theItem->setForeground( QBrush( IsCorrect ? Qt::black : Qt::red ) ); + blockSignals( isBlocked ); + + int anIndex = aRow->GetIndex(); + if( myVariableMap.contains( anIndex ) ) + { + NoteBoox_Variable& aVariable = myVariableMap[ anIndex ]; + if( aVariable.Name.compare( aRow->GetName() ) != 0 || + aVariable.Value.compare( aRow->GetValue() ) != 0 ) + { + aVariable.Name = aRow->GetName(); + aVariable.Value = aRow->GetValue(); + } + else + isModified = false; + } + + if(IsCorrect && IsVariableComplited && IsLastRow(aRow)) + AddEmptyRow(); + } + + if( !myIsModified ) + myIsModified = isModified; + } +} + +//============================================================================ +/*! Function : IsUniqueName + * Purpose : Return true if theName is unique name of the Variable + */ +//============================================================================ +bool NoteBook_Table::IsUniqueName(const NoteBook_TableRow* theRow) const +{ + for(int i=0; iGetName().compare(theRow->GetName()) == 0) + return false; + } + return true; +} + +//============================================================================ +/*! Function : RemoveSelected + * Purpose : Remove selected rows in the table + */ +//============================================================================ +void NoteBook_Table::RemoveSelected() +{ + isProcessItemChangedSignal = false; + QList aSelectedItems = selectedItems(); + if( !(aSelectedItems.size() > 0)) { + isProcessItemChangedSignal = true; + return; + } + bool removedFromStudy = false; + for(int i=0; i < aSelectedItems.size(); i++ ) { + NoteBook_TableRow* aRow = GetRowByItem(aSelectedItems[i]); + if(aRow) { + if(IsLastRow(aRow)) { + aRow->SetName(QString()); + aRow->SetValue(QString()); + } + else { + int nRow = row(aSelectedItems[i]); + + if( myStudy->IsVariableUsed( string( aRow->GetName().toLatin1().constData() ) ) ) + { + if( QMessageBox::warning( parentWidget(), tr( "WARNING" ), + tr( "REMOVE_VARIABLE_IS_USED" ).arg( aRow->GetName() ), + QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No ) + { + isProcessItemChangedSignal = true; + return; + } + } + + int index = aRow->GetIndex(); + QString aVarName = aRow->GetName(); + myRemovedRows.append( index ); + if( myVariableMap.contains( index ) ) + myVariableMap.remove( index ); + removeRow(nRow); + myRows.removeAt(nRow); + if(myStudy->IsVariable(aVarName.toLatin1().constData())) + removedFromStudy = true; + } + } + } + if(removedFromStudy) + myIsModified = true; + RenamberRowItems(); + isProcessItemChangedSignal = true; +} + +//============================================================================ +/*! Function : SetProcessItemChangedSignalFlag + * Purpose : + */ +//============================================================================ +void NoteBook_Table::SetProcessItemChangedSignalFlag(const bool enable) +{ + isProcessItemChangedSignal = enable; +} + +//============================================================================ +/*! Function : GetProcessItemChangedSignalFlag + * Purpose : + */ +//============================================================================ +bool NoteBook_Table::GetProcessItemChangedSignalFlag() const +{ + return isProcessItemChangedSignal; +} + +//============================================================================ +/*! Function : GetRows + * Purpose : + */ +//============================================================================ +QList NoteBook_Table::GetRows() const +{ + return myRows; +} + +//============================================================================ +/*! Function : ResetMaps + * Purpose : Reset variable maps + */ +//============================================================================ +void NoteBook_Table::ResetMaps() +{ + myIsModified = false; + myVariableMapRef = myVariableMap; + myRemovedRows.clear(); +} + +/////////////////////////////////////////////////////////////////////////// +// SalomeApp_NoteBookDlg class // +/////////////////////////////////////////////////////////////////////////// +//============================================================================ +/*! Function : SalomeApp_NoteBookDlg + * Purpose : Constructor + */ +//============================================================================ +SalomeApp_NoteBookDlg::SalomeApp_NoteBookDlg(QWidget * parent, _PTR(Study) theStudy): + QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + myStudy(theStudy) +{ + setModal(false); + setObjectName("SalomeApp_NoteBookDlg"); + setWindowTitle(tr("NOTEBOOK_TITLE")); + QGridLayout* aLayout = new QGridLayout(this); + aLayout->setMargin(DEFAULT_MARGIN); + aLayout->setSpacing(DEFAULT_SPACING); + + //Table + myTable = new NoteBook_Table(this); + aLayout->addWidget(myTable, 0, 0, 1, 3); + + //Buttons + myRemoveButton = new QPushButton(tr("BUT_REMOVE")); + aLayout->addWidget(myRemoveButton, 1, 0, 1, 1); + + QSpacerItem* spacer = + new QSpacerItem(DEFAULT_SPACING, 5 , QSizePolicy::Expanding, QSizePolicy::Minimum); + aLayout->addItem(spacer, 1, 1, 2, 1); + + myUpdateStudyBtn = new QPushButton(tr("BUT_UPDATE_STUDY")); + aLayout->addWidget(myUpdateStudyBtn, 1, 2, 1, 1); + + QGroupBox* groupBox = new QGroupBox(this); + + QGridLayout* aLayout1 = new QGridLayout(groupBox); + + aLayout1->setMargin(DEFAULT_MARGIN); + aLayout1->setSpacing(DEFAULT_SPACING); + + myOkBtn = new QPushButton(tr("BUT_APPLY_AND_CLOSE")); + aLayout1->addWidget(myOkBtn, 0, 0, 1, 1); + + myApplyBtn = new QPushButton(tr("BUT_APPLY")); + aLayout1->addWidget(myApplyBtn, 0, 1, 1, 1); + + QSpacerItem* spacer1 = + new QSpacerItem(DEFAULT_SPACING, 5, QSizePolicy::Expanding, QSizePolicy::Minimum); + aLayout1->addItem(spacer1, 0, 2, 1, 1); + + myCancelBtn = new QPushButton(tr("BUT_CLOSE")); + aLayout1->addWidget(myCancelBtn, 0, 3, 1, 1); + + myHelpBtn = new QPushButton(tr("BUT_HELP")); + aLayout1->addWidget(myHelpBtn, 0, 4, 1, 1); + + aLayout->addWidget(groupBox, 2, 0, 1, 3); + + QWidgetList aWidgetList; + aWidgetList.append( myTable ); + aWidgetList.append( myOkBtn ); + aWidgetList.append( myApplyBtn ); + aWidgetList.append( myCancelBtn ); + aWidgetList.append( myHelpBtn ); + aWidgetList.append( myUpdateStudyBtn ); + aWidgetList.append( myRemoveButton ); + Qtx::setTabOrder( aWidgetList ); + + connect( myOkBtn, SIGNAL(clicked()), this, SLOT(onOK()) ); + connect( myApplyBtn, SIGNAL(clicked()), this, SLOT(onApply()) ); + connect( myCancelBtn, SIGNAL(clicked()), this, SLOT(onCancel()) ); + connect( myUpdateStudyBtn, SIGNAL(clicked()), this, SLOT(onUpdateStudy()) ); + connect( myRemoveButton, SIGNAL(clicked()), this, SLOT(onRemove())); + connect( myHelpBtn, SIGNAL(clicked()), this, SLOT(onHelp())); + + myTable->Init(myStudy); +} + +//============================================================================ +/*! Function : ~SalomeApp_NoteBookDlg + * Purpose : Destructor + */ +//============================================================================ +SalomeApp_NoteBookDlg::~SalomeApp_NoteBookDlg(){} + + +//============================================================================ +/*! Function : Init() + * Purpose : init variable table + */ +//============================================================================ +void SalomeApp_NoteBookDlg::Init(_PTR(Study) theStudy){ + if(myStudy!= theStudy) + myStudy = theStudy; + myTable->Init(myStudy); +} + + +//============================================================================ +/*! Function : onOK + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onOK() +{ + onApply(); + if( myTable->IsValid() ) + accept(); +} + +//============================================================================ +/*! Function : onHelp + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onHelp() +{ + QString aHelpFileName("using_notebook.html"); + LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); + if (app) + app->onHelpContextModule("GUI",aHelpFileName); + else { + QString platform; +#ifdef WIN32 + platform = "winapplication"; +#else + platform = "application"; +#endif + SUIT_MessageBox::warning(this, tr("WRN_WARNING"), + tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE"). + arg(app->resourceMgr()->stringValue("ExternalBrowser", + platform)). + arg(aHelpFileName)); + } + +} +//============================================================================ +/*! Function : onApply + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onApply() +{ + if( !myTable->IsValid() ) + { + SUIT_MessageBox::warning( this, tr( "WARNING" ), tr( "INCORRECT_DATA" ) ); + return; + } + + double aDVal; + int anIVal; + bool aBVal; + + const QList& aRemovedRows = myTable->GetRemovedRows(); + const VariableMap& aVariableMap = myTable->GetVariableMap(); + const VariableMap& aVariableMapRef = myTable->GetVariableMapRef(); + + for( QListIterator anIter( aRemovedRows ); anIter.hasNext(); ) + { + int anIndex = anIter.next(); + if( aVariableMapRef.contains( anIndex ) ) + { + QString aRemovedVariable = aVariableMapRef[ anIndex ].Name; + myStudy->RemoveVariable( string( aRemovedVariable.toLatin1().constData() ) ); + } + } + + VariableMap::const_iterator it = aVariableMap.constBegin(), itEnd = aVariableMap.constEnd(); + for( ; it != itEnd; ++it ) + { + int anIndex = it.key(); + const NoteBoox_Variable& aVariable = it.value(); + QString aName = aVariable.Name; + QString aValue = aVariable.Value; + + if( !aName.isEmpty() && !aValue.isEmpty() ) + { + if( aVariableMapRef.contains( anIndex ) ) + { + const NoteBoox_Variable& aVariableRef = aVariableMapRef[ anIndex ]; + QString aNameRef = aVariableRef.Name; + QString aValueRef = aVariableRef.Value; + + if( !aNameRef.isEmpty() && !aValueRef.isEmpty() && aNameRef != aName ) + { + myStudy->RenameVariable( string( aNameRef.toLatin1().constData() ), + string( aName.toLatin1().constData() ) ); + } + } + + if( NoteBook_TableRow::IsIntegerValue(aValue,&anIVal) ) + myStudy->SetInteger(string(aName.toLatin1().constData()),anIVal); + + else if( NoteBook_TableRow::IsRealValue(aValue,&aDVal) ) + myStudy->SetReal(string(aName.toLatin1().constData()),aDVal); + + else if( NoteBook_TableRow::IsBooleanValue(aValue,&aBVal) ) + myStudy->SetBoolean(string(aName.toLatin1().constData()),aBVal); + } + } + myTable->ResetMaps(); + + SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); + if(app) + app->updateActions(); + +} + +//============================================================================ +/*! Function : onCancel + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onCancel() +{ + if( myTable->IsModified() ) + { + int answer = QMessageBox::question( this, tr( "CLOSE_CAPTION" ), tr( "CLOSE_DESCRIPTION" ), + QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel ); + switch( answer ) + { + case QMessageBox::Yes : onOK(); return; + case QMessageBox::No : break; + case QMessageBox::Cancel : return; + default : break; + } + } + reject(); +} + +//============================================================================ +/*! Function : onRemove + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onRemove() +{ + myTable->RemoveSelected(); +} + +//============================================================================ +/*! Function : onUpdateStudy + * Purpose : [slot] + */ +//============================================================================ +void SalomeApp_NoteBookDlg::onUpdateStudy() +{ + onApply(); + if( !myTable->IsValid() ) + return; + + QApplication::setOverrideCursor( Qt::WaitCursor ); + + if( !updateStudy() ) + SUIT_MessageBox::warning( this, tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) ); + + QApplication::restoreOverrideCursor(); +} + +//============================================================================ +/*! Function : updateStudy + * Purpose : + */ +//============================================================================ +bool SalomeApp_NoteBookDlg::updateStudy() +{ + SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); + if( !app ) + return false; + + SalomeApp_Study* study = dynamic_cast( app->activeStudy() ); + if( !study ) + return false; + + bool isStudySaved = study->isSaved(); + QString aStudyName = study->studyName(); + + _PTR(Study) studyDS = study->studyDS(); + + // get unique temporary directory name + QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() ); + if( aTmpDir.isEmpty() ) + return false; + + if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 ) + aTmpDir.remove( aTmpDir.length() - 1, 1 ); + + // dump study to the temporary directory + QString aFileName( "notebook" ); + bool toPublish = true; + bool toSaveGUI = true; + + int savePoint; + _PTR(AttributeParameter) ap; + _PTR(IParameters) ip = ClientFactory::getIParameters(ap); + if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag. + if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method + ip->setDumpPython(studyDS); + savePoint = SalomeApp_VisualState( app ).storeState(); //SRN: create a temporary save point + } + bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aFileName.toStdString(), toPublish ); + if ( toSaveGUI ) + study->removeSavePoint(savePoint); //SRN: remove the created temporary save point. + + if( !ok ) + return false; + + // clear a study (delete all objects) + clearStudy(); + + // get active application + app = dynamic_cast( SUIT_Session::session()->activeApplication() ); + + // load study from the temporary directory + QString command = QString( "execfile(\"%1\")" ).arg( aTmpDir + QDir::separator() + aFileName + ".py" ); + + PyConsole_Console* pyConsole = app->pythonConsole(); + if ( pyConsole ) + pyConsole->execAndWait( command ); + + // remove temporary directory + QDir aDir( aTmpDir ); + QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) ); + for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it ) + ok = aDir.remove( *it ) && ok; + if( ok ) + ok = aDir.rmdir( aTmpDir ); + + if( SalomeApp_Study* newStudy = dynamic_cast( app->activeStudy() ) ) + { + myStudy = newStudy->studyDS(); + myTable->Init(myStudy); + if(isStudySaved) { + newStudy->markAsSavedIn(aStudyName); + } + } + else + ok = false; + + return ok; +} + +//============================================================================ +/*! Function : clearStudy + * Purpose : + */ +//============================================================================ +void SalomeApp_NoteBookDlg::clearStudy() +{ + SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); + if( !app ) + return; + + QList aList = SUIT_Session::session()->applications(); + int anIndex = aList.indexOf( app ); + + //Store position and size of the this dialog + int aW = width(); + int aH = height(); + int aX = x(); + int aY = y(); + + // Disconnect dialog from application desktop in case if: + // 1) Application is not the first application in the session + // 2) Application is the first application in session but not the only. + bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1)); + + if( changeDesktop ) + setParent( 0 ); + + app->onCloseDoc( false ); + + if( anIndex > 0 && anIndex < aList.count() ) + app = dynamic_cast( aList[ anIndex - 1 ] ); + else if(anIndex == 0 && aList.count() > 1) + app = dynamic_cast( aList[ 1 ] ); + + if( !app ) + return; + + app->onNewDoc(); + + app = dynamic_cast( SUIT_Session::session()->activeApplication() ); + if( changeDesktop && app ) { + setParent( app->desktop(), Qt::Dialog ); + app->setNoteBook(this); + } + //Set position and size of the this dialog + resize( aW, aH ); + move( aX, aY ); + show(); +} diff --git a/src/SalomeApp/SalomeApp_NoteBookDlg.h b/src/SalomeApp/SalomeApp_NoteBookDlg.h new file mode 100644 index 000000000..431b50ced --- /dev/null +++ b/src/SalomeApp/SalomeApp_NoteBookDlg.h @@ -0,0 +1,172 @@ +// Copyright (C) 2008 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/ or email : webmaster.salome@opencascade.com +// +// File: SalomeApp_NoteBookDlg.h +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. +// Module : GUI + +#ifndef SALOMEAPP_NOTEBOOKDLG_H +#define SALOMEAPP_NOTEBOOKDLG_H + +#include "SalomeApp.h" + +#include "SALOMEDSClient_ClientFactory.hxx" +#include CORBA_SERVER_HEADER(SALOMEDS) + +#include +#include +#include + +class QWidget; +class QPushButton; +class QTableWidgetItem; + +struct NoteBoox_Variable +{ + NoteBoox_Variable() {} + NoteBoox_Variable( const QString& theName, const QString& theValue ) + { + Name = theName; + Value = theValue; + } + QString Name; + QString Value; +}; + +typedef QMap< int, NoteBoox_Variable > VariableMap; + +class SALOMEAPP_EXPORT NoteBook_TableRow : public QWidget +{ + public: + NoteBook_TableRow(int, QWidget* parent=0); + virtual ~NoteBook_TableRow(); + + int GetIndex() const { return myIndex; } + + void AddToTable(QTableWidget *theTable); + + void SetName(const QString theName); + void SetValue(const QString theValue); + + QString GetValue() const; + QString GetName() const; + + bool CheckName(); + bool CheckValue(); + + QTableWidgetItem* GetVariableItem(); + QTableWidgetItem* GetNameItem(); + QTableWidgetItem* GetHeaderItem(); + + static bool IsRealValue(const QString theValue, double* theResult = 0); + static bool IsIntegerValue(const QString theValue, int* theResult = 0); + static bool IsBooleanValue(const QString theValue, bool* theResult = 0); + + private: + int myIndex; + QTableWidgetItem* myRowHeader; + QTableWidgetItem* myVariableName; + QTableWidgetItem* myVariableValue; +}; + +class SALOMEAPP_EXPORT NoteBook_Table : public QTableWidget +{ + Q_OBJECT + public: + NoteBook_Table(QWidget * parent = 0); + virtual ~NoteBook_Table(); + + void Init(_PTR(Study) theStudy); + static QString Variable2String(const std::string& theVarName, + _PTR(Study) theStudy); + + bool IsValid() const; + + void AddRow( const QString& theName = QString::null, const QString& theValue = QString::null ); + void AddEmptyRow(); + NoteBook_TableRow* GetRowByItem(const QTableWidgetItem* theItem) const; + bool IsLastRow(const NoteBook_TableRow* aRow) const; + + void RemoveSelected(); + + void SetProcessItemChangedSignalFlag(const bool enable); + bool GetProcessItemChangedSignalFlag()const; + + bool IsUniqueName(const NoteBook_TableRow* theRow) const; + QList GetRows() const; + + const bool IsModified() const { return myIsModified; } + const QList& GetRemovedRows() const { return myRemovedRows; } + const VariableMap& GetVariableMap() const { return myVariableMap; } + const VariableMap& GetVariableMapRef() const { return myVariableMapRef; } + void RenamberRowItems(); + + void ResetMaps(); + + public slots: + void onItemChanged(QTableWidgetItem* theItem); + + private: + int getUniqueIndex() const; + + private: + bool isProcessItemChangedSignal; + QList myRows; + + bool myIsModified; + QList myRemovedRows; + VariableMap myVariableMapRef; + VariableMap myVariableMap; + + _PTR(Study) myStudy; +}; + +class SALOMEAPP_EXPORT SalomeApp_NoteBookDlg : public QDialog +{ + Q_OBJECT + public: + SalomeApp_NoteBookDlg(QWidget * parent , _PTR(Study) theStudy); + virtual ~SalomeApp_NoteBookDlg(); + + void Init(_PTR(Study) theStudy); + + public slots: + void onOK(); + void onApply(); + void onCancel(); + void onRemove(); + void onUpdateStudy(); + void onHelp(); + + protected: + bool updateStudy(); + void clearStudy(); + + private: + NoteBook_Table* myTable; + QPushButton* myRemoveButton; + QPushButton* myUpdateStudyBtn; + QPushButton* myOkBtn; + QPushButton* myApplyBtn; + QPushButton* myCancelBtn; + QPushButton* myHelpBtn; + + _PTR(Study) myStudy; +}; + +#endif //SALOMEAPP_NOTEBOOKDLG_H diff --git a/src/SalomeApp/SalomeApp_Study.cxx b/src/SalomeApp/SalomeApp_Study.cxx index 6183c679f..1c040af7d 100644 --- a/src/SalomeApp/SalomeApp_Study.cxx +++ b/src/SalomeApp/SalomeApp_Study.cxx @@ -592,6 +592,16 @@ void SalomeApp_Study::RemoveTemporaryFiles ( const char* theModuleName, const bo } } +/*! + Mark the study as saved in the file + \param theFileName - the name of file +*/ +void SalomeApp_Study::markAsSavedIn(QString theFileName) +{ + setStudyName(theFileName); + setIsSaved(true); +} + /*! Deletes all references to object \param obj - object diff --git a/src/SalomeApp/SalomeApp_Study.h b/src/SalomeApp/SalomeApp_Study.h index bc19f4ee9..217423d1a 100644 --- a/src/SalomeApp/SalomeApp_Study.h +++ b/src/SalomeApp/SalomeApp_Study.h @@ -77,6 +77,7 @@ public: virtual std::string getVisualComponentName(); virtual void restoreState(int savePoint); + void markAsSavedIn(QString theFileName); protected: virtual void saveModuleData ( QString theModuleName, QStringList theListOfFiles ); diff --git a/src/SalomeApp/resources/SalomeApp_msg_en.ts b/src/SalomeApp/resources/SalomeApp_msg_en.ts index 550e5a0e1..2252e9a2a 100644 --- a/src/SalomeApp/resources/SalomeApp_msg_en.ts +++ b/src/SalomeApp/resources/SalomeApp_msg_en.ts @@ -80,6 +80,18 @@ REFENTRY_COLUMN Ref.Entry + + ERR_INCOMPATIBLE_TYPE + Variable with name "%1" has incompatible numeric type + + + ERR_INVALID_VALUE + Value hasn't been validated + + + ERR_NO_VARIABLE + Variable with name "%1" doesn't exist + SalomeApp_Application @@ -264,6 +276,18 @@ Do you want to reload it ? PRP_DESK_FILE_DUMP_STUDY Dumps study to the python script + + TOT_DESK_FILE_NOTEBOOK + Open Notebook + + + MEN_DESK_FILE_NOTEBOOK + Noteboo&k... + + + PRP_DESK_FILE_NOTEBOOK + Open Notebook + TOT_DESK_PROPERTIES Study properties @@ -351,4 +375,77 @@ Do you want to reload it ? Shutdown standalone servers + + NoteBook_Table + + REMOVE_VARIABLE_IS_USED + Variable with name "%1" is used in the study. +Do you really want to remove it? + + + RENAME_VARIABLE_IS_USED + Variable with name "%1" is used in the study. +Do you really want to rename it? + + + VARNAME_COLUMN + Variable Name + + + VARVALUE_COLUMN + Variable Value + + + VARVALUE_INCORRECT + Variable Value Incorrect: %1 + + + VARNAME_INCORRECT + Valiable Name Incorrect :%1 + + + VARNAME_EXISTS + Valiable with name "%1" exists + + + + SalomeApp_NoteBookDlg + + NOTEBOOK_TITLE + Salome NoteBook + + + BUT_UPDATE_STUDY + &Update Study + + + BUT_REMOVE + &Remove + + + BUT_APPLY_AND_CLOSE + A&pply and Close + + + BUT_HELP + &Help + + + CLOSE_CAPTION + Close NoteBook + + + CLOSE_DESCRIPTION + Do you want to save changes you made to NoteBook? + + + INCORRECT_DATA + At least one variable has been defined incorrectly. +Please edit its parameters or remove it from table. + + + ERR_UPDATE_STUDY_FAILED + Failed to update study! + + -- 2.39.2