Salome HOME
bos #29458 Salome on demand
[modules/gui.git] / src / CAM / CAM_Application.cxx
old mode 100755 (executable)
new mode 100644 (file)
index ad48664..2e6f51e
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -208,7 +208,8 @@ void CAM_Application::modules( QStringList& lst, const bool loaded ) const
   {
     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
           it != myInfoList.end(); ++it )
-      lst.append( (*it).title );
+      if ( (*it).status != stNoGui )
+        lst.append( (*it).title );
   }
 }
 
@@ -268,9 +269,6 @@ void CAM_Application::loadModules()
 {
   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
   {
-    if ( !isModuleAccessible( (*it).title ) ) {
-      continue;
-    }
     CAM_Module* mod = loadModule( (*it).title );
     if ( mod )
       addModule( mod );
@@ -303,11 +301,6 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
     return 0;
   }
 
-  if ( !isModuleAccessible( modName ) ) {
-    qWarning( qPrintable( tr( "Module \"%1\" cannot be loaded in this application." ).arg( modName ) ) );
-    return 0;
-  }
-
   QString libName = moduleLibrary( modName );
   if ( libName.isEmpty() )
   {
@@ -320,13 +313,28 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
   GET_VERSION_FUNC getVersion = 0;
 
 #ifdef WIN32
-  HINSTANCE modLib = ::LoadLibrary( libName.toLatin1() ); 
+#ifdef UNICODE
+  LPTSTR str_libname = new TCHAR[libName.length() + 1];
+  str_libname[libName.toWCharArray(str_libname)] = '\0';
+#else
+  QByteArray arr = libName.toLatin1();
+  LPTSTR str_libname = arr.constData();
+#endif
+  HINSTANCE modLib = ::LoadLibrary( str_libname );
+#ifdef UNICODE
+  delete str_libname;
+#endif
   if ( !modLib )
   {
     LPVOID lpMsgBuf;
     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
-    err = QString( "Failed to load  %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
+#ifdef UNICODE
+       QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
+#else 
+       QString out_err = (LPTSTR)lpMsgBuf;
+#endif
+    err = QString( "Failed to load  %1. %2" ).arg( libName ).arg(out_err);
     ::LocalFree( lpMsgBuf );
   }
   else
@@ -337,14 +345,20 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
       LPVOID lpMsgBuf;
       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
-    err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
-    ::LocalFree( lpMsgBuf );
+#ifdef UNICODE
+         QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
+#else 
+         QString out_err = (LPTSTR)lpMsgBuf;
+#endif
+
+         err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( out_err );
+         ::LocalFree( lpMsgBuf );
     }
 
     getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
   }
 #else
-  void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY | RTLD_GLOBAL );
+  void* modLib = dlopen( libName.toUtf8(), RTLD_LAZY | RTLD_GLOBAL );
   if ( !modLib )
     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
   else
@@ -401,16 +415,22 @@ bool CAM_Application::activateModule( const QString& modName )
   // See issues 0021307, 0021373
   BusyLocker lock( myBlocked );
 
+  QString name = modName;
+  if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
+    name = moduleTitle( modName );
+
   bool res = false;
-  if ( !modName.isEmpty() )
+  if ( !name.isEmpty() )
   {
-    CAM_Module* mod = module( modName );
+    setProperty("activateModule", true);
+    CAM_Module* mod = module( name );
     if ( !mod )
-      mod = loadModule( modName );
+      mod = loadModule( name );
     addModule( mod );
 
     if ( mod )
       res = activateModule( mod );
+    setProperty("activateModule", QVariant());
   }
   else
     res = activateModule( 0 );
@@ -438,12 +458,14 @@ bool CAM_Application::activateModule( CAM_Module* mod )
   {
     if ( !myModule->deactivateModule( activeStudy() ) )
     {
-      // ....      
-    }    
+      // ???
+    }
+    moduleDeactivated( myModule );
   }     
   myModule = mod;
 
