X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSUITApp%2FSUITApp.cxx;h=316fa764f88cfedcc9c4c0785b11f27c1e716abc;hb=320eb776e5eb37ade130d10326bf5cee4559ee86;hp=0feb3e385e432718b80e677728b00ece7a950e2d;hpb=ad6276bbf89c70b93ccef9a82800f18ff5578a00;p=modules%2Fgui.git diff --git a/src/SUITApp/SUITApp.cxx b/src/SUITApp/SUITApp.cxx index 0feb3e385..316fa764f 100644 --- a/src/SUITApp/SUITApp.cxx +++ b/src/SUITApp/SUITApp.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2023 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 @@ -20,33 +20,19 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -//#ifdefined WIN32 -//#ifndef DISABLE_PYCONSOLE -//#define DISABLE_PYCONSOLE -//#endif -//#else //#if defined WIN32 -//#ifdef DISABLE_PYCONSOLE -// NOTE: DO NOT DELETE THIS DEFINITION ON LINUX -// or make sure Python is initialized in main() in any case -// Otherwise, application based on light SALOME and using Python -// are unlikely to work properly. -//#undef DISABLE_PYCONSOLE -//#include -//#endif -// #ifndef DISABLE_PYCONSOLE #include "SUITApp_init_python.hxx" #endif -//#endif //#if defined WIN32 - #include "GUI_version.h" #include "SUITApp_Application.h" #include "SUIT_Desktop.h" #include "SUIT_LicenseDlg.h" #include "SUIT_ResourceMgr.h" #include "SUIT_Session.h" +#ifdef USE_SALOME_STYLE #include "Style_Salome.h" +#endif // USE_SALOME_STYLE #include "QtxSplash.h" #include @@ -58,233 +44,305 @@ #include -#ifdef WIN32 -#include -#endif - -static QString salomeVersion() +namespace { - return GUI_VERSION_STR; -} - -static QString getAppName( const QString& libName ) -{ - QString appName = QFileInfo( libName ).baseName(); - if ( appName.startsWith( "lib" ) ) appName = appName.mid( 3 ); - return appName; -} + //! Get version of SALOME GUI module + static QString salomeVersion() + { + return GUI_VERSION_STR; + } -// static void MessageOutput( QtMsgType type, const char* msg ) -// { -// switch ( type ) -// { -// case QtDebugMsg: -// #ifdef _DEBUG_ -// printf( "Debug: %s\n", msg ); -// #endif -// break; -// case QtWarningMsg: -// #ifdef _DEBUG_ -// printf( "Warning: %s\n", msg ); -// #endif -// break; -// case QtFatalMsg: -// #ifdef _DEBUG_ -// printf( "Fatal: %s\n", msg ); -// #endif -// break; -// default: -// break; -// } -// } - -class SUITApp_Session: public SUIT_Session -{ -public: - SUITApp_Session( bool theIniFormat, int argc, char** argv ) : SUIT_Session( argc, argv ), myIniFormat ( theIniFormat ) {} - virtual ~SUITApp_Session() {} + //! Extract application name from the library filename + static QString getAppName( const QString& libName ) + { + QString appName = QFileInfo( libName ).baseName(); + if ( appName.startsWith( "lib" ) ) + appName = appName.mid( 3 ); + return appName; + } - virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const + //! Custom resources manager, that allows customization of application name/version + // via configuration/translation files. + class ResourceMgr : public SUIT_ResourceMgr { - SUIT_ResourceMgr* resMgr = 0; - if ( myIniFormat ) + public: + ResourceMgr( bool iniFormat = false, const QString& appName = "LightApp" ) + : SUIT_ResourceMgr( appName, "%1Config" ) { - resMgr = new SUIT_ResourceMgr( appName, QString( "%1Config" ) ); - resMgr->setCurrentFormat( "ini" ); + customize( iniFormat, appName ); // activate customization + setCurrentFormat( iniFormat ? "ini" : "xml" ); + setOption( "translators", QString( "%P_msg_%L.qm|%P_icons.qm|%P_images.qm" ) ); } - else + + QString customName() const { return myCustomAppName; } + QString version() const { return myCustomAppVersion; } + + private: + static void customize( bool iniFormat, const QString& appName ) { - resMgr = new SUIT_ResourceMgr( appName, QString( "%1Config" ) ); - resMgr->setVersion( salomeVersion() ); - resMgr->setCurrentFormat( "xml" ); + // Try to retrieve actual application name and version from translation files. + // We create temporary resource manager and load translations. + // This procedure is supposed to be done only once, at first call. + if ( myCustomAppName.isNull() ) { + SUIT_ResourceMgr mgr( appName, "%1Config" ); + mgr.setCurrentFormat( iniFormat ? "ini" : "xml" ); + mgr.setWorkingMode( IgnoreUserValues ); // prevent reading data from user's file + mgr.loadLanguage( appName, "en" ); + + // actual application name can be customized via APP_NAME resource key + myCustomAppName = QObject::tr( "APP_NAME" ).trimmed(); + if ( myCustomAppName == "APP_NAME" || myCustomAppName.toLower() == "salome" ) + myCustomAppName = appName; // fallback name + + // actual application name can be customized via APP_VERSION resource key + myCustomAppVersion = QObject::tr( "APP_VERSION" ).trimmed(); + if ( myCustomAppVersion == "APP_VERSION" ) + myCustomAppVersion = myCustomAppName == appName ? salomeVersion() : ""; // fallback version + } } - if ( resMgr ) + protected: + QString userFileName( const QString& /*appName*/, const bool forLoad ) const { - resMgr->setOption( "translators", QString( "%P_msg_%L.qm|%P_icons.qm|%P_images.qm" ) ); + if ( version().isEmpty() ) return ""; + return SUIT_ResourceMgr::userFileName( myCustomAppName, forLoad ); + } + + virtual long userFileId( const QString& _fname ) const + { + ////////////////////////////////////////////////////////////////////////////////////////////// + // In SALOME and SALOME-based applications the user preferences file is named as + // - .xml. on Windows + // - rc. on Linux + // where + // * AppName is application name, defaults to LightApp. Can be customized in SALOME-based + // applications, see ResourceMgr above for more details. + // * AppVersion is application version, defaults to current version of SALOME GUI module + // if AppName is not customize, otherwise empty. Can be customized in SALOME-based + // applications, see ResourceMgr above for more details. + // + // Since version 6.5.0 of SALOME, user file is stored in the ~/.config/salome + // directory. For backward compatibility, when user preferences from nearest + // version of application is searched, user home directory is also looked through, + // with lower priority. + // + // Since version 6.6.0 of SALOME, user file name on Linux is no more prefixed by dot + // symbol since it is stored in the hidden ~/.config/salome directory. However, dot-prefixed + // files are also taken into account (with lower priority) for backward compatibility. + // + // Notes: + // - Currently the following format of version number is supported: + // [.[.[]]] + // Parts in square brackets are considered optional. Here: + // * major - major version id + // * minor - minor version id + // * release - maintenance version id + // * type - dev or patch marker; it can be either one alphabetical symbol (from 'a' to 'z') + // or 'rc' to point release candidate (case-insensitive) + // * dev - dev version or patch number + // All numerical values must be of range [1-99]. + // Examples: 1.0, 6.5.0, 1.2.0a1, 3.3.3rc3 (release candidate 3), 11.0.0p1 (patch 1) + // + // - Versioning approach can be customized by implementing and using own resource manager class, + // see QtxResurceMgr, SUIT_ResourceMgr classes, and ResourceMgr class above in this file. + ////////////////////////////////////////////////////////////////////////////////////////////// + + long id = -1; + if ( !myCustomAppName.isEmpty() ) { +#ifdef WIN32 + // On Windows, user file name is something like LightApp.xml.6.5.0 where + // - LightApp is an application name (can be customized) + // - xml is a file format (xml or ini) + // - 6.5.0 is an application version, can include alfa/beta/rc marks, e.g. 6.5.0a3, 6.5.0rc1 + QRegExp exp( QString( "%1\\.%2\\.([a-zA-Z0-9.]+)" ).arg( myCustomAppName ).arg( currentFormat() ) ); +#else + // On Linux, user file name is something like LightApprc.6.5.0 where + // - LightApp is an application name (can be customized) + // - 6.5.0 is an application version, can include alfa/beta/rc marks, e.g. 6.5.0a3, 6.5.0rc1 + + // VSR 24/09/2012: issue 0021781: since version 6.6.0 user filename is not prepended with "." + // when it is stored in the ~/.config/ directory; + // for backward compatibility we also check files prepended with "." with lower priority + QRegExp exp( QString( "\\.?%1rc\\.([a-zA-Z0-9.]+)" ).arg( myCustomAppName ) ); +#endif + QString fname = QFileInfo( _fname ).fileName(); + if ( exp.exactMatch( fname ) ) { + long fid = Qtx::versionToId( exp.cap( 1 ) ); + if ( fid > 0 ) id = fid; + } + } + return id; } - return resMgr; - } -private: - bool myIniFormat; -}; + private: + static QString myCustomAppName; + static QString myCustomAppVersion; + }; + QString ResourceMgr::myCustomAppName; + QString ResourceMgr::myCustomAppVersion; + + //! Custom session, to use custom resource manager class. + class Session : public SUIT_Session + { + public: + Session( bool theIniFormat = false ) : SUIT_Session(), myIniFormat( theIniFormat ) {} + virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const + { + return new ResourceMgr( myIniFormat, appName ); + } + private: + bool myIniFormat; + }; +} // end of anonymous namespace int main( int argc, char* argv[] ) { - //#ifndef DISABLE_PYCONSOLE - // // First of all initialize Python, as in complex multi-component applications - // // someone else might initialize it some way unsuitable for light SALOME! - // Py_SetProgramName( argv[0] ); - // Py_Initialize(); // Initialize the interpreter - // PySys_SetArgv( argc, argv ); - // PyEval_InitThreads(); // Create (and acquire) the interpreter lock - // PyEval_ReleaseLock(); // Let the others use Python API until we need it again - //#endif - - //qInstallMsgHandler( MessageOutput ); - - QStringList argList; - bool noExceptHandling = false; + // Set-up application settings configuration (as for QSettings) + // Note: these are default settings which can be customized (see below) + QApplication::setOrganizationName( "salome" ); + QApplication::setApplicationName( "salome" ); + QApplication::setApplicationVersion( salomeVersion() ); + + // Add /plugins dir to the pluins search path for image plugins + QString qtdir = Qtx::qtDir( "plugins" ); + if ( !qtdir.isEmpty() ) + QApplication::addLibraryPath( qtdir ); + + // Add application library path (to search style plugin etc...) + QString path = Qtx::addSlash( Qtx::getenv( "GUI_ROOT_DIR" ) ) + "bin/salome"; + QApplication::addLibraryPath( QDir::toNativeSeparators( path ) ); + + // QSurfaceFormat should be set before creation of QApplication, + // so to avoid conflicts beetween SALOME and ParaView QSurfaceFormats we should merge theirs formats + // (see void Qtx::initDefaultSurfaceFormat()) and set the resultant format here. + Qtx::initDefaultSurfaceFormat(); + + // Create Qt application instance: this should be done as early as possible! + // Note: QApplication forces setting locale LC_ALL to system one: setlocale(LC_ALL, ""). + SUITApp_Application app( argc, argv ); + + // Initialize Python (if necessary) + // Note: Python forces setting locale LC_CTYPE to system one: setlocale(LC_CTYPE, ""). +#ifndef DISABLE_PYCONSOLE + char* py_argv[] = {(char*)""}; + SUIT_PYTHON::init_python( 1, py_argv ); +#endif + + // Treat command line arguments + bool debugExceptions = false; bool iniFormat = false; bool noSplash = false; bool useLicense = false; - for ( int i = 1; i < argc; i++ ) + QStringList args; + foreach( QString arg, QApplication::arguments().mid(1) ) // omit 1st argument: app executable { - if ( !strcmp( argv[i], "--noexcepthandling" ) ) - noExceptHandling = true; - else if ( !strcmp( argv[i], "--format=ini") ) + if ( arg == "--no-exception-handler" ) + debugExceptions = true; + else if ( arg == "--format=ini" ) iniFormat = true; - else if ( !strcmp( argv[i], "--nosplash") ) + else if ( arg == "--no-splash" ) noSplash = true; - else if ( !strcmp( argv[i], "--uselicense" ) ) + else if ( arg == "--show-license" ) useLicense = true; - else - argList.append( QString( argv[i] ) ); + else if ( !arg.startsWith( "-" ) ) + args << arg; } + if ( args.empty() ) + args << "LightApp"; // fallback application library - // set "C" locale if requested via preferences - { - SUITApp_Session stmp( iniFormat, argc, argv ); - QApplication::setApplicationName( "salome" ); - SUIT_ResourceMgr* resMgr = stmp.createResourceMgr( "LightApp" ); - bool isCloc = resMgr->booleanValue( "language", "locale", true ); - if ( isCloc ) { - QLocale::setDefault( QLocale::c() ); - } - else { - QLocale::setDefault( QLocale::system() ); - } - } + QString appName = getAppName( args.first() ); - // add /plugins directory to the pluins search path for image plugins - QString qtdir = Qtx::qtDir( "plugins" ); - if ( !qtdir.isEmpty() ) - QApplication::addLibraryPath( qtdir ); + // Create auxiliary resource manager to access application settings + ResourceMgr resMgr( iniFormat, appName ); + resMgr.setWorkingMode( ResourceMgr::IgnoreUserValues ); + resMgr.loadLanguage( appName, "en" ); - //Set a "native" graphic system in case if application runs on the remote host - QString remote(::getenv("REMOTEHOST")); - QString client(::getenv("SSH_CLIENT")); - if(remote.length() > 0 || client.length() > 0 ) { - QApplication::setGraphicsSystem(QLatin1String("native")); - } - - SUITApp_Application app( argc, argv ); - QString cfgAppName = getAppName( argList.isEmpty() ? QString() : argList.first() ); - // hard-coding for LightApp :( no other way to this for the moment - if ( cfgAppName == "LightApp" ) { - app.setOrganizationName( "salome" ); - app.setApplicationName( "salome" ); - app.setApplicationVersion( salomeVersion() ); + // Set-up application settings configuration possible customized via resources + if ( resMgr.customName() != "LightApp" ) { + QApplication::setApplicationName( resMgr.customName() ); + QApplication::setApplicationVersion( resMgr.version() ); } - int result = -1; + // Force default "C" locale if requested via user's preferences + // Note: this does not change whole application locale (changed via setlocale() function), + // but only affects GUI behavior + resMgr.setWorkingMode( ResourceMgr::AllowUserValues ); // we must take into account user preferences + if ( resMgr.booleanValue( "language", "locale", true ) ) + QLocale::setDefault( QLocale::c() ); + resMgr.setWorkingMode( ResourceMgr::IgnoreUserValues ); - if ( useLicense ) { - QString env; +#if defined(GLOBAL_DOUBLE_CONVERSION) + // VSR 30/03/2021: moved here from QtxDoubleSpinBox/QtxIntSpinBox because of crash on Qt 5.12. + // Disable thousands separator for spin box + // see issue 14540 (old id 21219) + QLocale locale; + locale.setNumberOptions(locale.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator); + QLocale::setDefault(locale); +#endif -#ifdef WIN32 - DWORD aLen=1024; - char aStr[1024]; - HANDLE aToken=0; - HANDLE hProcess = GetCurrentProcess(); - OpenProcessToken(hProcess,TOKEN_QUERY,&aToken); - if( GetUserProfileDirectory( aToken, aStr, &aLen ) ) - env = aStr; + if ( !debugExceptions ) + debugExceptions = resMgr.booleanValue( "launch", "noexcepthandler", false ); + if ( !noSplash ) + noSplash = !resMgr.booleanValue( "launch", "splash", true ); + if ( !useLicense ) + useLicense = resMgr.booleanValue( "launch", "license", false ); -#else - if ( ::getenv( "HOME" ) ) - env = ::getenv( "HOME" ); -#endif - - QFile file( env + "/ReadLicense.log" ); // Read the text from a file - if( !file.exists() ) { + // If asked, read the text from a file show a license dialog + // TODO: path to license file, and option to check license, may be defined in XML cfg file. + if ( useLicense ) { + QFile file( QDir::home().filePath( "ReadLicense.log" ) ); + if ( !file.exists() ) { SUIT_LicenseDlg aLicense; if ( aLicense.exec() != QDialog::Accepted ) - return result; + return 1; // license is not accepted! } } - if ( !argList.isEmpty() ) + // If not disabled, show splash screen + QtxSplash* splash = 0; + if ( !noSplash ) { - SUITApp_Session aSession( iniFormat, argc, argv ); - QtxSplash* splash = 0; - SUIT_ResourceMgr* resMgr = aSession.createResourceMgr( argList.first() ); - if ( !noSplash ) - { - if ( resMgr ) - { - resMgr->loadLanguage(); - - splash = QtxSplash::splash( QPixmap() ); - splash->readSettings( resMgr ); - if ( splash->pixmap().isNull() ) { - delete splash; - splash = 0; - } - else { - QString appName = QObject::tr( "APP_NAME" ).trimmed(); - QString appVersion = QObject::tr( "APP_VERSION" ).trimmed(); - if ( appVersion == "APP_VERSION" ) - { - if ( appName == "APP_NAME" || appName.toLower() == "salome" ) - appVersion = salomeVersion(); - else - appVersion = ""; - } - splash->setOption( "%A", appName ); - splash->setOption( "%V", QObject::tr( "ABOUT_VERSION" ).arg( appVersion ) ); - splash->setOption( "%L", QObject::tr( "ABOUT_LICENSE" ) ); - splash->setOption( "%C", QObject::tr( "ABOUT_COPYRIGHT" ) ); - splash->show(); - QApplication::instance()->processEvents(); - } - } + splash = QtxSplash::splash( QPixmap() ); + splash->readSettings( &resMgr ); + if ( splash->pixmap().isNull() ) + splash->setPixmap( resMgr.loadPixmap( appName, QObject::tr( "ABOUT_SPLASH" ) ) ); + if ( splash->pixmap().isNull() ) + splash->setPixmap( resMgr.loadPixmap( "LightApp", QObject::tr( "ABOUT_SPLASH" ) ) ); + if ( splash->pixmap().isNull() ) { + delete splash; + splash = 0; + } + else { + splash->setOption( "%A", QObject::tr( "APP_NAME" ) ); + splash->setOption( "%V", QObject::tr( "ABOUT_VERSION" ).arg( resMgr.version() ) ); + splash->setOption( "%L", QObject::tr( "ABOUT_LICENSE" ) ); + splash->setOption( "%C", QObject::tr( "ABOUT_COPYRIGHT" ) ); + splash->show(); + QApplication::instance()->processEvents(); } + } -#ifndef DISABLE_PYCONSOLE - //...Initialize python - int _argc = 1; - char* _argv[] = {(char*)""}; - SUIT_PYTHON::init_python(_argc,_argv); -#endif + // Create session + Session session( iniFormat ); - SUIT_Application* theApp = aSession.startApplication( argList.first() ); - if ( theApp ) - { - Style_Salome::initialize( theApp->resourceMgr() ); - if ( theApp->resourceMgr()->booleanValue( "Style", "use_salome_style", true ) ) - Style_Salome::apply(); + // Initialize and start application supplied by the library specified via the parameter + SUIT_Application* sessionApp = session.startApplication( appName ); + if ( sessionApp ) + { +#ifdef USE_SALOME_STYLE + Style_Salome::initialize( session->resourceMgr() ); + if ( session->resourceMgr()->booleanValue( "Style", "use_salome_style", true ) ) + Style_Salome::apply(); +#endif // USE_SALOME_STYLE - if ( !noExceptHandling ) - app.setHandler( aSession.handler() ); + if ( !debugExceptions ) + app.setHandler( session.handler() ); - if ( splash ) - splash->finish( theApp->desktop() ); + if ( splash ) + splash->finish( sessionApp->desktop() ); - result = app.exec(); - } + return app.exec(); } - return result; + return 1; }