-// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024 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
// File: LightApp_Application.cxx
// Created: 6/20/2005 18:39:45 PM
// Author: Natalia Donis
-
#ifdef WIN32
// E.A. : On windows with python 2.6, there is a conflict
// E.A. : between pymath.h and Standard_math.h which define
#include "LightApp_PreferencesDlg.h"
#include "LightApp_ModuleDlg.h"
#include "LightApp_AboutDlg.h"
+#include "LightApp_ExtInfoDlg.h"
#include "LightApp_ModuleAction.h"
// temporary commented
#include "LightApp_EventFilter.h"
#include <QtxMap.h>
#include <LogWindow.h>
+#include <SalomeApprc_utils.h>
#ifndef DISABLE_GLVIEWER
#include <GLViewer_Viewer.h>
#include <PyViewer_ViewWindow.h>
#endif
+#ifndef DISABLE_PV3DVIEWER
+#ifndef DISABLE_SALOMEOBJECT
+ #include <SPV3D_ViewModel.h>
+ #include <SPV3D_ViewManager.h>
+ #include "LightApp_PV3DSelector.h"
+#else
+ #include <PV3DViewer_ViewModel.h>
+ #include <PV3DViewer_ViewManager.h>
+#endif
+ #include <PV3DViewer_ViewManager.h>
+ #include <PV3DViewer_ViewModel.h>
+ #include "PV3DViewer_ViewWindow.h"
+#endif
+
#define VISIBILITY_COLUMN_WIDTH 25
#include <utilities.h>
#define FIRST_HELP_ID 1000000
+#define HAS_WWW_URL true
+#define HAS_FORUM_URL true
+#define HAS_YOUTUBE_URL true
+#define HAS_TUTORIAL_URL false
#ifndef DISABLE_SALOMEOBJECT
#include <SALOME_InteractiveObject.hxx>
//since the 'toolbar marker' is not unique, find index of first occurrence of the
//'toolbar marker' in the array and check that next string is name of the toolbar
+namespace
+{
+ const char* salomeAppDir = "SALOME_APPLICATION_DIR";
+}
+
void LightAppCleanUpAppResources()
{
if ( LightApp_Application::_prefs_ ) {
result = QLocale( lang ).nativeLanguageName();
return result;
}
+
+ QString getHelpItem( const QString& section, const QString& parameter, const QString& root = QString() )
+ {
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ foreach( QString item, resMgr->stringValue( section, parameter ).split( ";;", QString::SkipEmptyParts ) )
+ {
+ if ( item.startsWith( "http", Qt::CaseInsensitive ) )
+ return item;
+ QString path = item;
+ path.remove( QRegExp( "#.*$" ) );
+ QFileInfo fi( path );
+ if ( fi.isRelative() && !root.isEmpty() )
+ path = Qtx::addSlash( root ) + path;
+ if ( QFile::exists( path ) )
+ return item;
+ }
+ return QString();
+ }
+
+ const bool HAS_SALOME_ON_DEMAND =
+#if defined(WITH_SALOME_ON_DEMAND)
+ true;
+#else
+ false;
+#endif
}
/*!Create new instance of LightApp_Application.*/
if ( prevMod )
actName = prevMod->moduleName();
- if ( actName == modName )
+ QString name = modName;
+ if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
+ name = moduleTitle( modName );
+
+ if ( actName == name )
return true;
- putInfo( tr( "ACTIVATING_MODULE" ).arg( modName ) );
+ putInfo( tr( "ACTIVATING_MODULE" ).arg( name ) );
saveDockWindowsState();
if ( infoPanel() )
infoPanel()->clear();
- bool status = CAM_Application::activateModule( modName );
+ bool status = CAM_Application::activateModule( name );
updateModuleActions();
if ( objectBrowser()->root() != activeStudy()->root() )
objectBrowser()->setRoot( activeStudy()->root() );
updateObjectBrowser( true );
+
+ // expand SHAPERSTUDY data after leaving Shaper module
+ // bos #40645 [CEA] Automatically expand tree in Object Browser
+ if (actName == "Shaper") {
+ SUIT_AbstractModel* aModel = dynamic_cast<SUIT_AbstractModel*>(objectBrowser()->model());
+ LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( activeStudy() );
+ if (aModel && aStudy) {
+ DataObjectList aComps;
+ aStudy->root()->children(aComps);
+ for(auto aCompSUIT : aComps){
+ LightApp_DataObject* aComp = dynamic_cast<LightApp_DataObject*>( aCompSUIT );
+ if ( aComp && aComp->componentDataType() == "SHAPERSTUDY") {
+ QModelIndex anIndex = aModel->index(aComp);
+ objectBrowser()->treeView()->expand(anIndex);
+ break;
+ }
+ }
+ }
+ }
}
if ( activeModule() ) activeModule()->updateModuleVisibilityState();
int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, -1, 1000 );
- int id = LightApp_Application::UserID + FIRST_HELP_ID;
+ QString url;
// a) Link to web site
- QString url = resMgr->stringValue("GUI", "site_url");
- if ( !url.isEmpty() ) {
- QString title = tr ( "SALOME_SITE" );
- QAction* as = createAction( WebSiteId, title,
- resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
- title, title,
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- as->setData( url );
- createMenu( as, helpMenu, -1, 0 );
+ if ( HAS_WWW_URL ) {
+ url = resMgr->stringValue("GUI", "site_url");
+ if ( !url.isEmpty() ) {
+ QString title = tr ( "SALOME_SITE" );
+ QAction* as = createAction( WebSiteId, title,
+ resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+ title, title,
+ 0, desk, false, this, SLOT( onHelpContentsModule() ) );
+ as->setData( url );
+ createMenu( as, helpMenu, -1, 0 );
+ }
}
// b) Link to Forum
- url = resMgr->stringValue("GUI", "forum_url");
- if ( !url.isEmpty() ) {
- QString title = tr ( "SALOME_FORUM" );
- QAction* af = createAction( ForumId, title,
- resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
- title, title,
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- af->setData( url );
- createMenu( af, helpMenu, -1, 0 );
+ if ( HAS_FORUM_URL ) {
+ url = resMgr->stringValue("GUI", "forum_url");
+ if ( !url.isEmpty() ) {
+ QString title = tr ( "SALOME_FORUM" );
+ QAction* af = createAction( ForumId, title,
+ resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+ title, title,
+ 0, desk, false, this, SLOT( onHelpContentsModule() ) );
+ af->setData( url );
+ createMenu( af, helpMenu, -1, 0 );
+ }
}
// c) Link to YouTube channel
- url = resMgr->stringValue("GUI", "channel_url");
- if ( !url.isEmpty() ) {
- createMenu( separator(), helpMenu, -1, 0 );
- QString title = tr ( "SALOME_VIDEO_TUTORIALS" );
- QAction* av = createAction( VideosId, title,
- resMgr->loadPixmap( "LightApp", tr( "ICON_LIFE_RIGN" ), false ),
- title, tr( "PRP_SALOME_VIDEO_TUTORIALS" ),
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- av->setData( url );
- createMenu( av, helpMenu, -1, 0 );
+ if ( HAS_YOUTUBE_URL ) {
+ url = resMgr->stringValue("GUI", "channel_url");
+ if ( !url.isEmpty() ) {
+ createMenu( separator(), helpMenu, -1, 0 );
+ QString title = tr ( "SALOME_VIDEO_TUTORIALS" );
+ QAction* av = createAction( VideosId, title,
+ resMgr->loadPixmap( "LightApp", tr( "ICON_LIFE_RIGN" ), false ),
+ title, tr( "PRP_SALOME_VIDEO_TUTORIALS" ),
+ 0, desk, false, this, SLOT( onHelpContentsModule() ) );
+ av->setData( url );
+ createMenu( av, helpMenu, -1, 0 );
+ }
}
// d) Link to Tutorials
-
- url = resMgr->stringValue("GUI", "tutorials_url");
- if ( !url.isEmpty() ) {
- QString title = tr ( "SALOME_TUTORIALS" );
- QAction* as = createAction( TutorialsId, title,
- resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
- title, tr( "PRP_SALOME_TUTORIALS" ),
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- as->setData( url );
- createMenu( as, helpMenu, -1, 0 );
+ if ( HAS_TUTORIAL_URL ) {
+ url = resMgr->stringValue("GUI", "tutorials_url");
+ if ( !url.isEmpty() ) {
+ QString title = tr ( "SALOME_TUTORIALS" );
+ QAction* as = createAction( TutorialsId, title,
+ resMgr->loadPixmap( "LightApp", tr( "ICON_WWW" ), false ),
+ title, tr( "PRP_SALOME_TUTORIALS" ),
+ 0, desk, false, this, SLOT( onHelpContentsModule() ) );
+ as->setData( url );
+ createMenu( as, helpMenu, -1, 0 );
+ }
}
// e) Help for modules
- // - First create top-level menus to preserve correct order
- QString userGuide = "User's Guide";
- QString devGuide = "Developer's Guide";
- createMenu( userGuide, helpMenu, -1, 5 );
- createMenu( devGuide, helpMenu, -1, 5 );
-
QStringList aModuleList;
modules( aModuleList, false );
aModuleList.prepend( "GUI" );
aModuleList.prepend( "KERNEL" );
- QString aModule;
- foreach( aModule, aModuleList ) {
- if ( aModule.isEmpty() ) // module title (user name)
- continue;
- IMap <QString, QString> helpData; // list of help files for the module
- QString helpSubMenu; // help submenu name (empty if not needed)
- QString modName = moduleName( aModule ); // module name
- if ( modName.isEmpty() ) modName = aModule; // for KERNEL and GUI
- QString rootDir = QString( "%1_ROOT_DIR" ).arg( modName ); // module root dir env variable
- QString modDir = Qtx::getenv( rootDir.toUtf8().constData() ); // module root dir path
- QString docSection;
- if (resMgr->hasValue( modName, "documentation" ) )
- docSection = resMgr->stringValue(modName, "documentation");
- else if ( resMgr->hasSection( modName + "_documentation" ) )
- docSection = modName + "_documentation";
- if ( !docSection.isEmpty() ) {
- helpSubMenu = resMgr->stringValue( docSection, "sub_menu", "" );
- if ( helpSubMenu.contains( "%1" ) )
- helpSubMenu = helpSubMenu.arg( aModule );
- QStringList listOfParam = resMgr->parameters( docSection );
- foreach( QString paramName, listOfParam ) {
- QString valueStr = resMgr->stringValue( docSection, paramName );
- if ( !valueStr.isEmpty() ) {
- QStringList valueItems = valueStr.split( ";;", QString::SkipEmptyParts );
- foreach( QString item, valueItems ) {
- if ( item.startsWith( "http", Qt::CaseInsensitive ) ) {
- QString key = paramName.contains( "%1" ) ? paramName.arg( aModule ) : paramName;
- helpData.insert( key, item );
- break;
- }
- else {
- QFileInfo fi( item );
- if ( fi.isRelative() && !modDir.isEmpty() )
- item = Qtx::addSlash( modDir ) + item;
- if ( QFile::exists( item ) ) {
- QString key = paramName.contains( "%1" ) ? paramName.arg( aModule ) : paramName;
- helpData.insert( key, item );
- break;
- }
- }
- }
- }
- }
- }
-
- if ( helpData.isEmpty() && !modDir.isEmpty() ) {
- QStringList idxLst = QStringList() << modDir << "share" << "doc" << "salome" << "gui" << modName << "index.html";
- QString indexFile = idxLst.join( QDir::separator() ); // index file
- if ( QFile::exists( indexFile ) )
- helpData.insert( tr( "%1 module Users's Guide" ).arg( aModule ), indexFile );
- }
+ foreach( QString aModule, aModuleList )
+ createHelpItems( aModule );
- IMapConstIterator<QString, QString > fileIt;
- for ( fileIt = helpData.begin(); fileIt != helpData.end(); fileIt++ ) {
- QString helpItemPath = fileIt.key();
- // remove all '//' occurances
- while ( helpItemPath.contains( "//" ) )
- helpItemPath.replace( "//", "" );
- // obtain submenus hierarchy if given
- QStringList smenus = helpItemPath.split( "/" );
- helpItemPath = smenus.takeLast();
- // workaround for User's Guide and Developer's Guide to avoid having single item in module's submenu.
- if ( helpItemPath == userGuide || helpItemPath == devGuide ) {
- QString menuPath = smenus.join( "/" );
- QStringList allKeys = helpData.keys();
- QStringList total = allKeys.filter( QRegExp( QString( "^%1" ).arg( menuPath ) ) );
- if ( total.count() == 1 && smenus.count() > 0 )
- helpItemPath = smenus.takeLast();
- }
- QPixmap helpIcon = fileIt.value().startsWith( "http", Qt::CaseInsensitive ) ?
- resMgr->loadPixmap( "STD", tr( "ICON_WWW" ), false ) : resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false );
- QAction* a = createAction( id, helpItemPath, helpIcon, helpItemPath, helpItemPath,
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- a->setData( fileIt.value() );
- if ( !helpSubMenu.isEmpty() ) {
- smenus.prepend( helpSubMenu );
- }
- // create sub-menus hierarchy
- int menuId = helpMenu;
- foreach ( QString subMenu, smenus )
- menuId = createMenu( subMenu, menuId, -1, 5 );
- createMenu( a, menuId, -1, ( menuId != helpMenu && (helpItemPath == userGuide || helpItemPath == devGuide) ) ? 0 : 5 );
- id++;
- }
- }
-
- // - Additional help items
+ // f) Additional help items
+ int id = LightApp_Application::UserID + FIRST_HELP_ID + 1000;
createMenu( separator(), helpMenu, -1, 10 );
QStringList addHelpItems = resMgr->parameters( "add_help" );
foreach ( QString paramName, addHelpItems ) {
- QString valueStr = resMgr->stringValue( "add_help", paramName );
- if ( !valueStr.isEmpty() ) {
- QStringList valueItems = valueStr.split( ";;", QString::SkipEmptyParts );
- foreach( QString item, valueItems ) {
- if ( item.startsWith( "http", Qt::CaseInsensitive ) || QFile::exists( item ) ) {
- QPixmap helpIcon = item.startsWith( "http", Qt::CaseInsensitive ) ?
- resMgr->loadPixmap( "STD", tr( "ICON_WWW" ), false ) : resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false );
- QAction* a = createAction( id++, paramName, helpIcon, paramName, paramName,
- 0, desk, false, this, SLOT( onHelpContentsModule() ) );
- a->setData( item );
- createMenu( a, helpMenu, -1, 10 );
- break;
- }
- }
+ QString helpItem = getHelpItem( "add_help", paramName );
+ if ( !helpItem.isEmpty() )
+ {
+ QPixmap helpIcon = helpItem.startsWith( "http", Qt::CaseInsensitive ) ?
+ resMgr->loadPixmap( "STD", tr( "ICON_WWW" ), false ) : resMgr->loadPixmap( "STD", tr( "ICON_HELP" ), false );
+ QAction* a = createAction( id++, paramName, helpIcon, paramName, paramName,
+ 0, desk, false, this, SLOT( onHelpContentsModule() ) );
+ a->setData( helpItem );
+ createMenu( a, helpMenu, -1, 10 );
}
}
connect( mru, SIGNAL( activated( const QString& ) ), this, SLOT( onMRUActivated( const QString& ) ) );
registerAction( MRUId, mru );
- // default icon for neutral point ('SALOME' module)
- QPixmap defIcon = resMgr->loadPixmap( "LightApp", tr( "APP_DEFAULT_ICO" ), false );
- if ( defIcon.isNull() )
- defIcon = QPixmap( imageEmptyIcon );
-
- //! default icon for any module
- QPixmap modIcon = resMgr->loadPixmap( "LightApp", tr( "APP_MODULE_ICO" ), false );
- if ( modIcon.isNull() )
- modIcon = QPixmap( imageEmptyIcon );
-
+ // List of modules
+ LightApp_ModuleAction* moduleAction = new LightApp_ModuleAction( resMgr, desk );
+ registerAction( ModulesListId, moduleAction );
+ // a. here we add regular modules (specified to GUI via --modules cmd line option, or default list from configuration)
+ // b. custom modules are added in customize() method
QStringList modList;
modules( modList, false );
-
- if ( modList.count() > 1 )
- {
- LightApp_ModuleAction* moduleAction =
- new LightApp_ModuleAction( tr( "APP_NAME" ), defIcon, desk );
-
- QMap<QString, QString> iconMap;
- moduleIconNames( iconMap );
-
- const int iconSize = 20;
-
- QStringList::Iterator it;
- for ( it = modList.begin(); it != modList.end(); ++it )
- {
- QString modName = moduleName( *it );
-
- QString iconName;
- if ( iconMap.contains( *it ) )
- iconName = iconMap[*it];
-
- QPixmap icon = resMgr->loadPixmap( modName, iconName, false );
- if ( icon.isNull() )
- {
- icon = modIcon;
- INFOS( std::endl <<
- "****************************************************************" << std::endl <<
- " Warning: icon for " << qPrintable(*it) << " is not found!" << std::endl <<
- " Using the default icon." << std::endl <<
- "****************************************************************" << std::endl);
- }
- icon = Qtx::scaleIcon( icon, iconSize );
-
- moduleAction->insertModule( *it, icon );
- }
-
- connect( moduleAction, SIGNAL( moduleActivated( const QString& ) ),
- this, SLOT( onModuleActivation( const QString& ) ) );
- registerAction( ModulesListId, moduleAction );
- }
+ foreach ( QString aModule, modList )
+ moduleAction->insertModule( aModule, moduleIcon( aModule, 20 ) ); // scale icon to 20x20 pix
+
+ connect( this, SIGNAL( moduleActivated( QString ) ),
+ moduleAction, SLOT( setActiveModule( QString ) ) );
+ connect( moduleAction, SIGNAL( moduleActivated( const QString& ) ),
+ this, SLOT( onModuleActivation( const QString& ) ) );
+ connect( moduleAction, SIGNAL( adding() ),
+ this, SLOT( onExtAdding() ) );
+ connect( moduleAction, SIGNAL( removing( QString ) ),
+ this, SLOT( onExtRemoving( QString ) ) );
+ connect( moduleAction, SIGNAL(showExtInfo()),
+ this, SLOT(onShowExtInfo()));
+
+ addExtensionsActions(moduleAction);
// New window
int windowMenu = createMenu( tr( "MEN_DESK_WINDOW" ), -1, MenuWindowId, 100 );
#ifndef DISABLE_PYVIEWER
createActionForViewer( NewPyViewerId, newWinMenu, QString::number( 7 ), Qt::ALT+Qt::Key_Y );
#endif
+#ifndef DISABLE_PV3DVIEWER
+ createActionForViewer( NewPV3DViewId, newWinMenu, QString::number( 8 ), Qt::ALT+Qt::Key_3 );
+#endif
createAction( RenameId, tr( "TOT_RENAME" ), QIcon(), tr( "MEN_DESK_RENAME" ), tr( "PRP_RENAME" ),
Qt::ALT+Qt::SHIFT+Qt::Key_R, desk, false, this, SLOT( onRenameWindow() ) );
createMenu( StyleId, viewMenu, 20, -1 );
#endif // USE_SALOME_STYLE
createMenu( FullScreenId, viewMenu, 20, -1 );
+ createMenu( separator(), viewMenu, -1, 20, -1 );
+ createMenu( ModulesListId, viewMenu );
int modTBar = createTool( tr( "INF_TOOLBAR_MODULES" ), // title (language-dependant)
QString( "SalomeModules" ) ); // name (language-independant)
createTool( ModulesListId, modTBar );
}
+/*!Create actions for installed extensions:*/
+void LightApp_Application::addExtensionsActions(LightApp_ModuleAction* moduleAction)
+{
+ if (!moduleAction)
+ {
+ MESSAGE("Couldn't get a moduleAction! Return.");
+ return;
+ }
+
+ // It should be set on the app start if we use an --on_demand 1 command line option
+ auto extRootDir = getenv(salomeAppDir);
+ if (!extRootDir)
+ {
+ // It's ok if we don't use --on_demand
+ return;
+ }
+ SCRUTE(extRootDir);
+
+ // Import Python module that manages SALOME extensions.
+ PyLockWrapper lck; // acquire GIL
+ PyObjWrapper extensionQuery = PyImport_ImportModule((char*)"SalomeOnDemandTK.extension_query");
+ PyObjWrapper installedExtensions = PyObject_CallMethod(
+ extensionQuery, (char*)"ext_by_name", (char*)"s", extRootDir);
+ if (!installedExtensions)
+ {
+ return;
+ }
+
+ // Iterate installed extensions
+ for (Py_ssize_t pos = 0; pos < PyList_Size(installedExtensions); ++pos)
+ {
+ // Get the current ext name
+ auto extNameItem = PyList_GetItem(installedExtensions, pos);
+ QString extName(PyUnicode_AsUTF8(extNameItem));
+ SCRUTE(extName.toStdString());
+
+ moduleAction->insertExtension(extName);
+ }
+
+ // Udate actions only once after all of them were already inserted
+ moduleAction->updateExtActions();
+}
+
+/*!
+ Customize actions.
+*/
+void LightApp_Application::customize()
+{
+ // List of modules
+ LightApp_ModuleAction* moduleAction = qobject_cast<LightApp_ModuleAction*>( action( ModulesListId ) );
+ // a. regular modules were added in createActions() method
+ // b. here we add custom modules (manually added by the user)
+ if ( HAS_SALOME_ON_DEMAND && QString::compare(getenv("SALOME_ON_DEMAND"),"HIDE", Qt::CaseInsensitive) != 0)
+ {
+ // Update rc file
+ updateSalomeApprc();
+
+ QStringList modList = resourceMgr()->stringValue( "launch", "user_modules" ).split( ";", QString::SkipEmptyParts );
+ foreach ( QString aModule, modList )
+ addUserModule( aModule, resourceMgr()->stringValue( "user_modules", aModule ), true );
+ }
+ else
+ {
+ moduleAction->setModeEnabled( LightApp_ModuleAction::AddRemove, false );
+ }
+}
+
+/*!
+ Update rc file with SALOME_APPLICATION_DIR or with SALOME_MODULES.
+*/
+void LightApp_Application::updateSalomeApprc()
+{
+ SUIT_ResourceMgr* resMgr = resourceMgr();
+ auto extRootDir = getenv(salomeAppDir);
+
+ QString salomemodules(getenv("SALOME_MODULES"));
+ if(salomemodules.isEmpty())
+ UpdateCompInfo_with_salomeappdir( QDir(extRootDir), resMgr );
+ else
+ UpdateCompInfo_with_salomemodules(salomemodules, QDir(extRootDir), resMgr);
+}
+
/*!On module activation action.*/
-void LightApp_Application::onModuleActivation( const QString& modName )
+void LightApp_Application::onModuleActivation( const QString& modTitle )
{
// Force user to create/open a study before module activation
- QMap<QString, QString> iconMap;
- moduleIconNames( iconMap );
- QPixmap icon = resourceMgr()->loadPixmap( moduleName( modName ), iconMap[ modName ], false );
- if ( icon.isNull() )
- icon = resourceMgr()->loadPixmap( "LightApp", tr( "APP_MODULE_BIG_ICO" ), false ); // default icon for any module
-
+ QPixmap icon = moduleIcon( modTitle );
bool cancelled = false;
- while ( !modName.isEmpty() && !activeStudy() && !cancelled ){
- LightApp_ModuleDlg aDlg( desktop(), modName, icon );
+ while ( !modTitle.isEmpty() && !activeStudy() && !cancelled ){
+ LightApp_ModuleDlg aDlg( desktop(), modTitle, icon );
QMap<int, QString> opmap = activateModuleActions();
for ( QMap<int, QString>::ConstIterator it = opmap.begin(); it != opmap.end(); ++it )
aDlg.addButton( it.value(), it.key() );
else {
// cancelled
putInfo( tr("INF_CANCELLED") );
-
- LightApp_ModuleAction* moduleAction =
- qobject_cast<LightApp_ModuleAction*>( action( ModulesListId ) );
- if ( moduleAction )
- moduleAction->setActiveModule( QString() );
+ emit moduleActivated( QString() );
cancelled = true;
}
}
if ( !cancelled )
- activateModule( modName );
+ activateModule( modTitle );
+}
+
+/*!On extension adding action.*/
+void LightApp_Application::onExtAdding()
+{
+ // Show dialog to browse a salome extension file
+ QStringList filters = (QStringList() << tr("Salome extension files") + " (*.salomex)" << tr("All files") + " (*)");
+ QStringList paths = getOpenFileNames(QString(), filters.join(";;"), QString(), desktop());
+ if (paths.isEmpty())
+ {
+ MESSAGE("Adding an extension was cancelled.");
+ return;
+ }
+
+ LightApp_ModuleAction* moduleAction = qobject_cast<LightApp_ModuleAction*>(action(ModulesListId));
+ if (!moduleAction)
+ {
+ MESSAGE("Couldn't get a moduleAction! Return.");
+ return;
+ }
+
+ // It should be set on the app start
+ auto extRootDir = getenv(salomeAppDir);
+ if (!extRootDir)
+ {
+ SUIT_MessageBox::warning(desktop(), tr("WRN_WARNING"), tr("WRN_SALOME_APPLICATION_DIR"));
+ return;
+ }
+ SCRUTE(extRootDir);
+
+ // We'll load all the extensions modules from this path
+ auto SalomeExtDir = QDir::cleanPath(QString(extRootDir) + QDir::separator() + "__SALOME_EXT__");
+ SCRUTE(SalomeExtDir.toStdString());
+
+ // Import Python module that manages SALOME extensions.
+ // It seems to be faster to lock and unlock once than on each iteration,
+ // but I didn't compare the performance for each case.
+ PyLockWrapper lck; // acquire GIL
+ PyObjWrapper extensionUnpacker = PyImport_ImportModule((char*)"SalomeOnDemandTK.extension_unpacker");
+ PyObjWrapper runSalomeOnDemand = PyImport_ImportModule((char*)"runSalomeOnDemand");
+
+ // Loop via selected extensions files
+ foreach(QString path, paths)
+ {
+ std::string extPath = path.toStdString();
+ SCRUTE(extPath);
+
+ PyObjWrapper unpackedModules = PyObject_CallMethod(
+ extensionUnpacker, (char*)"install_salomex", (char*)"s", extPath.c_str());
+ if (!unpackedModules || unpackedModules == Py_None)
+ {
+ SUIT_MessageBox::warning(desktop(), tr("WRN_WARNING"), tr("WRN_FAILED_UNPACK_EXTENSION").arg(path) );
+ continue;
+ }
+
+ PyObjWrapper pKeys = PyDict_Keys(unpackedModules);
+ // Iterate all the components (modules) for this extension
+ for (Py_ssize_t pos = 0; pos < PyDict_Size(unpackedModules); ++pos)
+ {
+ auto moduleNameItem = PyList_GetItem(pKeys, pos);
+ auto interactiveItem = PyDict_GetItem(unpackedModules, moduleNameItem);
+
+ QString moduleName(PyUnicode_AsUTF8(moduleNameItem));
+ SCRUTE(moduleName.toStdString());
+ addUserModule(moduleName, SalomeExtDir, PyObject_IsTrue(interactiveItem));
+ }
+
+ // Add an extension to GUI
+ QFileInfo extFileInfo(path);
+ QString extName = extFileInfo.baseName();
+ if (moduleAction)
+ {
+ moduleAction->insertExtension(extName);
+ }
+
+ // Update environment of salome
+ PyObjWrapper update_env = PyObject_CallMethod(
+ runSalomeOnDemand, (char*)"set_selext_env", (char*)"ss", extRootDir, extName.toStdString().c_str());
+ if (!update_env)
+ {
+ SUIT_MessageBox::warning(desktop(), tr("WRN_WARNING"), tr("WRN_FAILED_UPDATE_ENV").arg(extName + "_env.py") );
+ continue;
+ }
+ }
+
+ // Udate actions only once after all of them were already inserted
+ moduleAction->updateExtActions();
+}
+
+/*Add user module.*/
+bool LightApp_Application::addUserModule( const QString& name, const QString& root, bool interactive )
+{
+ if ( name == "KERNEL" || name == "GUI" )
+ return false; // skip KERNEL and GUI modules
+
+ if ( name.isEmpty() || root.isEmpty() )
+ return false;
+
+ if ( !moduleTitle( name ).isEmpty() ) // module alread in current session
+ {
+ if ( interactive )
+ SUIT_MessageBox::warning( desktop(), tr( "WRN_WARNING" ), tr( "WRN_MODULE_DUPLICATED" ).arg( name ) );
+ return false;
+ }
+ if ( !QFileInfo( root ).exists() ) // root directory does not exist
+ {
+ if ( interactive )
+ SUIT_MessageBox::warning( desktop(), tr( "WRN_WARNING" ), tr( "WRN_MODULE_ROOT_DOES_NOT_EXIST" ).arg( root ) );
+ return false;
+ }
+ // resources directory
+ QString resDir = Qtx::joinPath( QStringList() << root << "share" << "salome" << "resources" << name.toLower() );
+ if ( !QFileInfo( resDir ).exists() ) // resources directory does not exist
+ {
+ if ( interactive )
+ SUIT_MessageBox::warning( desktop(), tr( "WRN_WARNING" ), tr( "WRN_MODULE_BAD_RESDIR" ).arg( resDir ) );
+ return false;
+ }
+
+ SUIT_ResourceMgr* resMgr = resourceMgr();
+
+ // read XML configuration file
+ resMgr->setConstant(QString("%1_ROOT_DIR").arg(name), root);
+ if (!resMgr->addResource(resDir)) // cannot read configuration
+ {
+ if ( interactive )
+ SUIT_MessageBox::warning( desktop(), tr( "WRN_WARNING" ), tr( "WRN_MODULE_CANNOT_READ_CFG" ).arg( resDir ) );
+ return false;
+ }
+ // fill in information about module
+ if ( !appendModuleInfo( name ) ) // cannot append module information to internal table
+ {
+ if ( interactive )
+ SUIT_MessageBox::warning( desktop(), tr( "WRN_WARNING" ), tr( "WRN_MODULE_BAD_CFG_FILE" ).arg( name ) );
+ return false;
+ }
+
+ // load translations
+ resMgr->loadLanguage(name);
+
+ // Do all the GUI related stuff only if the module supports that.
+ // We already did check for GUI inside CAM_Application::appendModuleInfo, but
+ // need to do that again.
+ // TODO: Maybe it's better to return ModuleInfo from appendModuleInfo() and check status.
+ const QString title = resMgr->stringValue(name, "name", QString()).trimmed();
+ if (resMgr->booleanValue(name, "gui", false) || !title.isEmpty() && interactive)
+ {
+ // Append module to the menu / toolbar
+ LightApp_ModuleAction* moduleAction = qobject_cast<LightApp_ModuleAction*>(action(ModulesListId));
+ if (moduleAction)
+ {
+ // Scale icon to 20x20 pix
+ moduleAction->insertModule(moduleTitle(name), moduleIcon(moduleTitle(name), 20), true);
+ }
+ }
+
+ // add empty page to Preferences dialog
+ LightApp_Preferences* prefs = preferences();
+ if ( prefs && !prefs->hasModule( moduleTitle( name ) ) )
+ {
+ int prefId = prefs->addPreference( moduleTitle( name ) );
+ prefs->setItemIcon( prefId, moduleIcon( moduleTitle( name ), 20 ) ); // scale icon to 20x20 pix
+ LightApp_Module* m = qobject_cast<LightApp_Module*>( module( moduleTitle( name ) ) );
+ if ( m )
+ {
+ m->createPreferences();
+ emptyPreferences( moduleTitle( name ) );
+ }
+ }
+ // add Help items
+ createHelpItems( moduleTitle( name ) );
+ // extend module catalog
+ QString catalogue = QDir( resDir ).filePath( QString( "%1Catalog.xml" ).arg( name ) );
+ addCatalogue( name, catalogue );
+ // update windows (in particular, Info panel)
+ updateWindows();
+ // save module in the resource manager
+ if ( interactive )
+ {
+ QStringList customModules = resMgr->stringValue("launch", "user_modules").split(";", QString::SkipEmptyParts);
+ customModules << name;
+ customModules.removeDuplicates();
+ resMgr->setValue( "launch", "user_modules", customModules.join( ";" ) );
+ resMgr->setValue( "user_modules", name, root );
+ }
+ return true;
+}
+
+/*!Remove user module from UI.*/
+void LightApp_Application::removeUserModule(const QString& moduleInnerName, LightApp_ModuleAction* moduleAction)
+{
+ MESSAGE("Remove a module from UI...");
+ SCRUTE(moduleInnerName.toStdString());
+
+ // There is a some confusion point, because now we have a module's 'inner' name
+ // from the extension's salomexd file.
+ // But, in the next GUI methods we need to use a module title (user name).
+ // For example, PYHELLO (inner name) and PyHello (user name to display in GUI).
+ // Then, from the inner module's name we need to get a user one.
+ QString moduleUserName = moduleTitle(moduleInnerName);
+ SCRUTE(moduleUserName.toStdString());
+
+ // Set current state in modules combo box
+ // Don't confuse again, because activeModule()->moduleName() returns a module title, not an inner one!
+ if (activeModule() && activeModule()->moduleName() == moduleUserName)
+ activateModule("");
+
+ // Remove from "Modules" menu and toolbar
+ if (moduleAction)
+ {
+ moduleAction->removeModule(moduleUserName);
+ }
+
+ // Remove Help menu items
+ removeHelpItems(moduleUserName);
+
+ // Remove Preferences
+ LightApp_Preferences* prefs = preferences();
+ if (prefs)
+ prefs->removeModule(moduleUserName);
+
+ // Remove settings
+ // Here we use an inner module name!
+ QStringList customModules = resourceMgr()->stringValue("launch", "user_modules").split(";", QString::SkipEmptyParts);
+ customModules.removeAll(moduleInnerName);
+ resourceMgr()->setValue("launch", "user_modules", customModules.join(";"));
+ removeModuleInfo(moduleInnerName);
+}
+
+/*!On module removing action.*/
+void LightApp_Application::onExtRemoving(const QString& title)
+{
+ MESSAGE("Remove an extension...");
+ std::string extName = title.toStdString();
+ SCRUTE(extName);
+
+ // Ask user if he's ready to completely remove an extension and all its modules.
+ int answer = SUIT_MessageBox::question(
+ desktop(),
+ tr("TLT_REMOVE_EXTENSION"),
+ tr("QUE_REMOVE_EXTENSION").arg(title),
+ SUIT_MessageBox::Ok | SUIT_MessageBox::Cancel,
+ SUIT_MessageBox::Ok
+ );
+
+ if (answer == SUIT_MessageBox::Cancel)
+ {
+ MESSAGE("Removing of an extension was cancelled");
+ return; // cancelled
+ }
+
+ if (activeStudy() && activeStudy()->isModified() && !onSaveDoc())
+ {
+ // doc is not saved, or saving cancelled
+ SUIT_MessageBox::warning(
+ desktop(),
+ tr("WRN_WARNING"), tr("WRN_CANCEL_REMOVE_EXTENSION_UNSAVE").arg(title)
+ );
+
+ return;
+ }
+
+ // It should be set on the app start
+ auto extRootDir = getenv(salomeAppDir);
+ if (!extRootDir)
+ {
+ SUIT_MessageBox::warning(desktop(), tr("WRN_WARNING"), tr("WRN_SALOME_APPLICATION_DIR"));
+ return;
+ }
+ SCRUTE(extRootDir);
+
+ // Import Python module that manages SALOME extensions.
+ PyLockWrapper lck; // acquire GIL
+ PyObjWrapper extensionRemover = PyImport_ImportModule((char*)"SalomeOnDemandTK.extension_remover");
+ PyObjWrapper removedModules = PyObject_CallMethod(
+ extensionRemover, (char*)"remove_salomex", (char*)"ss", extRootDir, extName.c_str());
+ if (!removedModules || removedModules == Py_None)
+ {
+ SUIT_MessageBox::warning(desktop(), tr("WRN_WARNING"), tr("WRN_FAILED_REMOVE_EXTENSION").arg(title));
+ return;
+ }
+
+ // We need it to remove ext and modules from UI
+ LightApp_ModuleAction* moduleAction = qobject_cast<LightApp_ModuleAction*>(action(ModulesListId));
+ if (!moduleAction)
+ {
+ MESSAGE("Cannot get a pointer to LightApp_ModuleAction! Removing from menue and toolbars will skipped.");
+ }
+
+ // Module's content was already removed on python remove_salomex call,
+ // then all we do next - just remove UI items.
+ for (Py_ssize_t pos = 0; pos < PyList_Size(removedModules); ++pos)
+ {
+ // Get the current module's name
+ auto moduleNameItem = PyList_GetItem(removedModules, pos);
+ const QString moduleInnerName(PyUnicode_AsUTF8(moduleNameItem));
+
+ removeUserModule(moduleInnerName, moduleAction);
+ }
+
+ // Remove an ext from UI
+ if (moduleAction)
+ {
+ moduleAction->removeExtension(title);
+ }
+
+ // Update windows (in particular, Info panel)
+ updateWindows();
+}
+
+/*!On show extension info action.*/
+void LightApp_Application::onShowExtInfo()
+{
+ // Show dialog with information about loaded salome extensions
+ LightApp_ExtInfoDlg dlg(desktop());
+ dlg.exec();
}
/*!Default module activation.*/
case NewPyViewerId:
type = PyViewer_Viewer::Type();
break;
+#endif
+#ifndef DISABLE_PV3DVIEWER
+ case NewPV3DViewId:
+ type = PV3DViewer_ViewModel::Type();
+ break;
#endif
}
void LightApp_Application::onOpenDoc()
{
SUIT_Study* study = activeStudy();
-
+
if ( !checkExistingDoc( false ) )
return;
-
+
QString aName = getFileName( true, QString(), getFileFilter( true ), QString(), 0 );
if ( aName.isNull() ) //Cancel
return;
-
+
onOpenDoc( aName );
-
+
if ( !study ) // new study will be create in THIS application
{
updateWindows();
if( a )
a->setEnabled( activeStudy() );
#endif
+
+#ifndef DISABLE_PV3DVIEWER
+ a = action( NewPV3DViewId );
+ if( a )
+ a->setEnabled( activeStudy() );
+#endif
}
/*!
{
// normalize path
if ( myUrl.startsWith( "file://", Qt::CaseInsensitive ) )
- myUrl = myUrl.remove( 0, QString( "file://" ).count() );
+ myUrl = myUrl.remove( 0, QString( "file://" ).count() );
// For the external browser we always specify 'file://' protocol,
// because some web browsers (e.g. Mozilla Firefox) can't open local file without protocol.
myUrl = myUrl.prepend( "file://" );
#else
QString cmdLine = QString( "%1 %2 \"%3\"" ).arg( myBrowser, myParameters, myUrl );
// remove LD_LIBRARY_PATH from the environement before starting launcher to avoid bad interactions.
- // (especially in the case of universal binaries)
+ // (especially in the case of universal binaries)
env.remove("LD_LIBRARY_PATH");
#endif
QProcess* proc = new QProcess();
QString rootDir = Qtx::getenv( (component + "_ROOT_DIR").toLatin1().constData() );
if ( !rootDir.isEmpty() )
{
- path = (QStringList() << rootDir << "share" << "doc" << "salome" << "gui" << component << url).join( QDir::separator() );
+ path = (QStringList() << rootDir << "share" << "doc" << "salome" << "gui" << component << url).join( QDir::separator() );
}
}
}
}
#endif
+#ifndef DISABLE_PV3DVIEWER
+# ifndef DISABLE_SALOMEOBJECT
+ if ( vmType == SPV3D_ViewModel::Type() )
+# else
+ if ( vmType == PV3DViewer_ViewModel::Type() )
+# endif
+ {
+ viewMgr = new SPV3D_ViewManager( activeStudy(), desktop() );
+ SPV3D_ViewModel* vm = dynamic_cast<SPV3D_ViewModel*>( viewMgr->getViewModel() );
+ if ( vm )
+ {
+ // vm->setBackground(...); //NYI
+ // vm->...
+
+ new LightApp_PV3DSelector( vm, mySelMgr );
+ }
+#else
+ viewMgr = new PV3DViewer_ViewManager( activeStudy(), desktop() );
+ PV3DViewer_ViewModel* vm = dynamic_cast<PV3DViewer_ViewModel*>( viewMgr->getViewModel() );
+ if ( vm )
+ {
+ // vm->setBackground(...); //NYI
+ }
+#endif
+ }
+
if ( !viewMgr )
return 0;
if ( !crt )
return myPrefs;
- SUIT_ResourceMgr* resMgr = resourceMgr();
-
QList<SUIT_Application*> appList = SUIT_Session::session()->applications();
for ( QList<SUIT_Application*>::iterator appIt = appList.begin(); appIt != appList.end(); ++appIt )
{
QStringList names;
app->modules( names, false );
- // icons of modules
- QMap<QString, QString> icons;
- app->moduleIconNames( icons );
-
// step 1: iterate through list of all available modules
// and add empty preferences page
for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it )
if ( !_prefs_->hasModule( *it ) ) // prevent possible duplications
{
int modId = _prefs_->addPreference( *it ); // add empty page
- if ( icons.contains( *it ) ) // set icon
- _prefs_->setItemIcon( modId, Qtx::scaleIcon( resMgr->loadPixmap( moduleName( *it ),
- icons[*it], false ), 20 ) );
+ _prefs_->setItemIcon( modId, moduleIcon( *it, 20 ) ); // scale icon to 20x20 pix
}
}
}
}
+void LightApp_Application::moduleDeactivated( CAM_Module* /*mod*/ )
+{
+ if ( infoPanel() )
+ infoPanel()->clear();
+}
+
void LightApp_Application::emptyPreferences( const QString& modName )
{
QtxPreferenceItem* item = myPrefs->findItem( modName, true );
pref->setItemProperty( "step", 0.1, light_dz );
// ... "Light source" group <<end>>
+ // ... "View cube" group <<start>>
+ int occViewCubeGroup = pref->addPreference( tr( "PREF_GROUP_VIEWCUBE" ), occGroup );
+ pref->setItemProperty( "columns", 2, occViewCubeGroup );
+ // .... -> show view cube on viewer start
+ pref->addPreference( tr( "PREF_VIEWCUBE_SHOW" ), occViewCubeGroup,
+ LightApp_Preferences::Bool, "OCCViewer", "viewcube_show" );
+ // .... -> view cube duration of animation (sec)
+ int viewcube_dur = pref->addPreference( tr( "PREF_VIEWCUBE_DURATION" ), occViewCubeGroup,
+ LightApp_Preferences::DblSpin, "OCCViewer", "viewcube_duration" );
+ pref->setItemProperty( "min", 0.1, viewcube_dur );
+ pref->setItemProperty( "max", 10.0, viewcube_dur );
+ pref->setItemProperty( "step", 0.1, viewcube_dur );
+ // .... -> show view cube axes
+ pref->addPreference( tr( "PREF_VIEWCUBE_AXES" ), occViewCubeGroup,
+ LightApp_Preferences::Bool, "OCCViewer", "viewcube_axes" );
+ // ... "View cube" group <<end>>
+
+ // ... "View cube default (OCCT) attributes" group <<start>>
+ int occViewCubeAttrsGroup = pref->addPreference( tr( "PREF_VIEWCUBE_CUSTOM" ), occGroup,
+ LightApp_Preferences::Auto, "OCCViewer", "viewcube_custom" );
+ pref->setItemProperty( "columns", 2, occViewCubeAttrsGroup );
+ // .... -> box color
+ pref->addPreference( tr( "PREF_VIEWCUBE_COLOR" ), occViewCubeAttrsGroup,
+ LightApp_Preferences::Color, "OCCViewer", "viewcube_color" );
+ // .... -> view cube size
+ int viewcube_size = pref->addPreference( tr( "PREF_VIEWCUBE_SIZE" ), occViewCubeAttrsGroup,
+ LightApp_Preferences::DblSpin, "OCCViewer", "viewcube_size" );
+ pref->setItemProperty( "min", 30.0, viewcube_size );
+ pref->setItemProperty( "max", 100.0, viewcube_size );
+ pref->setItemProperty( "step", 10.0, viewcube_size );
+ // .... -> text color
+ pref->addPreference( tr( "PREF_VIEWCUBE_TEXTCOLOR" ), occViewCubeAttrsGroup,
+ LightApp_Preferences::Color, "OCCViewer", "viewcube_text_color" );
+ // ... "View cube" group <<end>>
+
// ... -> empty frame (for layout) <<start>>
int occGen = pref->addPreference( "", occGroup, LightApp_Preferences::Frame );
pref->setItemProperty( "margin", 0, occGen );
int vtkSelectionGroup = pref->addPreference( tr( "PREF_GROUP_SELECTION" ), vtkGroup );
pref->setItemProperty( "columns", 2, vtkSelectionGroup );
// .... -> preselection
- int vtkPreselection = pref->addPreference( tr( "PREF_PRESELECTION" ), vtkSelectionGroup,
+ int vtkPreselection = pref->addPreference( tr( "PREF_PRESELECTION" ), vtkSelectionGroup,
LightApp_Preferences::Selector, "VTKViewer", "preselection" );
aValuesList.clear();
anIndicesList.clear();
int spacemousePref2 = pref->addPreference( tr( "PREF_SPACEMOUSE_FUNC_2" ), vtkSM,
LightApp_Preferences::Selector, "VTKViewer",
"spacemouse_func2_btn" );
- // .... -> dominant / combined switch
+ // .... -> dominant / combined switch
int spacemousePref3 = pref->addPreference( tr( "PREF_SPACEMOUSE_FUNC_3" ), vtkSM,
LightApp_Preferences::Selector, "VTKViewer",
"spacemouse_func5_btn" ); //
}
#endif
+#ifndef DISABLE_OCCVIEWER
+ if ( sec == QString( "OCCViewer" ) && param.contains( "viewcube" ) )
+ {
+ QList<SUIT_ViewManager*> lst;
+ viewManagers( OCCViewer_Viewer::Type(), lst );
+ QListIterator<SUIT_ViewManager*> it( lst );
+ while ( it.hasNext() )
+ {
+ SUIT_ViewModel* vm = it.next()->getViewModel();
+ if ( !vm || !vm->inherits( "OCCViewer_Viewer" ) )
+ continue;
+
+ OCCViewer_Viewer* occVM = (OCCViewer_Viewer*)vm;
+ occVM->setViewCubeParamsFromPreferences();
+ }
+ }
+#endif
+
if ( sec == QString( "3DViewer" ) && param == QString( "zooming_mode" ) )
{
int mode = resMgr->integerValue( "3DViewer", "zooming_mode", 0 );
*/
void LightApp_Application::updateModuleActions()
{
- QString modName;
- if ( activeModule() )
- modName = activeModule()->moduleName();
-
- LightApp_ModuleAction* moduleAction =
- qobject_cast<LightApp_ModuleAction*>( action( ModulesListId ) );
- if ( moduleAction )
- moduleAction->setActiveModule( modName );
-}
-
-void LightApp_Application::removeModuleAction( const QString& modName )
-{
- LightApp_ModuleAction* moduleAction =
- qobject_cast<LightApp_ModuleAction*>( action( ModulesListId ) );
- if ( moduleAction )
- moduleAction->removeModule( modName );
+ emit moduleActivated( activeModule() ? activeModule()->moduleName() : QString() );
}
bool LightApp_Application::checkModule( const QString& title )
infoPanel()->addLabel( action( FileNewId )->statusTip(), grp );
infoPanel()->addAction( action( FileOpenId ), grp );
infoPanel()->addLabel( action( FileOpenId )->statusTip(), grp );
- infoPanel()->addAction( action( TutorialsId ), grp );
- infoPanel()->addLabel( action( TutorialsId )->statusTip(), grp );
+ if ( HAS_TUTORIAL_URL ) {
+ infoPanel()->addAction( action( TutorialsId ), grp );
+ infoPanel()->addLabel( action( TutorialsId )->statusTip(), grp );
+ }
infoPanel()->addAction( action( VideosId ), grp );
infoPanel()->addLabel( action( VideosId )->statusTip(), grp );
aResMgr->value( "windows_visibility", modName, aDefaultVisibility );
bool hasDefaultVisibility = !aDefaultVisibility.isEmpty();
aResMgr->setWorkingMode( prevMode );
-
+
if( !storeWin && !storeTb && aDefaultState.isEmpty() && !hasDefaultVisibility)
return;
QMap<QString, bool> *tbMap = 0;
QMap<QString, bool> *dwMap = 0;
-
+
QMap<QString, bool> userTbMap, userDwMap;
dockWindowsState( myWinVis[modName], userTbMap, userDwMap );
QMap<QString, bool> defaultTbMap, defaultDwMap;
if(hasDefaultVisibility) {
- dockWindowsState( aDefaultVisibility, defaultTbMap, defaultDwMap);
+ dockWindowsState( aDefaultVisibility, defaultTbMap, defaultDwMap);
}
if(storeTb) {
if(tbMap) {
QList<QToolBar*> tbList = findToolBars();
for ( QList<QToolBar*>::iterator tit = tbList.begin(); tit != tbList.end(); ++tit )
- {
+ {
QToolBar* tb = *tit;
- if ( tbMap->contains( tb->objectName() ) ) {
+ if ( tbMap->contains( tb->objectName() ) ) {
tb->setVisible( (*tbMap)[tb->objectName()] );
}
}
for ( QList<QDockWidget*>::iterator dit = dwList.begin(); dit != dwList.end(); ++dit )
{
QDockWidget* dw = *dit;
-
+
QObject* po = Qtx::findParent( dw, "QMainWindow" );
if ( po != desktop() )
continue;
-
+
if ( dwMap->contains( dw->objectName() ) )
dw->setVisible( (*dwMap)[dw->objectName()] );
}
}
}
-/*!
- Adds icon names for modules
-*/
-void LightApp_Application::moduleIconNames( QMap<QString, QString>& iconMap ) const
+QPixmap LightApp_Application::moduleIcon( const QString& moduleTitle, const int size ) const
{
- iconMap.clear();
-
- SUIT_ResourceMgr* resMgr = resourceMgr();
- if ( !resMgr )
- return;
-
- QStringList modList;
- modules( modList, false );
-
- for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
+ QPixmap icon;
+ if ( resourceMgr() )
{
- QString modName = *it;
- QString modIntr = moduleName( modName );
- QString modIcon = resMgr->stringValue( modIntr, "icon", QString() );
-
- if ( modIcon.isEmpty() )
- continue;
-
- if ( SUIT_Tools::extension( modIcon ).isEmpty() )
- modIcon += QString( ".png" );
-
- iconMap.insert( modName, modIcon );
+ QPixmap defaultIcon = resourceMgr()->loadPixmap( "LightApp", tr( "APP_MODULE_ICO" ), QPixmap( imageEmptyIcon ) );
+ QString iconName = resourceMgr()->stringValue( moduleName( moduleTitle ), "icon", QString() );
+ icon = resourceMgr()->loadPixmap( moduleName( moduleTitle ), iconName, defaultIcon );
+ if ( size > 0 )
+ icon = Qtx::scaleIcon( icon, size );
}
+ return icon;
}
/*!
#else
aTypesList<<VTKViewer_Viewer::Type();
#endif
+#endif
+#ifndef DISABLE_PV3DVIEWER
+ aTypesList<<PV3DViewer_ViewModel::Type();
#endif
return aTypesList;
}
}
else if ( message.toLower().startsWith("register_module_in_study" ) ) {
QString moduleName = message.split( sectionSeparator ).last();
- // Check name of current activating module name in order to avoid ciclik
+ // Check name of current activating module name in order to avoid ciclik
// call because of messages
if (!property("activateModule").toBool()) {
CAM_Module* mod = module(moduleName);
}
/*!
- Internal method.
+ Internal method.
Returns all top level toolbars.
Note : Result list contains only main window toolbars, not including toolbars from viewers.
*/
if ( aDisplayer ) {
Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
if ( aDisplayer->canBeDisplayed( obj->entry(), theViewModel->getType() ) ) {
- if ( aView && aDisplayer->IsDisplayed( obj->entry(), aView ) )
+ if ( aDisplayer->IsDisplayed( obj->entry(), aView ) )
anObjState = Qtx::ShownState;
else
anObjState = Qtx::HiddenState;
if( activeStudy() ) {
int answer = !activeStudy()->isModified() ? 1 :
SUIT_MessageBox::question( desktop(),
- tr( "APPCLOSE_CAPTION" ),
- tr( "STUDYCLOSE_DESCRIPTION" ),
- tr( "APPCLOSE_SAVE" ),
- tr( "APPCLOSE_CLOSE" ),
- tr( "APPCLOSE_CANCEL" ), 0 );
+ tr( "APPCLOSE_CAPTION" ),
+ tr( "STUDYCLOSE_DESCRIPTION" ),
+ tr( "APPCLOSE_SAVE" ),
+ tr( "APPCLOSE_CLOSE" ),
+ tr( "APPCLOSE_CANCEL" ), 0 );
if(answer == 0) {
if ( activeStudy()->isSaved() ) {
onSaveDoc();
- if (closeExistingDoc) {
- closeDoc(false);
- }
+ if (closeExistingDoc) {
+ closeDoc(false);
+ }
} else if ( onSaveAsDoc() ) {
if (closeExistingDoc) {
if( !closeDoc( false ) ) {
}
else if( answer == 1 ) {
if (closeExistingDoc) {
- closeDoc( false );
+ closeDoc( false );
}
} else if( answer == 2 ) {
result = false;
}
#endif // DISABLE_PYCONSOLE
+
+void LightApp_Application::createHelpItems( const QString& modTitle )
+{
+ if ( modTitle.isEmpty() )
+ return;
+
+ QString userGuide = "User's Guide";
+ QString devGuide = "Developer's Guide";
+
+ int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, -1, 1000 );
+
+ createMenu( userGuide, helpMenu, -1, 5 );
+ createMenu( devGuide, helpMenu, -1, 5 );
+
+ IMap <QString, QString> helpData; // list of help files for the module
+ QString helpSubMenu; // help submenu name (empty if not needed)
+ QString modName = moduleName( modTitle ); // module name
+ if ( modName.isEmpty() ) modName = modTitle; // for KERNEL and GUI
+ QString rootDir = QString( "%1_ROOT_DIR" ).arg( modName ); // module root dir env variable
+ QString modDir = Qtx::getenv( rootDir.toUtf8().constData() ); // module root dir path
+ QString docSection;
+ if ( resourceMgr()->hasValue( modName, "documentation" ) )
+ docSection = resourceMgr()->stringValue( modName, "documentation" );
+ else if ( resourceMgr()->hasSection( modName + "_documentation" ) )
+ docSection = modName + "_documentation";
+ if ( !docSection.isEmpty() )
+ {
+ helpSubMenu = resourceMgr()->stringValue( docSection, "sub_menu", "" );
+ if ( helpSubMenu.contains( "%1" ) )
+ helpSubMenu = helpSubMenu.arg( modTitle );
+ foreach( QString paramName, resourceMgr()->parameters( docSection ) )
+ {
+ QString key = paramName.contains( "%1" ) ? paramName.arg( modTitle ) : paramName;
+ QString helpItem = getHelpItem( docSection, paramName );
+ if ( !helpItem.isEmpty() )
+ helpData.insert( key, helpItem );
+ }
+ }
+
+ if ( helpData.isEmpty() && !modDir.isEmpty() )
+ {
+ QStringList idxLst = QStringList() << modDir << "share" << "doc" << "salome" << "gui" << modName << "index.html";
+ QString indexFile = idxLst.join( QDir::separator() ); // index file
+ if ( QFile::exists( indexFile ) )
+ helpData.insert( tr( "%1 module Users's Guide" ).arg( modTitle ), indexFile );
+ }
+
+ IMapConstIterator<QString, QString > fileIt;
+ for ( fileIt = helpData.begin(); fileIt != helpData.end(); fileIt++ )
+ {
+ QString helpItemPath = fileIt.key();
+ // remove all '//' occurances
+ while ( helpItemPath.contains( "//" ) )
+ helpItemPath.replace( "//", "" );
+ // obtain submenus hierarchy if given
+ QStringList smenus = helpItemPath.split( "/" );
+ helpItemPath = smenus.takeLast();
+ // workaround for User's Guide and Developer's Guide to avoid having single item in module's submenu.
+ if ( helpItemPath == userGuide || helpItemPath == devGuide )
+ {
+ QString menuPath = smenus.join( "/" );
+ QStringList allKeys = helpData.keys();
+ QStringList total = allKeys.filter( QRegExp( QString( "^%1" ).arg( menuPath ) ) );
+ if ( total.count() == 1 && smenus.count() > 0 )
+ helpItemPath = smenus.takeLast();
+ }
+ QPixmap helpIcon = fileIt.value().startsWith( "http", Qt::CaseInsensitive ) ?
+ resourceMgr()->loadPixmap( "STD", tr( "ICON_WWW" ), false ) :
+ resourceMgr()->loadPixmap( "STD", tr( "ICON_HELP" ), false );
+ QAction* a = createAction( -1, helpItemPath, helpIcon, helpItemPath, helpItemPath,
+ 0, desktop(), false, this, SLOT( onHelpContentsModule() ) );
+ a->setData( fileIt.value() );
+ if ( !helpSubMenu.isEmpty() )
+ smenus.prepend( helpSubMenu );
+ // create sub-menus hierarchy
+ int menuId = helpMenu;
+ foreach ( QString subMenu, smenus )
+ menuId = createMenu( subMenu, menuId, -1, 5 );
+ createMenu( a, menuId, -1, ( menuId != helpMenu && ( helpItemPath == userGuide || helpItemPath == devGuide ) ) ? 0 : 5 );
+ if ( !myHelpItems.contains( modName ) )
+ myHelpItems[modName] = IdList();
+ myHelpItems[modName].append( actionId( a ) );
+ }
+}
+
+void LightApp_Application::removeHelpItems( const QString& modTitle )
+{
+ QString modName = moduleName( modTitle );
+ if ( myHelpItems.contains( modName ) )
+ {
+ foreach( int id, myHelpItems[modName] )
+ setMenuShown( id, false );
+ myHelpItems.remove( modName );
+ }
+}