Back to index

salome-gui  6.5.0
CAM_Application.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 #include "CAM_Application.h"
00024 
00025 #include "CAM_Study.h"
00026 #include "CAM_Module.h"
00027 
00028 #include <SUIT_Tools.h>
00029 #include <SUIT_Desktop.h>
00030 #include <SUIT_Session.h>
00031 #include <SUIT_MessageBox.h>
00032 #include <SUIT_ResourceMgr.h>
00033 
00034 #include <KERNEL_version.h>
00035 #include <GUI_version.h>
00036 
00037 #include <QApplication>
00038 #include <QRegExp>
00039 
00040 #ifdef WIN32
00041 #include <windows.h>
00042 #else
00043 #include <dlfcn.h>
00044 #endif
00045 
00046 #include <cstdio>
00047 
00048 namespace
00049 {
00050 class BusyLocker
00051 {
00052 public:
00053   BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
00054   ~BusyLocker() { myBusy = myPrev; }
00055 private:
00056   bool  myPrev;
00057   bool& myBusy;
00058 };
00059 }
00060 
00065 extern "C" CAM_EXPORT SUIT_Application* createApplication()
00066 {
00067   return new CAM_Application();
00068 }
00069 
00095 CAM_Application::CAM_Application( const bool autoLoad )
00096 : STD_Application(),
00097   myModule( 0 ),
00098   myAutoLoad( autoLoad ),
00099   myBlocked( false )
00100 {
00101   readModuleList();
00102 }
00103 
00109 CAM_Application::~CAM_Application()
00110 {
00111   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
00112     delete *it;
00113   myModules.clear();
00114 }
00115 
00123 void CAM_Application::start()
00124 {
00125   if ( myAutoLoad )
00126     loadModules();
00127 
00128   STD_Application::start();
00129 }
00130 
00135 CAM_Module* CAM_Application::activeModule() const
00136 {
00137   return myModule;
00138 }
00139 
00144 CAM_Module* CAM_Application::module(  const QString& modName ) const
00145 {
00146   CAM_Module* mod = 0;
00147   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
00148         it != myModules.end() && !mod; ++it )
00149     if ( (*it)->moduleName() == modName )
00150       mod = *it;
00151   return mod;
00152 }
00153 
00158 CAM_Application::ModuleList CAM_Application::modules() const
00159 {
00160   return myModules;
00161 }
00162 
00167 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
00168 {
00169   out.clear();
00170 
00171   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
00172         it != myModules.end(); ++it )
00173     out.append( *it );
00174 }
00175 
00185 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
00186 {
00187   lst.clear();
00188 
00189   if ( loaded )
00190   {
00191     for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
00192           it != myModules.end(); ++it )
00193       lst.append( (*it)->moduleName() );
00194   }
00195   else
00196   {
00197     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
00198           it != myInfoList.end(); ++it )
00199       lst.append( (*it).title );
00200   }
00201 }
00202 
00212 void CAM_Application::addModule( CAM_Module* mod )
00213 {
00214   if ( !mod || myModules.contains( mod ) )
00215     return;
00216 
00217   mod->initialize( this );
00218 
00219   QMap<CAM_Module*, int> map;
00220 
00221   ModuleList newList;
00222   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
00223         it != myInfoList.end(); ++it )
00224   {
00225     if ( (*it).title == mod->moduleName() )
00226       newList.append( mod );
00227     else
00228     {
00229       CAM_Module* curMod = module( (*it).title );
00230       if ( curMod )
00231         newList.append( curMod );
00232     }
00233   }
00234 
00235   for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
00236         it != myModules.end(); ++it )
00237   {
00238     if ( !newList.contains( *it ) )
00239       newList.append( *it );
00240   }
00241 
00242   if ( !newList.contains( mod ) )
00243       newList.append( mod );
00244 
00245   myModules = newList;
00246 
00247   moduleAdded( mod );
00248 }
00249 
00255 void CAM_Application::loadModules()
00256 {
00257   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
00258   {
00259     if ( !isModuleAccessible( (*it).title ) ) {
00260       continue;
00261     }
00262     CAM_Module* mod = loadModule( (*it).title );
00263     if ( mod )
00264       addModule( mod );
00265     else {
00266       QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
00267       if ( desktop() && desktop()->isVisible() )
00268         SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
00269       else
00270         qWarning( qPrintable( wrn ) ); 
00271     }
00272   }
00273 }
00274 
00286 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
00287 {
00288   if ( myInfoList.isEmpty() )
00289   {
00290     qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
00291     return 0;
00292   }
00293 
00294   if ( !isModuleAccessible( modName ) ) {
00295     qWarning( qPrintable( tr( "Module \"%1\" cannot be loaded in this application." ).arg( modName ) ) );
00296     return 0;
00297   }
00298 
00299   QString libName = moduleLibrary( modName );
00300   if ( libName.isEmpty() )
00301   {
00302     qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
00303     return 0;
00304   }
00305 
00306   QString err;
00307   GET_MODULE_FUNC crtInst = 0;
00308   GET_VERSION_FUNC getVersion = 0;
00309 
00310 #ifdef WIN32
00311   HINSTANCE modLib = ::LoadLibrary( libName.toLatin1() ); 
00312   if ( !modLib )
00313   {
00314     LPVOID lpMsgBuf;
00315     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
00316                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
00317     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
00318     ::LocalFree( lpMsgBuf );
00319   }
00320   else
00321   {
00322     crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
00323     if ( !crtInst )
00324     {
00325       LPVOID lpMsgBuf;
00326       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
00327                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
00328     err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
00329     ::LocalFree( lpMsgBuf );
00330     }
00331 
00332     getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
00333   }
00334 #else
00335   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY );
00336   if ( !modLib )
00337     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
00338   else
00339   {
00340     crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
00341     if ( !crtInst )
00342       err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
00343 
00344     getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
00345   }
00346 #endif
00347 
00348   CAM_Module* module = crtInst ? crtInst() : 0;
00349   if ( module )
00350   {
00351     module->setModuleName( modName );
00352     module->setName( moduleName( modName ) );
00353   }
00354 
00355   if ( !err.isEmpty() && showMsg ) {
00356     if ( desktop() && desktop()->isVisible() )
00357       SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
00358     else
00359       qWarning( qPrintable( err ) ); 
00360   }
00361 
00362   char* version = getVersion ? getVersion() : 0;
00363 
00364   if(version) {    
00365     for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
00366       if ( (*it).title == modName ) {
00367         if( (*it).version.isEmpty() ) {
00368           (*it).version = QString(version);
00369         }
00370         break;
00371       }
00372     }
00373   }
00374   
00375   return module;
00376 }
00377 
00383 bool CAM_Application::activateModule( const QString& modName )
00384 {
00385   if ( !modName.isEmpty() && !activeStudy() || myBlocked )
00386     return false;
00387 
00388   // VSR 25/10/2011: prevent nested activation/deactivation
00389   // See issues 0021307, 0021373
00390   BusyLocker lock( myBlocked );
00391 
00392   bool res = false;
00393   if ( !modName.isEmpty() )
00394   {
00395     CAM_Module* mod = module( modName );
00396     if ( !mod && !moduleLibrary( modName ).isEmpty() )
00397     {
00398       mod = loadModule( modName );
00399       addModule( mod );
00400     }
00401 
00402     if ( mod )
00403       res = activateModule( mod );
00404   }
00405   else
00406     res = activateModule( 0 );
00407 
00408   return res;
00409 }
00410 
00419 bool CAM_Application::activateModule( CAM_Module* mod )
00420 {
00421   if ( mod && !activeStudy() )
00422     return false;
00423 
00424   if ( myModule == mod )
00425     return true;
00426 
00427   if ( myModule )
00428   {
00429     if ( !myModule->deactivateModule( activeStudy() ) )
00430     {
00431       // ....      
00432     }    
00433   }     
00434   myModule = mod;
00435 
00436   if ( myModule ){
00437     // Connect the module to the active study
00438     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
00439     if ( !myModule->activateModule( activeStudy() ) )
00440     {
00441       myModule->setMenuShown( false );
00442       myModule->setToolShown( false );
00443       QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
00444       if ( desktop() && desktop()->isVisible() )
00445         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
00446       else
00447         qWarning( qPrintable( wrn ) ); 
00448       myModule = 0;
00449       return false;
00450     }
00451   }
00452 
00453   updateCommandsStatus();
00454 
00455   return true;
00456 }
00457 
00462 SUIT_Study* CAM_Application::createNewStudy() 
00463 { 
00464   return new CAM_Study( this );
00465 }
00466 
00470 void CAM_Application::updateCommandsStatus()
00471 {
00472   STD_Application::updateCommandsStatus();
00473 
00474   if ( activeModule() )
00475     activeModule()->updateCommandsStatus();
00476 }
00477 
00485 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
00486 {
00487   for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
00488     (*it)->studyClosed( theDoc );
00489 }
00490 
00491 void CAM_Application::afterCloseDoc()
00492 {
00493 }
00494 
00499 void CAM_Application::setActiveStudy( SUIT_Study* study )
00500 {
00501   STD_Application::setActiveStudy( study );
00502 }
00503 
00512 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
00513 {
00514 }
00515 
00521 QString CAM_Application::moduleName( const QString& title ) const
00522 {
00523   QString res;
00524   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
00525   {
00526     if ( (*it).title == title )
00527       res = (*it).name;
00528   }
00529   return res;
00530 }
00531 
00537 QString CAM_Application::moduleTitle( const QString& name ) const
00538 {
00539   QString res;
00540   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
00541   {
00542     if ( (*it).name == name )
00543       res = (*it).title;
00544   }
00545   return res;
00546 }
00547 
00553 QString CAM_Application::moduleIcon( const QString& name ) const
00554 {
00555   QString res;
00556   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
00557   {
00558     if ( (*it).name == name )
00559       res = (*it).icon;
00560   }
00561   return res;
00562 }
00563 
00571 bool CAM_Application::isModuleAccessible( const QString& title ) const
00572 {
00573   bool found   = false;
00574   bool blocked = false;
00575   
00576   QStringList somewhereLoaded;
00577   QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
00578   foreach( SUIT_Application* app, apps ) {
00579     CAM_Application* camApp = dynamic_cast<CAM_Application*>( app );
00580     if ( !camApp ) continue;
00581     QStringList loaded;
00582     camApp->modules( loaded, true );
00583     foreach( QString lm, loaded ) {
00584       if ( !somewhereLoaded.contains( lm ) ) somewhereLoaded << lm;
00585     }
00586   }
00587 
00588   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && !found; ++it )
00589   {
00590     found = (*it).title == title;
00591     blocked = (*it).isSingleton && somewhereLoaded.contains((*it).title);
00592   }
00593   return found && !blocked;
00594 }
00595 
00602 QString CAM_Application::moduleLibrary( const QString& title, const bool full ) const
00603 {
00604   QString res;
00605   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
00606   {
00607     if ( (*it).title == title )
00608       res = (*it).internal;
00609   }
00610   if ( !res.isEmpty() && full )
00611     res = SUIT_Tools::library( res );
00612   return res;
00613 }
00614 
00635 void CAM_Application::readModuleList()
00636 {
00637   if ( !myInfoList.isEmpty() )
00638     return;
00639 
00640   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
00641 
00642   QStringList modList;
00643 
00644   QString args = QApplication::arguments().join( " " );
00645 
00646   QRegExp rx1("--modules=([\\w,]*)");
00647   rx1.setMinimal( false );
00648   QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
00649   rx2.setMinimal( true );
00650   int pos = 0;
00651   while ( 1 ) {
00652     QString modules;
00653     int pos1 = rx1.indexIn( args, pos );
00654     int pos2 = rx2.indexIn( args, pos );
00655     if ( pos1 != -1 && pos2 != -1 ) {
00656       modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
00657       pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
00658     }
00659     else if ( pos1 != -1 ) {
00660       modules = rx1.cap( 1 );
00661       pos = pos1 + rx1.matchedLength();
00662     }
00663     else if ( pos2 != -1 ) {
00664       modules = rx2.cap( 1 );
00665       pos = pos2 + rx2.matchedLength();
00666     }
00667     else {
00668       break;
00669     }
00670 
00671     modList.clear();
00672     QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
00673     for ( int i = 0; i < mods.count(); i++ ) {
00674       if ( !mods[i].trimmed().isEmpty() )
00675         modList.append( mods[i].trimmed() );
00676     }
00677   }
00678 
00679   if ( modList.isEmpty() ) {
00680     QString mods = resMgr->stringValue( "launch", "modules", QString() );
00681     modList = mods.split( ",", QString::SkipEmptyParts );
00682   }
00683 
00684   for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
00685   {
00686     QString modName = (*it).trimmed();
00687 
00688     if ( modName.isEmpty() )
00689       continue;  // empty module name
00690 
00691     if ( !moduleTitle( modName ).isEmpty() )
00692       continue;  // already added
00693 
00694     QString modTitle = resMgr->stringValue( *it, "name", QString() );
00695     if ( modTitle.isEmpty() )
00696     {
00697       printf( "****************************************************************\n" );
00698       printf( "*    Warning: %s GUI resources are not found.\n", qPrintable(*it) );
00699       printf( "*    %s GUI will not be available.\n", qPrintable(*it) );
00700       printf( "****************************************************************\n" );
00701       continue;
00702     }
00703 
00704     QString modIcon = resMgr->stringValue( *it, "icon", QString() );
00705 
00706     QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
00707     if ( !modLibrary.isEmpty() )
00708     {
00709       modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
00710 #ifdef WIN32
00711       QString libExt = QString( "dll" );
00712 #else
00713       QString libExt = QString( "so" );
00714 #endif
00715       if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
00716         modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
00717 #ifndef WIN32
00718       QString prefix = QString( "lib" );
00719       if ( modLibrary.startsWith( prefix ) )
00720         modLibrary.remove( 0, prefix.length() );
00721 #endif
00722     }
00723     else
00724       modLibrary = modName;
00725 
00726     bool aIsSingleton = resMgr->booleanValue(*it, "singleton", false);
00727 
00728     QString ver = resMgr->stringValue(*it, "version", QString());
00729 
00730     ModuleInfo inf;
00731     inf.name = modName;
00732     inf.title = modTitle;
00733     inf.internal = modLibrary;
00734     inf.icon = modIcon;
00735     inf.isSingleton = aIsSingleton;
00736     inf.version = ver;
00737     myInfoList.append( inf );
00738   }
00739 
00740   if ( myInfoList.isEmpty() ) {
00741     if ( desktop() && desktop()->isVisible() )
00742       SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
00743     else
00744       {
00745         printf( "****************************************************************\n" );
00746         printf( "*    Warning: modules list is empty.\n" );
00747         printf( "****************************************************************\n" );
00748       }
00749   }
00750 }
00751 
00761 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
00762 {
00763   // to do : add common items for popup menu ( if they are exist )
00764   if ( activeModule() ) 
00765     activeModule()->contextMenuPopup( type, menu, title );
00766 }
00767 
00771 void CAM_Application::createEmptyStudy()
00772 {
00773   /*SUIT_Study* study = */activeStudy();
00774   STD_Application::createEmptyStudy();
00775 }
00776 
00780 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo() const {
00781 
00782   ModuleShortInfoList info;
00783 
00784   ModuleShortInfo kernel;
00785   kernel.name = "KERNEL";
00786   kernel.version = KERNEL_VERSION_STR;
00787   info.append(kernel);
00788 
00789   ModuleShortInfo gui;
00790   gui.name = "GUI";
00791   gui.version = GUI_VERSION_STR;
00792   info.append(gui);
00793 
00794   for(int i = 0; i < myInfoList.size(); i++) {
00795     ModuleShortInfo infoItem;
00796     infoItem.name = myInfoList.at(i).title;
00797     infoItem.version = myInfoList.at(i).version;
00798     info.append(infoItem);
00799   }  
00800   return info;
00801 }