Salome HOME
Copyright update 2021
[modules/gui.git] / src / Qtx / Qtx.cxx
old mode 100755 (executable)
new mode 100644 (file)
index c60b75b..28cf2c3
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2021  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
 #include <QApplication>
 #include <QDesktopWidget>
 #include <QtDebug>
+#include <QSurfaceFormat>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <clocale>
 
+#ifdef WIN32
+#include <windows.h>
+#define MAX_VALUE_SIZE 32767 // Limit according to http://msdn.microsoft.com/en-us/library/ms683188.aspx
+#endif
+
+#include <iostream>
+
 #define BICOLOR_CHANGE_HUE
 
 /*!
@@ -273,30 +281,54 @@ void Qtx::simplifySeparators( QWidget* wid, const bool recursive )
   if ( !wid )
     return;
 
-  QList<QAction*> items = wid->actions();
-  if ( items.isEmpty() )
-    return;
-
-  QList<QAction*> toRemove;
-  for ( int i = 1; i < items.count(); i++ )
+  if ( wid->inherits( "QMenu") || wid->inherits( "QMenuBar") )
   {
-    if ( items[i]->isSeparator() && items[i - 1]->isSeparator() )
-      toRemove.append( items[i] );
-
-    if ( recursive && items[i]->menu() )
-      simplifySeparators( items[i]->menu(), recursive );
+    if ( qobject_cast<QMenu*>( wid ) )
+      qobject_cast<QMenu*>( wid )->setSeparatorsCollapsible( true );
+    if ( recursive )
+    {
+      foreach ( QAction* action, wid->actions() )
+      {
+       if ( action->menu() )
+         simplifySeparators( action->menu(), recursive );
+      }
+    }
   }
+  else
+  {
+    QList<QAction*> actions = wid->actions();
+    if ( actions.isEmpty() )
+      return;
 
-  for ( QList<QAction*>::iterator it = toRemove.begin(); it != toRemove.end(); ++it )
-    wid->removeAction( *it );
-
-  items = wid->actions();
-  if ( !items.isEmpty() && items[0]->isSeparator() )
-    wid->removeAction( items[0] );
-
-  items = wid->actions();
-  if ( !items.isEmpty() && items[items.count() - 1]->isSeparator() )
-    wid->removeAction( items[items.count() - 1] );
+    bool is_action = false;
+    for ( int i = 0; i < actions.count(); i++ )
+    {
+      QAction* action = actions[i];
+      if ( action->isSeparator() )
+      {
+       action->setVisible( is_action );
+       is_action = false;
+      }
+      else if ( action->isVisible() )
+      {
+       is_action = true;
+      }
+    }
+    is_action = false;
+    for ( int i = actions.count() - 1; i > 0; i-- )
+    {
+      QAction* action = actions[i];
+      if ( action->isSeparator() )
+      {
+       action->setVisible( is_action );
+       is_action = false;
+      }
+      else if ( action->isVisible() )
+      {
+       is_action = true;
+      }
+    }
+  }
 }
 
 /*!
@@ -429,13 +461,15 @@ QString Qtx::library( const QString& str )
     name = QString( "lib" ) + name;
 #endif
 
-#ifdef WIN32
+#if defined(WIN32)
   QString libExt( "dll" );
+#elif defined(__APPLE__)
+  QString libExt( "dylib" );
 #else
   QString libExt( "so" );
 #endif
 
-  if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) )
+  if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) && ext.toLower() != QString( "dylib" ) )
   {
     if ( !name.isEmpty() && !ext.isEmpty() )
       name += QString( "." );
@@ -455,18 +489,18 @@ QString Qtx::library( const QString& str )
 */
 QString Qtx::tmpDir()
 {
-  const char* tmpdir = ::getenv( "TEMP" );
-  if ( !tmpdir )
-    tmpdir = ::getenv ( "TMP" );
-  if ( !tmpdir )
+  QString tmpdir = getenv( "TEMP" );
+  if ( tmpdir.isEmpty() )
+    tmpdir = getenv ( "TMP" );
+  if ( tmpdir.isEmpty() )
   {
 #ifdef WIN32
-    tmpdir = "C:\\";
+    tmpdir = QString("C:\\");
 #else
-    tmpdir = "/tmp";
+    tmpdir = QString("/tmp");
 #endif
   }
-  return QString( tmpdir );
+  return tmpdir;
 }
 
 /*!
@@ -533,14 +567,14 @@ QString Qtx::addSlash( const QString& path )
 */
 bool Qtx::dos2unix( const QString& absName )
 {
-  FILE* src = ::fopen( absName.toLatin1(), "rb" );
+  FILE* src = ::fopen( absName.toUtf8(), "rb" );
   if ( !src )
     return false;
 
   /* we'll use temporary file */
   char temp[512] = { '\0' };
   QString dir = Qtx::dir( absName );
-  FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toLatin1(), "__x" ) ), "wb" );
+  FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toUtf8(), "__x" ) ), "wb" );
   if ( !tgt )
     return false;
 