-  if ( myModule ){
+  if ( myModule )
+  {
     // Connect the module to the active study
     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
     if ( !myModule->activateModule( activeStudy() ) )
@@ -474,12 +496,10 @@ bool CAM_Application::activateModule( CAM_Module* mod )
 */
 bool CAM_Application::activateOperation( const QString& modName, int actionId )
 {
-  if (isModuleAccessible(modName)) {
-    CAM_Module* mod = loadModule(modName, false);
-    if (mod) {
-      addModule(mod);
-      return mod->activateOperation(actionId);
-    }
+  CAM_Module* mod = loadModule(modName, false);
+  if (mod) {
+    addModule(mod);
+    return mod->activateOperation(actionId);
   }
   return false;
 }
@@ -493,12 +513,10 @@ bool CAM_Application::activateOperation( const QString& modName, int actionId )
 */
 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
 {
-  if (isModuleAccessible(modName)) {
-    CAM_Module* mod = loadModule(modName, false);
-    if (mod) {
-      addModule(mod);
-      return mod->activateOperation(actionId);
-    }
+  CAM_Module* mod = loadModule(modName, false);
+  if (mod) {
+    addModule(mod);
+    return mod->activateOperation(actionId);
   }
   return false;
 }
@@ -516,12 +534,10 @@ bool CAM_Application::activateOperation( const QString& modName,
                                          const QString& actionId,
                                          const QString& pluginName )
 {
-  if (isModuleAccessible(modName)) {
-    CAM_Module* mod = loadModule(modName, false);
-    if (mod) {
-      addModule(mod);
-      return mod->activateOperation(actionId, pluginName);
-    }
+  CAM_Module* mod = loadModule(modName, false);
+  if (mod) {
+    addModule(mod);
+    return mod->activateOperation(actionId, pluginName);
   }
   return false;
 }
@@ -597,6 +613,18 @@ void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
 {
 }
 
+/*!
+  \brief Callback function, called when the module is just deactivated.
+  
+  This virtual method can be re-implemented in the successors. Base implementation
+  does nothing.
+
+  \param mod module just deactivated
+*/
+void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
+{
+}
+
 /*!
   \brief Get module name by its title (user name).
   \param title module title (user name)
@@ -631,7 +659,7 @@ QString CAM_Application::moduleTitle( const QString& name )
 
 /*!
   \brief Get module icon name.
-  \param name module name
+  \param name module name or title
   \return module icon or null QString if module is not found
 */
 QString CAM_Application::moduleIcon( const QString& name )
@@ -639,58 +667,40 @@ QString CAM_Application::moduleIcon( const QString& name )
   QString res;
   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
   {
-    if ( (*it).name == name )
+    if ( (*it).name == name || (*it).title == name )
       res = (*it).icon;
   }
   return res;
 }
 
 /*!
-  \brief Returns \c true if module is accessible for the current application.
-  Singleton module can be loaded only in one application object. In other application
-  objects this module will be unavailable.
-  \param title module title (user name)
-  \return \c true if module is accessible (can be loaded) or \c false otherwise
- */
-bool CAM_Application::isModuleAccessible( const QString& title )
+  \brief Get module description.
+  \param name module name or title
+  \return module description or null QString if description is not provided in config file.
+*/
+QString CAM_Application::moduleDescription( const QString& name )
 {
-  bool found   = false;
-  bool blocked = false;
-  bool statusOK = false;
-  
-  QStringList somewhereLoaded;
-  QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
-  foreach( SUIT_Application* app, apps ) {
-    CAM_Application* camApp = dynamic_cast<CAM_Application*>( app );
-    if ( !camApp ) continue;
-    QStringList loaded;
-    camApp->modules( loaded, true );
-    foreach( QString lm, loaded ) {
-      if ( !somewhereLoaded.contains( lm ) ) somewhereLoaded << lm;
-    }
-  }
-
-  for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && !found; ++it )
+  QString res;
+  for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
   {
-    found = (*it).title == title;
-    blocked = (*it).isSingleton && somewhereLoaded.contains((*it).title);
-    statusOK = (*it).status == stReady;
+    if ( (*it).name == name || (*it).title == name )
+      res = tr((*it).description.toUtf8());
   }
-  return found && statusOK && !blocked;
+  return res;
 }
 
 /*!
   \brief Get module library name by its title (user name).
-  \param title module title (user name)
+  \param title module name or title
   \param full if \c true, return full library name, otherwise return its internal name
   \return module library name or null QString if module is not found
  */
-QString CAM_Application::moduleLibrary( const QString& title, const bool full )
+QString CAM_Application::moduleLibrary( const QString& name, const bool full )
 {
   QString res;
   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
   {
-    if ( (*it).title == title )
+    if ( (*it).name == name || (*it).title == name )
       res = (*it).library;
   }
   if ( !res.isEmpty() && full )
@@ -698,6 +708,30 @@ QString CAM_Application::moduleLibrary( const QString& title, const bool full )
   return res;
 }
 
+/*!
+  \brief Get displayer proxy for given module, by its title (user name).
+  \param name module name or title
+  \return name of module which provides displayer for requested module
+ */
+QString CAM_Application::moduleDisplayer( const QString& name )
+{
+  QString res;
+
+  if ( !name.isEmpty() )
+  {
+    for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
+    {
+      if ( (*it).title == name || (*it).name == name ) {
+        res = (*it).displayer;
+        if ( res.isEmpty() )
+          res = (*it).title;
+      }
+    }
+  }
+
+  return res;
+}
+
 /*!
   \brief Read modules information list
 
@@ -723,6 +757,7 @@ void CAM_Application::readModuleList()
   if ( !myInfoList.isEmpty() )
     return;
 
+  // we cannot use own resourceMgr() as this method can be called from constructor
   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
 
   QStringList modList;
@@ -767,67 +802,11 @@ void CAM_Application::readModuleList()
     modList = mods.split( ",", QString::SkipEmptyParts );
   }
 
-  for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
-  {
-    QString modName = (*it).trimmed();
-
-    if ( modName.isEmpty() )
-      continue;  // empty module name
-
-    if ( !moduleTitle( modName ).isEmpty() )
-      continue;  // already added
-
-    if ( modName == "KERNEL" || modName == "GUI" )
-      continue; // omit KERNEL and GUI modules
-
-    QString modTitle = resMgr->stringValue( *it, "name", QString() );
-    if ( modTitle.isEmpty() )
-    {
-      printf( "****************************************************************\n" );
-      printf( "     Warning: module %s is improperly configured!\n", qPrintable(*it) );
-      printf( "     Module %s will not be available in GUI mode!\n", qPrintable(*it) );
-      printf( "****************************************************************\n" );
-      continue;
-    }
-
-    QString modIcon = resMgr->stringValue( *it, "icon", QString() );
+  // extra modules loaded manually on previous session
+  // ...
 
-    QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
-    if ( !modLibrary.isEmpty() )
-    {
-      modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
-#if defined(WIN32)
-      QString libExt = QString( "dll" );
-#elif defined(__APPLE__)
-      QString libExt = QString( "dylib" );
-#else
-      QString libExt = QString( "so" );
-#endif
-      if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
-        modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
-#ifndef WIN32
-      QString prefix = QString( "lib" );
-      if ( modLibrary.startsWith( prefix ) )
-        modLibrary.remove( 0, prefix.length() );
-#endif
-    }
-    else
-      modLibrary = modName;
-
-    bool aIsSingleton = resMgr->booleanValue( *it, "singleton", false );
-    bool hasGui = resMgr->booleanValue( *it, "gui", true );
-    QString version = resMgr->stringValue( *it, "version", QString() );
-
-    ModuleInfo inf;
-    inf.name = modName;
-    inf.title = modTitle;
-    inf.status = hasGui ? stUnknown : stNoGui;
-    if ( hasGui ) inf.library = modLibrary;
-    inf.icon = modIcon;
-    inf.isSingleton = aIsSingleton;
-    inf.version = version;
-    myInfoList.append( inf );
-  }
+  foreach ( QString modName, modList )
+    appendModuleInfo( modName.trimmed() );
 
   if ( myInfoList.isEmpty() ) {
     if ( desktop() && desktop()->isVisible() )
@@ -841,6 +820,70 @@ void CAM_Application::readModuleList()
   }
 }
 
+bool CAM_Application::appendModuleInfo( const QString& modName )
+{
+  if ( modName.isEmpty() )
+    return false;  // empty module name
+
+  if ( !moduleTitle( modName ).isEmpty() )
+    return false;  // already added
+
+  if ( modName == "KERNEL" || modName == "GUI" )
+    return false; // skip KERNEL and GUI modules
+
+  // we cannot use own resourceMgr() as this method can be called from constructor
+  SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+
+  // "gui" option explicitly says that module has GUI
+  bool hasGui = resMgr->booleanValue( modName, "gui", true );
+
+  ModuleInfo inf;
+
+  // module internal name
+  inf.name = modName;
+  // module version
+  inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
+  // displayer, if module does not have GUI, displayer may be delegated to other module
+  inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
+  // status; if module has GUI, availability will be checked on activation
+  inf.status = hasGui ? stUnknown : stNoGui;
+
+  if ( hasGui )
+  {
+    // module with GUI must explicitly specify title (GUI name)
+    inf.title = resMgr->stringValue( modName, "name", QString() ).trimmed();
+    if ( inf.title.isEmpty() )
+      inf.status = stInvalid;
+    // icon
+    inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
+    // description, for Info panel
+    inf.description = resMgr->stringValue( modName, "description", QString() );
+    // library; if not specified, we use internal module name
+    inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
+    if ( inf.library.isEmpty() )
+      inf.library = modName;
+  }
+
+  if ( inf.status != stInvalid )
+    myInfoList.append( inf );
+
+  return true;
+}
+
+void CAM_Application::removeModuleInfo( const QString& modName )
+{
+  QMutableListIterator<ModuleInfo> it( myInfoList );
+  while ( it.hasNext() )
+  {
+    ModuleInfo info = it.next();
+    if ( info.name == modName )
+    {
+      it.remove();
+      break;
+    }
+  }
+}
+
 /*!
   \brief Add common menu items to the popup menu.
 
@@ -885,7 +928,7 @@ CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
 
   for(int i = 0; i < myInfoList.size(); i++) {
     ModuleShortInfo infoItem;
-    infoItem.name = myInfoList.at(i).title;
+    infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
     infoItem.version = myInfoList.at(i).version;
     info.append(infoItem);
   }