X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FSalomeApp%2FSalomeApp_DataModel.cxx;h=8edc66316de2ccd6127e44c3451a42aac18da1e2;hb=cc14dfe0c087d1459c8b593ad7d262ddec495603;hp=1d771e2c64cd96249256d87d51eb2f7f40adf2c2;hpb=9a1c1c0754258f14a4158e9a004ff15262a1e716;p=modules%2Fgui.git diff --git a/src/SalomeApp/SalomeApp_DataModel.cxx b/src/SalomeApp/SalomeApp_DataModel.cxx index 1d771e2c6..8edc66316 100644 --- a/src/SalomeApp/SalomeApp_DataModel.cxx +++ b/src/SalomeApp/SalomeApp_DataModel.cxx @@ -1,265 +1,419 @@ +// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// 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_DataModel.cxx // Created: 10/25/2004 10:36:06 AM // Author: Sergey LITONIN -// Copyright (C) CEA 2004 #include "SalomeApp_DataModel.h" #include "SalomeApp_Study.h" -#include "SalomeApp_RootObject.h" #include "SalomeApp_DataObject.h" #include "SalomeApp_Module.h" #include "SalomeApp_Application.h" -#include "SalomeApp_SelectionMgr.h" -#include "SalomeApp_Engine_i.hxx" #include -#include -#include -#include - -#include "SALOMEDS_Tool.hxx" +#include +#include #include #include CORBA_SERVER_HEADER(SALOME_Exception) -//======================================================================= -// name : BuildTree -// Purpose : static method used by SalomeApp_Study and SalomeApp_DataModel classes -// to create default SALOMEDS-based data object tree -//======================================================================= -SUIT_DataObject* SalomeApp_DataModel::BuildTree( const _PTR(SObject)& obj, - SUIT_DataObject* parent, - SalomeApp_Study* study, - bool skip ) +typedef _PTR(SObject) kerPtr; +typedef SUIT_DataObject* suitPtr; + +/*! + \class SalomeApp_DataModelSync + Auxiliary class for synchronizing tree of kernel objects and SUIT_DataObjects +*/ +class SalomeApp_DataModelSync +{ +public: + SalomeApp_DataModelSync( _PTR( Study ), SUIT_DataObject* ); + + bool isEqual( const kerPtr&, const suitPtr& ) const; + kerPtr nullSrc() const; + suitPtr nullTrg() const; + suitPtr createItem( const kerPtr&, const suitPtr&, const suitPtr& ) const; + void updateItem( const kerPtr&, const suitPtr& ) const; + void deleteItemWithChildren( const suitPtr& ) const; + QList children( const kerPtr& ) const; + QList children( const suitPtr& ) const; + suitPtr parent( const suitPtr& ) const; + +private: + bool isCorrect( const kerPtr& ) const; + +private: + _PTR( Study ) myStudy; + SUIT_DataObject* myRoot; +}; + +/*! + Constructor +*/ +SalomeApp_DataModelSync::SalomeApp_DataModelSync( _PTR( Study ) aStudy, SUIT_DataObject* aRoot ) +: myStudy( aStudy ), + myRoot( aRoot ) { - SalomeApp_DataObject* aDataObj = 0; - if ( !obj || !study ) - return aDataObj; +} - _PTR(SObject) refObj; - if ( obj->GetName().size() || obj->ReferencedObject( refObj ) ) // skip nameless non references SObjects +/*! + \return true if kernel object is correct (has non empty name or is reference) +*/ +bool SalomeApp_DataModelSync::isCorrect( const kerPtr& so ) const +{ +#ifdef WITH_SALOMEDS_OBSERVER + // with GUI observers this function is not needed anymore + return true; +#endif + kerPtr refObj; + QString name = so->GetName().c_str(); + _PTR( GenericAttribute ) anAttr; + bool isDraw = true; + if ( so->FindAttribute(anAttr, "AttributeDrawable") ) { - _PTR(SComponent) aSComp( obj ); + _PTR(AttributeDrawable) aAttrDraw = anAttr; + isDraw = aAttrDraw->IsDrawable(); + } + bool res = so && ( so->GetName().size() || so->ReferencedObject( refObj ) ) && isDraw; + return res; +} - // patch for bug IPAL9313 - if ( aSComp && parent && skip ) - { - QString aSName( aSComp->GetName().c_str() ); - DataObjectList allComponents = parent->children( /*recursive=*/false ); - for ( DataObjectListIterator it( allComponents ); it.current(); ++it ) { - SUIT_DataObject* componentObj = it.current(); - if ( componentObj->name() == aSName ) { - //mkr : modifications for update already published in - //object browser, but not loaded yet component - //get names list of loaded modules - QStringList aLoadedModNames; - CAM_Application* anApp = dynamic_cast( SUIT_Session::session()->activeApplication() ); - if ( anApp ) anApp->modules( aLoadedModNames, /*loaded*/true ); - if ( !aLoadedModNames.isEmpty() && aLoadedModNames.contains( aSName ) == 0 ) { - // delete DataObject and re-create it and all its sub-objects - delete componentObj; - // don't do anything here, because iterator may be corrupted (deleted object inside it) - break; - } - else - return componentObj; - } - } - } +/*! + Creates SUIT object by KERNEL object + \param so - corresponding KERNEL object + \param parent - parent for SUIT object + \param after - previous sibling for SUIT object + \param prepend - SUIT object must be added to start of children list +*/ +suitPtr SalomeApp_DataModelSync::createItem( const kerPtr& so, + const suitPtr& parent, + const suitPtr& after ) const +{ + if( !isCorrect( so ) ) + return 0; - aDataObj = aSComp ? new SalomeApp_ModuleObject( aSComp, parent ) : - new SalomeApp_DataObject ( obj, parent ); + _PTR(SComponent) aSComp( so ); + suitPtr nitem = aSComp ? new SalomeApp_ModuleObject( aSComp, 0 ) : + new SalomeApp_DataObject( so, 0 ); - _PTR(ChildIterator) it ( study->studyDS()->NewChildIterator( obj ) ); - for ( ; it->More();it->Next() ) { - // don't use shared_ptr here, for Data Object will take - // ownership of this pointer - _PTR(SObject) aSO( it->Value() ); - BuildTree( aSO, aDataObj, study ); - } + if( parent ) { + int pos = after ? parent->childPos( after ) : 0; + parent->insertChild( nitem, pos+1 ); } - return aDataObj; + else if( myRoot ) { + myRoot->appendChild( nitem ); + } + return nitem; } -//======================================================================= -// name : SalomeApp_DataModel::SalomeApp_DataModel -// Purpose : Constructor -//======================================================================= -SalomeApp_DataModel::SalomeApp_DataModel( CAM_Module* theModule ) -: CAM_DataModel( theModule ) +/*! + Deletes object with all children + \param p - SUIT object +*/ +void SalomeApp_DataModelSync::deleteItemWithChildren( const suitPtr& p ) const { + if( !p ) + return; + + DataObjectList ch; + p->children( ch ); + DataObjectList::const_iterator anIt = ch.begin(), aLast = ch.end(); + for( ; anIt!=aLast; anIt++ ) + deleteItemWithChildren( *anIt ); + delete p; } -//======================================================================= -// name : SalomeApp_DataModel::~SalomeApp_DataModel -// Purpose : Destructor -//======================================================================= -SalomeApp_DataModel::~SalomeApp_DataModel() +/*! + \return true if objects correspond each other at all + \param p - kernel object + \param q - suit object +*/ +bool SalomeApp_DataModelSync::isEqual( const kerPtr& p, const suitPtr& q ) const { + LightApp_ModuleObject* lobj = dynamic_cast( q ); + SalomeApp_DataObject* sobj = dynamic_cast( q ); + _PTR( SComponent ) aComp( p ); + bool res = ( !p && !q ) || + ( lobj && !sobj && aComp ) || + ( sobj && isCorrect( p ) && p->GetID().c_str()==sobj->entry() ); + return res; } -//================================================================ -// Function : open -// Purpose : -//================================================================ -bool SalomeApp_DataModel::open( const QString&, CAM_Study* study ) +/*! + \return null kernel object +*/ +kerPtr SalomeApp_DataModelSync::nullSrc() const { - SalomeApp_Study* aDoc = dynamic_cast( study ); - if ( !aDoc ) - return false; + return kerPtr(); +} - QString anId = getRootEntry( aDoc ); - if ( anId.isEmpty() ) - return true; // Probably nothing to load +/*! + \return null suit object +*/ +suitPtr SalomeApp_DataModelSync::nullTrg() const +{ + return 0; +} - QString anEngine = getModule()->engineIOR(); - if ( anEngine == "-1" ) { - // Module doesn't have a CORBA engine and doesn't use - // a default one -> SALOMEDS persistence cannot be used - return false; +/*! + Fills list with children of kernel object + \param obj - kernel object + \param ch - list to be filled +*/ +QList SalomeApp_DataModelSync::children( const kerPtr& obj ) const +{ + QList ch; + + _PTR( GenericAttribute ) anAttr; + bool expandable = true; + if ( obj && obj->FindAttribute( anAttr, "AttributeExpandable" ) ) { + _PTR(AttributeExpandable) aAttrExp = anAttr; + expandable = aAttrExp->IsExpandable(); } - if ( anEngine.isEmpty() ) { - // Module use a default engine - //TODO: deside, if the below code has to be copyed in a light data model to avoid bulding of data tree twice - anEngine = SalomeApp_Application::defaultEngineIOR(); + if ( expandable ) { + // tmp?? + _PTR(UseCaseBuilder) aUseCaseBuilder = myStudy->GetUseCaseBuilder(); + if (aUseCaseBuilder->HasChildren(obj)) { + _PTR(UseCaseIterator) it ( aUseCaseBuilder->GetUseCaseIterator( obj ) ); + for ( ; it->More(); it->Next() ) + ch.append( it->Value() ); + } + else { + _PTR(ChildIterator) it ( myStudy->NewChildIterator( obj ) ); + for ( ; it->More(); it->Next() ) + ch.append( it->Value() ); + } } - _PTR(Study) aStudy ( aDoc->studyDS() ); // shared_ptr cannot be used here - _PTR(SComponent) aSComp ( aStudy->FindComponentID( std::string( anId.latin1() ) ) ); + return ch; +} - if ( aSComp ) { - _PTR(StudyBuilder) aBuilder( aStudy->NewBuilder() ); - if ( aBuilder ) { - try { - aBuilder->LoadWith( aSComp, std::string( anEngine.latin1() ) ); - } - catch( const SALOME::SALOME_Exception& ) { - // Oops, something went wrong while loading -> return an error - return false; - } +/*! + Fills list with children of SUIT object + \param p - SUIT object + \param ch - list to be filled +*/ +QList SalomeApp_DataModelSync::children( const suitPtr& p ) const +{ + QList ch; + if ( p ) + ch = p->children(); + return ch; +} - // Something has been read -> create data model tree - buildTree( aSComp, 0, aDoc ); - } - } else { - // Don't return false here, for there might be no data - // for a given component in the study yet +/*! + \return parent of SUIT object + \param p - SUIT object +*/ +suitPtr SalomeApp_DataModelSync::parent( const suitPtr& p ) const +{ + return p ? p->parent(): 0; +} + +/*! + Updates SUIT object + \param p - SUIT object +*/ +void SalomeApp_DataModelSync::updateItem( const kerPtr&, const suitPtr& ) const +{ +} + +/*! + Auxiliary function, shows SUIT tree +*/ +void showTree( SUIT_DataObject* root ) +{ + qDebug( root ? "" : "" ); + if( !root ) + return; + + SUIT_DataObjectIterator it( root, SUIT_DataObjectIterator::DepthLeft ); + for( ; it.current(); ++it ) + { + QString marg; marg.fill( ' ', 3*it.depth() ); + QString nnn = "%1 '%2'"; + qDebug( nnn.arg( marg ).arg( it.current()->name() ).toUtf8() ); } +} - emit opened(); //TODO: is it really needed? to be removed maybe... - return true; +/*! + Constructor +*/ +SalomeApp_DataModel::SalomeApp_DataModel( CAM_Module* theModule ) +: LightApp_DataModel( theModule ) +{ } -//================================================================ -// Function : save -// Purpose : -//================================================================ -bool SalomeApp_DataModel::save() +/*! + Destructor +*/ +SalomeApp_DataModel::~SalomeApp_DataModel() { - emit saved(); - return true; } -//================================================================ -// Function : saveAs -// Purpose : -//================================================================ -bool SalomeApp_DataModel::saveAs( const QString&, CAM_Study* ) +/*! + Opens data model +*/ +bool SalomeApp_DataModel::open( const QString& name, CAM_Study* study, QStringList ) { - emit saved(); + SalomeApp_Study* aDoc = dynamic_cast( study ); + if ( !aDoc ) + return false; + + QString anId = getRootEntry( aDoc ); + if ( anId.isEmpty() ) + return true; // Probably nothing to load + + _PTR(SComponent) aSComp ( SalomeApp_Application::getStudy()->FindComponentID( std::string( anId.toUtf8() ) ) ); + if ( aSComp ) + updateTree( aSComp, aDoc ); + + QStringList listOfFiles; + LightApp_DataModel::open(name, study, listOfFiles); return true; } -//================================================================ -// Function : close -// Purpose : -//================================================================ -bool SalomeApp_DataModel::close() +/*! + Creates data model +*/ +bool SalomeApp_DataModel::create( CAM_Study* theStudy ) { - emit closed(); + update(NULL, (LightApp_Study*)theStudy); return true; } -//================================================================ -// Function : update -// Purpose : -//================================================================ -void SalomeApp_DataModel::update( SalomeApp_DataObject*, SalomeApp_Study* study ) +/*! + Updates application. +*/ +void SalomeApp_DataModel::update( LightApp_DataObject*, LightApp_Study* study ) { - SalomeApp_RootObject* studyRoot = 0; - _PTR(SObject) sobj; + SalomeApp_Study* aSStudy = dynamic_cast(study); + LightApp_RootObject* studyRoot = 0; + _PTR(SComponent) sobj; SalomeApp_DataObject* modelRoot = dynamic_cast( root() ); if ( !modelRoot ){ // not yet connected to a study -> try using argument - if ( !study ) - study = dynamic_cast( getModule()->getApp()->activeStudy() ); - - if ( study ){ - studyRoot = dynamic_cast( study->root() ); - QString anId = getRootEntry( study ); + if ( !aSStudy ) + aSStudy = dynamic_cast( getModule()->getApp()->activeStudy() ); + if ( aSStudy ){ + studyRoot = dynamic_cast( aSStudy->root() ); + QString anId = getRootEntry( aSStudy ); if ( !anId.isEmpty() ){ // if nothing is published in the study for this module -> do nothing - _PTR(Study) aStudy ( study->studyDS() ); - sobj = aStudy->FindComponentID( std::string( anId.latin1() ) ); + sobj = SalomeApp_Application::getStudy()->FindComponentID( std::string( anId.toUtf8() ) ); } } } else{ - studyRoot = dynamic_cast( modelRoot->root() ); - study = studyRoot->study(); // value should not change here theoretically, but just to make sure - _PTR(Study) aStudy ( study->studyDS() ); - - // modelRoot->object() cannot be reused here: it is about to be deleted by buildTree() soon - sobj = aStudy->FindComponentID( std::string( modelRoot->entry().latin1() ) ); + studyRoot = dynamic_cast( modelRoot->root() ); + if ( studyRoot ) { + aSStudy = dynamic_cast( studyRoot->study() ); // value should not change here theoretically, but just to make sure + if ( aSStudy ) { + // modelRoot->object() cannot be reused here: it is about to be deleted by buildTree() soon + sobj = SalomeApp_Application::getStudy()->FindComponentID( std::string( modelRoot->entry().toUtf8() ) ); + } + } } - buildTree( sobj, studyRoot, study ); + if ( sobj && aSStudy ) + updateTree( sobj, aSStudy ); } -//================================================================ -// Function : buildTree -// Purpose : private method -//================================================================ -void SalomeApp_DataModel::buildTree( const _PTR(SObject)& obj, - SUIT_DataObject* parent, - SalomeApp_Study* study ) +/*! + Synchronizes kernel tree and suit data tree starting from component 'sobj' +*/ +SUIT_DataObject* SalomeApp_DataModel::synchronize( const _PTR( SComponent )& sobj, SalomeApp_Study* study ) { - if ( !obj ) - return; - //if ( !root() ){ // Build default SALOMEDS-based data object tree and insert it into study - SalomeApp_ModuleObject* aNewRoot = dynamic_cast( BuildTree( obj, parent, study ) ); - if ( aNewRoot ){ - aNewRoot->setDataModel( this ); - setRoot( aNewRoot ); + if( !study || !study->root() || !sobj ) + return 0; + + DataObjectList ch; study->root()->children( ch ); + DataObjectList::const_iterator anIt = ch.begin(), aLast = ch.end(); + SUIT_DataObject* suitObj = 0; + for( ; anIt!=aLast; anIt++ ) + { + LightApp_DataObject* dobj = dynamic_cast( *anIt ); + if( dobj && dobj->name() == sobj->GetName().c_str() ) + { + suitObj = dobj; + break; } - //} + } + +#ifdef WITH_SALOMEDS_OBSERVER + SalomeApp_RootObject* root=dynamic_cast(study->root()); + if(!(root->toSynchronize())) + return suitObj; +#endif + + SalomeApp_DataModelSync sync( study->studyDS(), study->root() ); + + if( !suitObj || dynamic_cast( suitObj ) ) + suitObj= ::synchronize( sobj, suitObj, sync ); + else + suitObj= 0; + + return suitObj; } -//================================================================ -// Function : getModule -// Purpose : -//================================================================ +/*! + Updates tree. +*/ +void SalomeApp_DataModel::updateTree( const _PTR( SComponent )& comp, SalomeApp_Study* study ) +{ + SalomeApp_ModuleObject* aNewRoot = dynamic_cast( synchronize( comp, study ) ); + if( aNewRoot ) + { + aNewRoot->setDataModel( this ); + setRoot( aNewRoot ); + } +} +/*! + \return module +*/ SalomeApp_Module* SalomeApp_DataModel::getModule() const { return dynamic_cast( module() ); } -//================================================================ -// Function : getStudy -// Purpose : -//================================================================ +/*! + \return study +*/ SalomeApp_Study* SalomeApp_DataModel::getStudy() const { - SalomeApp_RootObject* aRoot = dynamic_cast( root()->root() ); + if(!root()) return 0; + LightApp_RootObject* aRoot = dynamic_cast( root()->root() ); if ( !aRoot ) return 0; - return aRoot->study(); + SalomeApp_Study* aStudy = dynamic_cast( aRoot->study() ); + if ( !aStudy ) + return 0; + return aStudy; } -//================================================================ -// Function : getRootEntry -// Purpose : returns study entry corresponding to this data model -//================================================================ +/*! + \return study entry corresponding to this data model +*/ QString SalomeApp_DataModel::getRootEntry( SalomeApp_Study* study ) const { QString anEntry; @@ -269,105 +423,9 @@ QString SalomeApp_DataModel::getRootEntry( SalomeApp_Study* study ) const anEntry = anObj->entry(); } else if ( study && study->studyDS() ) { // this works even if is null - _PTR(SComponent) aSComp( study->studyDS()->FindComponent( module()->name() ) ); + _PTR(SComponent) aSComp( study->studyDS()->FindComponent( module()->name().toStdString() ) ); if ( aSComp ) anEntry = aSComp->GetID().c_str(); } return anEntry; } - -//================================================================ -// Function : isModified -// Purpose : default implementation, always returns false so as not to mask study's isModified() -//================================================================ -bool SalomeApp_DataModel::isModified() const -{ - return false; -} - -//================================================================ -// Function : isSaved -// Purpose : default implementation, always returns true so as not to mask study's isSaved() -//================================================================ -bool SalomeApp_DataModel::isSaved() const -{ - return true; -} - -// BEGIN: methods to be used by CORBAless modules - -//================================================================ -// Function : GetListOfFiles -// Purpose : to be used by CORBAless modules -//================================================================ -std::vector SalomeApp_DataModel::GetListOfFiles() const - //(const int theStudyId, const char* theComponentName) const -{ - SUIT_Study* anActiveStudy = getModule()->getApp()->activeStudy(); - if (anActiveStudy) { - int aStudyId = anActiveStudy->id(); - SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance(); - if (aDefaultEngine) { - return aDefaultEngine->GetListOfFiles(aStudyId, module()->name()); - } - } - - std::vector aListOfFiles; - return aListOfFiles; -} - -//================================================================ -// Function : SetListOfFiles -// Purpose : to be used by CORBAless modules -//================================================================ -void SalomeApp_DataModel::SetListOfFiles (const std::vector theListOfFiles) - //(const std::vector theListOfFiles, - // const int theStudyId, - // const char* theComponentName) -{ - SUIT_Study* anActiveStudy = getModule()->getApp()->activeStudy(); - if (anActiveStudy) { - int aStudyId = anActiveStudy->id(); - SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance(); - if (aDefaultEngine) { - aDefaultEngine->SetListOfFiles(theListOfFiles, aStudyId, module()->name()); - } - } -} - -//================================================================ -// Function : GetTmpDir -// Purpose : Static method. To be used by CORBAless modules -//================================================================ -std::string SalomeApp_DataModel::GetTmpDir (const char* theURL, - const bool isMultiFile) -{ - std::string anURLDir = SALOMEDS_Tool::GetDirFromPath(theURL); - std::string aTmpDir = isMultiFile ? anURLDir : SALOMEDS_Tool::GetTmpDir(); - return aTmpDir; -} - -//================================================================ -// Function : RemoveTemporaryFiles -// Purpose : to be used by CORBAless modules -//================================================================ -void SalomeApp_DataModel::RemoveTemporaryFiles (const bool isMultiFile) const -{ - if (isMultiFile) - return; - - std::vector aListOfFiles = GetListOfFiles(); - if (aListOfFiles.size() > 0) { - std::string aTmpDir = aListOfFiles[0]; - - const int n = aListOfFiles.size() - 1; - SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames; - aSeq->length(n); - for (int i = 0; i < n; i++) - aSeq[i] = CORBA::string_dup(aListOfFiles[i + 1].c_str()); - - SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true); - } -} - -// END: methods to be used by CORBAless modules