@@ -555,7 +589,7 @@ bool Qtx::dos2unix( const QString& absName )
     char inbuf[512], outbuf[512];
 
     /* convert buffer */
-    int nbread = ::fread( inbuf, 1, sizeof( inbuf ), src );
+    int nbread = (int)::fread( inbuf, 1, sizeof( inbuf ), src ); //!< TODO: conversion from 'size_t' to 'int'
     for ( int incnt = 0; incnt < nbread; incnt++  )
     {
       if ( waitingLF )
@@ -576,7 +610,7 @@ bool Qtx::dos2unix( const QString& absName )
     waitingLF = ( inbuf[nbread - 1] == CR );
 
     /* write converted buffer to temp file */
-    int nbwri = ::fwrite( outbuf, 1, outcnt, tgt );
+    int nbwri = (int)::fwrite( outbuf, 1, outcnt, tgt ); //!< TODO: conversion from 'size_t' to 'int'
     if ( nbwri != outcnt )
     {
       ::fclose( src );
@@ -651,11 +685,17 @@ QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
 /*!
   \brief Parse given string to retrieve environment variable.
 
-  Looks through the string for the patterns: ${name} or $(name) or %name%.
+  Looks through the string for the environment variable patterns.
   If string contains variable satisfying any pattern, the variable name
   is returned, start index of the variable is returned in the \a start parameter,
   and length of the variable is returned in the \a len parameter.
 
+  Supported environment variables definitions:
+  - ${name} or $name : Linux shell variable
+  - $(name)          : GNU make substitution
+  - %name%           : Windows shell variable
+  - %(name)s         : Python substitutions:
+
   \param str string being processed
   \param start if variable is found, this parameter contains its starting 
          position in the \a str
@@ -667,30 +707,22 @@ QString Qtx::findEnvVar( const QString& str, int& start, int& len )
   QString varName;
   len = 0;
 
-  QRegExp rx( "(^\\$\\{|[^\\$]\\$\\{)([a-zA-Z]+[a-zA-Z0-9_]*)(\\})|(^\\$\\(|[^\\$]\\$\\()([a-zA-Z]+[a-zA-Z0-9_]*)(\\))|(^\\$|[^\\$]\\$)([a-zA-Z]+[a-zA-Z0-9_]*)|(^%|[^%]%)([a-zA-Z]+[a-zA-Z0-9_]*)(%[^%]|%$)" );
-
-  int pos = rx.indexIn( str, start );
-  if ( pos != -1 )
+  QStringList rxList;
+  rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name}
+  rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)";       // $name
+  rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name)
+  rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%";        // %name%
+  rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s";  // %(name)s
+  
+  for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i ) 
   {
-    int i = 1;
-    while ( i <= rx.captureCount() && varName.isEmpty() )
+    QRegExp rx(rxList[i]);
+    int pos = rx.indexIn( str, start );
+    if ( pos != -1 )
     {
-      QString capStr = rx.cap( i );
-      if ( !capStr.contains( "%" ) && !capStr.contains( "$" ) )
-        varName = capStr;
-      i++;
-    }
-
-    if ( !varName.isEmpty() )
-    {
-      int capIdx = i - 1;
-      start = rx.pos( capIdx );
-      int end = start + varName.length();
-      if ( capIdx > 1 && rx.cap( capIdx - 1 ).contains( QRegExp( "\\$|%" ) ) )
-        start = rx.pos( capIdx - 1 ) + rx.cap( capIdx - 1 ).indexOf( QRegExp( "\\$|%" ) );
-      if ( capIdx < rx.captureCount() && !rx.cap( capIdx - 1 ).isEmpty() )
-        end++;
-      len = end - start;
+      varName = rx.cap( 1 );
+      start = pos;
+      len = rx.matchedLength();
     }
   }
   return varName;
@@ -719,8 +751,8 @@ QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
         break;
 
       QString newStr;
-      if ( ::getenv( envName.toLatin1() ) || mode == Always )
-        newStr = QString( ::getenv( envName.toLatin1() ) );
+      if ( getenv( envName ).isEmpty() || mode == Always )
+        newStr = QString( getenv( envName ) );
 
       if ( newStr.isNull() )
       {
@@ -1707,9 +1739,14 @@ Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
   
   To use the Localizer class, just create a local variable in the beginning
   of the code where you need to read / write data from textual file(s).
-  The constructor of the class forces setting "C" locale temporariy.
+  The constructor of the class forces setting "C" locale temporarily.
   The destructor switches back to the initial locale.
 
+  There are two ways to create a localizer.
+  First constructor accepts category and locale value to be forced as parameters.
+  The second constructor does not take parameters, and is just a shortcut to the
+  first one, setting LC_NUMERIC as a category and "C" as a locale to force.
+  
   \code
   Qtx::Localizer loc;
   readSomething();
@@ -1718,12 +1755,30 @@ Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
 */
 
 /*!
-  \brief Constructor. Forces "C" locale to be set.
+  \brief Default constructor. Forces "C" locale to be set as LC_NUMERIC.
 */
 Qtx::Localizer::Localizer()
 {
-  myCurLocale = setlocale( LC_NUMERIC, 0 );
-  setlocale( LC_NUMERIC, "C" );
+  init( LC_NUMERIC, "C" );
+}
+
+/*!
+  \brief Constructor. Forces \a locale to be set for \a category.
+*/
+Qtx::Localizer::Localizer( int category, const char* locale )
+{
+  init( category, locale );
+}
+
+/*!
+  \brief Internal initialization
+  \internal
+*/
+void Qtx::Localizer::init( int category, const char* locale )
+{
+  myCategory = category;
+  myOriginalLocale = setlocale( category, NULL );
+  setlocale( category, locale );
 }
 
 /*!
@@ -1731,7 +1786,7 @@ Qtx::Localizer::Localizer()
 */
 Qtx::Localizer::~Localizer()
 {
-  setlocale( LC_NUMERIC, myCurLocale.toLatin1().constData() );
+  setlocale( myCategory, myOriginalLocale.toLatin1().constData() );
 }
 
 /*!
@@ -2074,7 +2129,6 @@ long Qtx::versionToId( const QString& version )
   
   The function tries to detect qt installation directory by analyzing the system variables in the following order:
   - QT5_ROOT_DIR
-  - QT4_ROOT_DIR
   - QT_ROOT_DIR
   - QTDIR
 
@@ -2086,10 +2140,12 @@ long Qtx::versionToId( const QString& version )
 
 QString Qtx::qtDir( const QString& context )
 {
-  const char* vars[] = { "QT5_ROOT_DIR", "QT4_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
+
+  QStringList vars = { "QT5_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
   QString qtPath;
-  for (uint i = 0; i < sizeof(vars)/sizeof(vars[0]) && qtPath.isEmpty(); i++ )
-    qtPath = qgetenv( vars[i] );
+  for (int i = 0; i < vars.length() && qtPath.isEmpty(); i++ ) {
+    qtPath = getenv(vars[i]);
+  }
   if ( !qtPath.isEmpty() && !context.isEmpty() )
     qtPath = QDir( qtPath ).absoluteFilePath( context );
   return qtPath;
@@ -2106,7 +2162,37 @@ QFont Qtx::stringToFont( const QString& fontDescription )
   return font;
 }
 
+QString Qtx::getenv(const QString & envVar)
+{
+       QString value;
 #ifndef WIN32
+       value = qgetenv(envVar.toLocal8Bit().constData());
+#else
+       LPTSTR buff = new TCHAR[MAX_VALUE_SIZE];
+#ifdef UNICODE
+       LPTSTR anEnvVar = new TCHAR[envVar.length() + 1];       
+       anEnvVar[envVar.toWCharArray(anEnvVar)] = '\0';
+#else
+       const TCHAR* anEnvVar = envVar.toLocal8Bit(buff).constData();
+#endif 
+       const DWORD ret = GetEnvironmentVariable(anEnvVar, buff, MAX_VALUE_SIZE);
+       buff[ret] = '\0';
+       if (ret > 0) {
+#ifdef UNICODE
+               value = QString::fromWCharArray(buff);
+#else
+               value = QString::fromLocal8Bit(buff);
+#endif 
+       }
+       delete buff;
+#ifdef UNICODE
+       delete anEnvVar;
+#endif
+#endif
+       return value;
+}
+
+#if !defined WIN32 && !defined __APPLE__ 
 
 #include <X11/Xlib.h>
 #include <GL/glx.h>
@@ -2176,6 +2262,42 @@ Qt::HANDLE Qtx::getVisual()
 
 #endif // WIN32
 
+/*!
+  \brief Set default QSurfaceFormat for an application.
+
+  This application property should be set before a creation of the QApplication.
+*/  
+void Qtx::initDefaultSurfaceFormat()
+{
+  // Settings from Paraview: 
+  // This piece of code was taken from QVTKOpenGLWidget::defaultFormat() method in
+  // order to avoid dependency of the SALOME_Session_Server on vtk libraries
+  QSurfaceFormat fmt;
+  fmt.setRenderableType(QSurfaceFormat::OpenGL);
+  fmt.setVersion(3, 2);
+  fmt.setProfile(QSurfaceFormat::CoreProfile);
+  fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+  fmt.setRedBufferSize(1);
+  fmt.setGreenBufferSize(1);
+  fmt.setBlueBufferSize(1);
+  fmt.setDepthBufferSize(1);
+  fmt.setStencilBufferSize(0);
+#ifdef WIN32
+  fmt.setAlphaBufferSize(0);
+#else
+  fmt.setAlphaBufferSize(1);
+#endif
+  fmt.setStereo(false);
+  fmt.setSamples(0);
+  
+  // Settings for OCCT viewer window:
+  fmt.setDepthBufferSize(16);
+  fmt.setStencilBufferSize(1);
+  //  fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
+
+  QSurfaceFormat::setDefaultFormat(fmt);
+}
+
 /*!
   \class Qtx::CmdLineArgs
   \brief Get access to the command line arguments in the C-like manner.
@@ -2212,7 +2334,7 @@ Qtx::CmdLineArgs::CmdLineArgs()
 Qtx::CmdLineArgs::~CmdLineArgs()
 {
   for ( int i = 0; i < myArgc; i++ )
-    delete myArgv[i];
+    delete[] myArgv[i];
   delete[] myArgv;
 }