Beispiel #1
0
int main( int argc, char *argv[] )
{
#ifdef Q_OS_MACX
  // Increase file resource limits (i.e., number of allowed open files)
  // (from code provided by Larry Biehl, Purdue University, USA, from 'MultiSpec' project)
  // This is generally 256 for the soft limit on Mac
  // NOTE: setrlimit() must come *before* initialization of stdio strings,
  //       e.g. before any debug messages, or setrlimit() gets ignored
  // see: http://stackoverflow.com/a/17726104/2865523
  struct rlimit rescLimit;
  if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
  {
    rlim_t oldSoft( rescLimit.rlim_cur );
    rlim_t oldHard( rescLimit.rlim_max );
#ifdef OPEN_MAX
    rlim_t newSoft( OPEN_MAX );
    rlim_t newHard( std::min( oldHard, newSoft ) );
#else
    rlim_t newSoft( 4096 );
    rlim_t newHard( std::min(( rlim_t )8192, oldHard ) );
#endif
    if ( rescLimit.rlim_cur < newSoft )
    {
      rescLimit.rlim_cur = newSoft;
      rescLimit.rlim_max = newHard;

      if ( setrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
      {
        QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard NEW: %1 / %2" )
                     .arg( rescLimit.rlim_cur ).arg( rescLimit.rlim_max ) );
      }
    }
    QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard ORIG: %1 / %2" )
                 .arg( oldSoft ).arg( oldHard ) );
  }
#endif

  QgsDebugMsg( QString( "Starting qgis main" ) );
#ifdef WIN32  // Windows
#ifdef _MSC_VER
  _set_fmode( _O_BINARY );
#else //MinGW
  _fmode = _O_BINARY;
#endif  // _MSC_VER
#endif  // WIN32

  // Set up the custom qWarning/qDebug custom handler
#ifndef ANDROID
  qInstallMsgHandler( myMessageOutput );
#endif

#if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
  signal( SIGQUIT, qgisCrash );
  signal( SIGILL, qgisCrash );
  signal( SIGFPE, qgisCrash );
  signal( SIGSEGV, qgisCrash );
  signal( SIGBUS, qgisCrash );
  signal( SIGSYS, qgisCrash );
  signal( SIGTRAP, qgisCrash );
  signal( SIGXCPU, qgisCrash );
  signal( SIGXFSZ, qgisCrash );
#endif

#ifdef Q_OS_WIN
  SetUnhandledExceptionFilter( QgisApp::qgisCrashDump );
#endif

  // initialize random number seed
  srand( time( NULL ) );

  /////////////////////////////////////////////////////////////////
  // Command line options 'behaviour' flag setup
  ////////////////////////////////////////////////////////////////

  //
  // Parse the command line arguments, looking to see if the user has asked for any
  // special behaviours. Any remaining non command arguments will be kept aside to
  // be passed as a list of layers and / or a project that should be loaded.
  //

  // This behaviour is used to load the app, snapshot the map,
  // save the image to disk and then exit
  QString mySnapshotFileName = "";
  int mySnapshotWidth = 800;
  int mySnapshotHeight = 600;

  bool myHideSplash = false;
#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: Splash hidden" ) );
  myHideSplash = true;
#endif

  bool myRestorePlugins = true;
  bool myCustomization = true;

  // This behaviour will set initial extent of map canvas, but only if
  // there are no command line arguments. This gives a usable map
  // extent when qgis starts with no layers loaded. When layers are
  // loaded, we let the layers define the initial extent.
  QString myInitialExtent = "";
  if ( argc == 1 )
    myInitialExtent = "-1,-1,1,1";

  // This behaviour will allow you to force the use of a translation file
  // which is useful for testing
  QString myTranslationCode;

  // The user can specify a path which will override the default path of custom
  // user settings (~/.qgis) and it will be used for QSettings INI file
  QString configpath;
  QString optionpath;

  QString pythonfile;

  QString customizationfile;

#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
  //put all QGIS settings in the same place
  configpath = QgsApplication::qgisSettingsDirPath();
  QgsDebugMsg( QString( "Android: configpath set to %1" ).arg( configpath ) );
#endif

  QStringList args;

  if ( !bundleclicked( argc, argv ) )
  {
    // Build a local QCoreApplication from arguments. This way, arguments are correctly parsed from their native locale
    // It will use QString::fromLocal8Bit( argv ) under Unix and GetCommandLine() under Windows.
    QCoreApplication coreApp( argc, argv );
    args = QCoreApplication::arguments();

    for ( int i = 1; i < args.size(); ++i )
    {
      QString arg = args[i];

      if ( arg == "--help" || arg == "-?" )
      {
        usage( args[0].toStdString() );
        return 2;
      }
      else if ( arg == "--nologo" || arg == "-n" )
      {
        myHideSplash = true;
      }
      else if ( arg == "--noplugins" || arg == "-P" )
      {
        myRestorePlugins = false;
      }
      else if ( arg == "--nocustomization" || arg == "-C" )
      {
        myCustomization = false;
      }
      else if ( i + 1 < argc && ( arg == "--snapshot" || arg == "-s" ) )
      {
        mySnapshotFileName = QDir::convertSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--width" || arg == "-w" ) )
      {
        mySnapshotWidth = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == "--height" || arg == "-h" ) )
      {
        mySnapshotHeight = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == "--lang" || arg == "-l" ) )
      {
        myTranslationCode = args[++i];
      }
      else if ( i + 1 < argc && ( arg == "--project" || arg == "-p" ) )
      {
        myProjectFileName = QDir::convertSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--extent" || arg == "-e" ) )
      {
        myInitialExtent = args[++i];
      }
      else if ( i + 1 < argc && ( arg == "--optionspath" || arg == "-o" ) )
      {
        optionpath = QDir::convertSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == "--configpath" || arg == "-c" ) )
      {
        configpath = QDir::convertSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == "--code" || arg == "-f" ) )
      {
        pythonfile = QDir::convertSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--customizationfile" || arg == "-z" ) )
      {
        customizationfile = QDir::convertSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else
      {
        myFileList.append( QDir::convertSeparators( QFileInfo( args[i] ).absoluteFilePath() ) );
      }
    }
  }

  /////////////////////////////////////////////////////////////////////
  // If no --project was specified, parse the args to look for a     //
  // .qgs file and set myProjectFileName to it. This allows loading  //
  // of a project file by clicking on it in various desktop managers //
  // where an appropriate mime-type has been set up.                 //
  /////////////////////////////////////////////////////////////////////
  if ( myProjectFileName.isEmpty() )
  {
    // check for a .qgs
    for ( int i = 0; i < args.size(); i++ )
    {
      QString arg = QDir::convertSeparators( QFileInfo( args[i] ).absoluteFilePath() );
      if ( arg.contains( ".qgs" ) )
      {
        myProjectFileName = arg;
        break;
      }
    }
  }


  /////////////////////////////////////////////////////////////////////
  // Now we have the handlers for the different behaviours...
  ////////////////////////////////////////////////////////////////////

  /////////////////////////////////////////////////////////////////////
  // Initialise the application and the translation stuff
  /////////////////////////////////////////////////////////////////////

#ifdef Q_WS_X11
  bool myUseGuiFlag = getenv( "DISPLAY" ) != 0;
#else
  bool myUseGuiFlag = true;
#endif
  if ( !myUseGuiFlag )
  {
    std::cerr << QObject::tr(
                "QGIS starting in non-interactive mode not supported.\n"
                "You are seeing this message most likely because you "
                "have no DISPLAY environment variable set.\n"
              ).toUtf8().constData();
    exit( 1 ); //exit for now until a version of qgis is capabable of running non interactive
  }

  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, optionpath.isEmpty() ? configpath : optionpath );
  }

  // GUI customization is enabled according to settings (loaded when instance is created)
  // we force disabled here if --nocustomization argument is used
  if ( !myCustomization )
  {
    QgsCustomization::instance()->setEnabled( false );
  }

  QgsApplication myApp( argc, argv, myUseGuiFlag, configpath );

// (if Windows/Mac, use icon from resource)
#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC)
  myApp.setWindowIcon( QIcon( QgsApplication::iconsPath() + "qgis-icon-60x60.png" ) );
#endif

  //
  // Set up the QSettings environment must be done after qapp is created
  QCoreApplication::setOrganizationName( "QGIS" );
  QCoreApplication::setOrganizationDomain( "qgis.org" );
  QCoreApplication::setApplicationName( "QGIS2" );
  QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );

  QSettings* customizationsettings;
  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QString path = optionpath.isEmpty() ? configpath : optionpath;
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, path );
    customizationsettings = new QSettings( QSettings::IniFormat, QSettings::UserScope, "QGIS", "QGISCUSTOMIZATION2" );
  }
  else
  {
    customizationsettings = new QSettings( "QGIS", "QGISCUSTOMIZATION2" );
  }

  // Using the customizationfile option always overrides the option and config path options.
  if ( !customizationfile.isEmpty() )
  {
    customizationsettings = new QSettings( customizationfile, QSettings::IniFormat );
    QgsCustomization::instance()->setEnabled( true );
  }

  // Load and set possible default customization, must be done afterQgsApplication init and QSettings ( QCoreApplication ) init
  QgsCustomization::instance()->setSettings( customizationsettings );
  QgsCustomization::instance()->loadDefault();

#ifdef Q_OS_MACX
  // If the GDAL plugins are bundled with the application and GDAL_DRIVER_PATH
  // is not already defined, use the GDAL plugins in the application bundle.
  QString gdalPlugins( QCoreApplication::applicationDirPath().append( "/lib/gdalplugins" ) );
  if ( QFile::exists( gdalPlugins ) && !getenv( "GDAL_DRIVER_PATH" ) )
  {
    setenv( "GDAL_DRIVER_PATH", gdalPlugins.toUtf8(), 1 );
  }
#endif

  QSettings mySettings;

  // update any saved setting for older themes to new default 'gis' theme (2013-04-15)
  if ( mySettings.contains( "/Themes" ) )
  {
    QString theme = mySettings.value( "/Themes", "default" ).toString();
    if ( theme == QString( "gis" )
         || theme == QString( "classic" )
         || theme == QString( "nkids" ) )
    {
      mySettings.setValue( "/Themes", QString( "default" ) );
    }
  }


  // custom environment variables
  QMap<QString, QString> systemEnvVars = QgsApplication::systemEnvVars();
  bool useCustomVars = mySettings.value( "qgis/customEnvVarsUse", QVariant( false ) ).toBool();
  if ( useCustomVars )
  {
    QStringList customVarsList = mySettings.value( "qgis/customEnvVars", "" ).toStringList();
    if ( !customVarsList.isEmpty() )
    {
      foreach ( const QString &varStr, customVarsList )
      {
        int pos = varStr.indexOf( QLatin1Char( '|' ) );
        if ( pos == -1 )
          continue;
        QString envVarApply = varStr.left( pos );
        QString varStrNameValue = varStr.mid( pos + 1 );
        pos = varStrNameValue.indexOf( QLatin1Char( '=' ) );
        if ( pos == -1 )
          continue;
        QString envVarName = varStrNameValue.left( pos );
        QString envVarValue = varStrNameValue.mid( pos + 1 );

        if ( systemEnvVars.contains( envVarName ) )
        {
          if ( envVarApply == "prepend" )
          {
            envVarValue += systemEnvVars.value( envVarName );
          }
          else if ( envVarApply == "append" )
          {
            envVarValue = systemEnvVars.value( envVarName ) + envVarValue;
          }
        }

        if ( systemEnvVars.contains( envVarName ) && envVarApply == "unset" )
        {
#ifdef Q_WS_WIN
          putenv( envVarName.toUtf8().constData() );
#else
          unsetenv( envVarName.toUtf8().constData() );
#endif
        }
        else
        {
#ifdef Q_WS_WIN
          if ( envVarApply != "undefined" || !getenv( envVarName.toUtf8().constData() ) )
            putenv( QString( "%1=%2" ).arg( envVarName ).arg( envVarValue ).toUtf8().constData() );
#else
          setenv( envVarName.toUtf8().constData(), envVarValue.toUtf8().constData(), envVarApply == "undefined" ? 0 : 1 );
#endif
        }
      }
    }
Beispiel #2
0
int main( int argc, char *argv[] )
{
#ifdef Q_OS_MACX
  // Increase file resource limits (i.e., number of allowed open files)
  // (from code provided by Larry Biehl, Purdue University, USA, from 'MultiSpec' project)
  // This is generally 256 for the soft limit on Mac
  // NOTE: setrlimit() must come *before* initialization of stdio strings,
  //       e.g. before any debug messages, or setrlimit() gets ignored
  // see: http://stackoverflow.com/a/17726104/2865523
  struct rlimit rescLimit;
  if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
  {
    rlim_t oldSoft( rescLimit.rlim_cur );
    rlim_t oldHard( rescLimit.rlim_max );
#ifdef OPEN_MAX
    rlim_t newSoft( OPEN_MAX );
    rlim_t newHard( std::min( oldHard, newSoft ) );
#else
    rlim_t newSoft( 4096 );
    rlim_t newHard( std::min(( rlim_t )8192, oldHard ) );
#endif
    if ( rescLimit.rlim_cur < newSoft )
    {
      rescLimit.rlim_cur = newSoft;
      rescLimit.rlim_max = newHard;

      if ( setrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
      {
        QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard NEW: %1 / %2" )
                     .arg( rescLimit.rlim_cur ).arg( rescLimit.rlim_max ) );
      }
    }
    Q_UNUSED( oldSoft ); //avoid warnings
    QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard ORIG: %1 / %2" )
                 .arg( oldSoft ).arg( oldHard ) );
  }
#endif

  QgsDebugMsg( QString( "Starting qgis main" ) );
#ifdef WIN32  // Windows
#ifdef _MSC_VER
  _set_fmode( _O_BINARY );
#else //MinGW
  _fmode = _O_BINARY;
#endif  // _MSC_VER
#endif  // WIN32

  // Set up the custom qWarning/qDebug custom handler
#ifndef ANDROID
  qInstallMsgHandler( myMessageOutput );
#endif

#if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
  signal( SIGQUIT, qgisCrash );
  signal( SIGILL, qgisCrash );
  signal( SIGFPE, qgisCrash );
  signal( SIGSEGV, qgisCrash );
  signal( SIGBUS, qgisCrash );
  signal( SIGSYS, qgisCrash );
  signal( SIGTRAP, qgisCrash );
  signal( SIGXCPU, qgisCrash );
  signal( SIGXFSZ, qgisCrash );
#endif

#ifdef Q_OS_WIN
  SetUnhandledExceptionFilter( QgisApp::qgisCrashDump );
#endif

  // initialize random number seed
  qsrand( time( nullptr ) );

  /////////////////////////////////////////////////////////////////
  // Command line options 'behaviour' flag setup
  ////////////////////////////////////////////////////////////////

  //
  // Parse the command line arguments, looking to see if the user has asked for any
  // special behaviours. Any remaining non command arguments will be kept aside to
  // be passed as a list of layers and / or a project that should be loaded.
  //

  // This behaviour is used to load the app, snapshot the map,
  // save the image to disk and then exit
  QString mySnapshotFileName = "";
  int mySnapshotWidth = 800;
  int mySnapshotHeight = 600;

  bool myHideSplash = false;
#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: Splash hidden" ) );
  myHideSplash = true;
#endif

  bool myRestoreDefaultWindowState = false;
  bool myRestorePlugins = true;
  bool myCustomization = true;

  QString dxfOutputFile;
  QgsDxfExport::SymbologyExport dxfSymbologyMode = QgsDxfExport::SymbolLayerSymbology;
  double dxfScaleDenom = 50000.0;
  QString dxfEncoding = "CP1252";
  QString dxfPreset;
  QgsRectangle dxfExtent;

  // This behaviour will set initial extent of map canvas, but only if
  // there are no command line arguments. This gives a usable map
  // extent when qgis starts with no layers loaded. When layers are
  // loaded, we let the layers define the initial extent.
  QString myInitialExtent = "";
  if ( argc == 1 )
    myInitialExtent = "-1,-1,1,1";

  // This behaviour will allow you to force the use of a translation file
  // which is useful for testing
  QString myTranslationCode;

  // The user can specify a path which will override the default path of custom
  // user settings (~/.qgis) and it will be used for QSettings INI file
  QString configpath;
  QString optionpath;
  QString authdbdirectory;

  QString pythonfile;

  QString customizationfile;

#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
  //put all QGIS settings in the same place
  configpath = QgsApplication::qgisSettingsDirPath();
  QgsDebugMsg( QString( "Android: configpath set to %1" ).arg( configpath ) );
#endif

  QStringList args;

  if ( !bundleclicked( argc, argv ) )
  {
    // Build a local QCoreApplication from arguments. This way, arguments are correctly parsed from their native locale
    // It will use QString::fromLocal8Bit( argv ) under Unix and GetCommandLine() under Windows.
    QCoreApplication coreApp( argc, argv );
    args = QCoreApplication::arguments();

    for ( int i = 1; i < args.size(); ++i )
    {
      const QString &arg = args[i];

      if ( arg == "--help" || arg == "-?" )
      {
        usage( args[0].toStdString() );
        return 2;
      }
      else if ( arg == "--nologo" || arg == "-n" )
      {
        myHideSplash = true;
      }
      else if ( arg == "--noplugins" || arg == "-P" )
      {
        myRestorePlugins = false;
      }
      else if ( arg == "--nocustomization" || arg == "-C" )
      {
        myCustomization = false;
      }
      else if ( i + 1 < argc && ( arg == "--snapshot" || arg == "-s" ) )
      {
        mySnapshotFileName = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--width" || arg == "-w" ) )
      {
        mySnapshotWidth = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == "--height" || arg == "-h" ) )
      {
        mySnapshotHeight = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == "--lang" || arg == "-l" ) )
      {
        myTranslationCode = args[++i];
      }
      else if ( i + 1 < argc && ( arg == "--project" || arg == "-p" ) )
      {
        myProjectFileName = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--extent" || arg == "-e" ) )
      {
        myInitialExtent = args[++i];
      }
      else if ( i + 1 < argc && ( arg == "--optionspath" || arg == "-o" ) )
      {
        optionpath = QDir::toNativeSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == "--configpath" || arg == "-c" ) )
      {
        configpath = QDir::toNativeSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == "--authdbdirectory" || arg == "-a" ) )
      {
        authdbdirectory = QDir::toNativeSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == "--code" || arg == "-f" ) )
      {
        pythonfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == "--customizationfile" || arg == "-z" ) )
      {
        customizationfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( arg == "--defaultui" || arg == "-d" )
      {
        myRestoreDefaultWindowState = true;
      }
      else if ( arg == "--dxf-export" )
      {
        dxfOutputFile = args[++i];
      }
      else if ( arg == "--dxf-extent" )
      {
        QgsLocaleNumC l;
        QString ext( args[++i] );
        QStringList coords( ext.split( ',' ) );

        if ( coords.size() != 4 )
        {
          std::cerr << "invalid dxf extent " << ext.toStdString() << std::endl;
          return 2;
        }

        for ( int i = 0; i < 4; i++ )
        {
          bool ok;
          double d;

          d = coords[i].toDouble( &ok );
          if ( !ok )
          {
            std::cerr << "invalid dxf coordinate " << coords[i].toStdString() << " in extent " << ext.toStdString() << std::endl;
            return 2;
          }

          switch ( i )
          {
            case 0:
              dxfExtent.setXMinimum( d );
              break;
            case 1:
              dxfExtent.setYMinimum( d );
              break;
            case 2:
              dxfExtent.setXMaximum( d );
              break;
            case 3:
              dxfExtent.setYMaximum( d );
              break;
          }
        }
      }
      else if ( arg == "--dxf-symbology-mode" )
      {
        QString mode( args[++i] );
        if ( mode == "none" )
        {
          dxfSymbologyMode = QgsDxfExport::NoSymbology;
        }
        else if ( mode == "symbollayer" )
        {
          dxfSymbologyMode = QgsDxfExport::SymbolLayerSymbology;
        }
        else if ( mode == "feature" )
        {
          dxfSymbologyMode = QgsDxfExport::FeatureSymbology;
        }
        else
        {
          std::cerr << "invalid dxf symbology mode " << mode.toStdString() << std::endl;
          return 2;
        }
      }
      else if ( arg == "--dxf-scale-denom" )
      {
        bool ok;
        QString scale( args[++i] );
        dxfScaleDenom = scale.toDouble( &ok );
        if ( !ok )
        {
          std::cerr << "invalid dxf scale " << scale.toStdString() << std::endl;
          return 2;
        }
      }
      else if ( arg == "--dxf-encoding" )
      {
        dxfEncoding = args[++i];
      }
      else if ( arg == "--dxf-preset" )
      {
        dxfPreset = args[++i];
      }
      else if ( arg == "--" )
      {
        for ( i++; i < args.size(); ++i )
          myFileList.append( QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() ) );
      }
      else
      {
        myFileList.append( QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() ) );
      }
    }
  }

  /////////////////////////////////////////////////////////////////////
  // If no --project was specified, parse the args to look for a     //
  // .qgs file and set myProjectFileName to it. This allows loading  //
  // of a project file by clicking on it in various desktop managers //
  // where an appropriate mime-type has been set up.                 //
  /////////////////////////////////////////////////////////////////////
  if ( myProjectFileName.isEmpty() )
  {
    // check for a .qgs
    for ( int i = 0; i < args.size(); i++ )
    {
      QString arg = QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() );
      if ( arg.contains( ".qgs" ) )
      {
        myProjectFileName = arg;
        break;
      }
    }
  }


  /////////////////////////////////////////////////////////////////////
  // Now we have the handlers for the different behaviours...
  ////////////////////////////////////////////////////////////////////

  /////////////////////////////////////////////////////////////////////
  // Initialise the application and the translation stuff
  /////////////////////////////////////////////////////////////////////

#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(ANDROID)
  bool myUseGuiFlag = nullptr != getenv( "DISPLAY" );
#else
  bool myUseGuiFlag = true;
#endif
  if ( !myUseGuiFlag )
  {
    std::cerr << QObject::tr(
                "QGIS starting in non-interactive mode not supported.\n"
                "You are seeing this message most likely because you "
                "have no DISPLAY environment variable set.\n"
              ).toUtf8().constData();
    exit( 1 ); //exit for now until a version of qgis is capabable of running non interactive
  }

  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, optionpath.isEmpty() ? configpath : optionpath );
  }

  // GUI customization is enabled according to settings (loaded when instance is created)
  // we force disabled here if --nocustomization argument is used
  if ( !myCustomization )
  {
    QgsCustomization::instance()->setEnabled( false );
  }

  QgsApplication myApp( argc, argv, myUseGuiFlag, configpath );

  myApp.setWindowIcon( QIcon( QgsApplication::appIconPath() ) );

  //
  // Set up the QSettings environment must be done after qapp is created
  QCoreApplication::setOrganizationName( QgsApplication::QGIS_ORGANIZATION_NAME );
  QCoreApplication::setOrganizationDomain( QgsApplication::QGIS_ORGANIZATION_DOMAIN );
  QCoreApplication::setApplicationName( QgsApplication::QGIS_APPLICATION_NAME );
  QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );

  QSettings* customizationsettings;
  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QString path = optionpath.isEmpty() ? configpath : optionpath;
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, path );
    customizationsettings = new QSettings( QSettings::IniFormat, QSettings::UserScope, "QGIS", "QGISCUSTOMIZATION2" );
  }
  else
  {
    customizationsettings = new QSettings( "QGIS", "QGISCUSTOMIZATION2" );
  }

  // Using the customizationfile option always overrides the option and config path options.
  if ( !customizationfile.isEmpty() )
  {
    customizationsettings = new QSettings( customizationfile, QSettings::IniFormat );
    QgsCustomization::instance()->setEnabled( true );
  }

  // Load and set possible default customization, must be done afterQgsApplication init and QSettings ( QCoreApplication ) init
  QgsCustomization::instance()->setSettings( customizationsettings );
  QgsCustomization::instance()->loadDefault();

#ifdef Q_OS_MACX
  // If the GDAL plugins are bundled with the application and GDAL_DRIVER_PATH
  // is not already defined, use the GDAL plugins in the application bundle.
  QString gdalPlugins( QCoreApplication::applicationDirPath().append( "/lib/gdalplugins" ) );
  if ( QFile::exists( gdalPlugins ) && !getenv( "GDAL_DRIVER_PATH" ) )
  {
    setenv( "GDAL_DRIVER_PATH", gdalPlugins.toUtf8(), 1 );
  }

  // Point GDAL_DATA at any GDAL share directory embedded in the app bundle
  if ( !getenv( "GDAL_DATA" ) )
  {
    QStringList gdalShares;
    QString appResources( QDir::cleanPath( QgsApplication::pkgDataPath() ) );
    gdalShares << QCoreApplication::applicationDirPath().append( "/share/gdal" )
    << appResources.append( "/share/gdal" )
    << appResources.append( "/gdal" );
    Q_FOREACH ( const QString& gdalShare, gdalShares )
    {
      if ( QFile::exists( gdalShare ) )
      {
        setenv( "GDAL_DATA", gdalShare.toUtf8().constData(), 1 );
        break;
      }
    }
  }
Beispiel #3
0
// On Android, there there is a libqgis.so instead of a qgis executable.
// The main method symbol of this library needs to be exported so it can be called by java
// On Windows this main is included in qgis_app and called from mainwin.cpp
APP_EXPORT
#endif
int main( int argc, char *argv[] )
{
#ifdef Q_OS_MACX
  // Increase file resource limits (i.e., number of allowed open files)
  // (from code provided by Larry Biehl, Purdue University, USA, from 'MultiSpec' project)
  // This is generally 256 for the soft limit on Mac
  // NOTE: setrlimit() must come *before* initialization of stdio strings,
  //       e.g. before any debug messages, or setrlimit() gets ignored
  // see: http://stackoverflow.com/a/17726104/2865523
  struct rlimit rescLimit;
  if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
  {
    rlim_t oldSoft( rescLimit.rlim_cur );
    rlim_t oldHard( rescLimit.rlim_max );
#ifdef OPEN_MAX
    rlim_t newSoft( OPEN_MAX );
    rlim_t newHard( std::min( oldHard, newSoft ) );
#else
    rlim_t newSoft( 4096 );
    rlim_t newHard( std::min( ( rlim_t )8192, oldHard ) );
#endif
    if ( rescLimit.rlim_cur < newSoft )
    {
      rescLimit.rlim_cur = newSoft;
      rescLimit.rlim_max = newHard;

      if ( setrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
      {
        QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard NEW: %1 / %2" )
                     .arg( rescLimit.rlim_cur ).arg( rescLimit.rlim_max ) );
      }
    }
    Q_UNUSED( oldSoft ); //avoid warnings
    QgsDebugMsg( QString( "Mac RLIMIT_NOFILE Soft/Hard ORIG: %1 / %2" )
                 .arg( oldSoft ).arg( oldHard ) );
  }
#endif

  QgsDebugMsg( QString( "Starting qgis main" ) );
#ifdef WIN32  // Windows
#ifdef _MSC_VER
  _set_fmode( _O_BINARY );
#else //MinGW
  _fmode = _O_BINARY;
#endif  // _MSC_VER
#endif  // WIN32

  // Set up the custom qWarning/qDebug custom handler
#ifndef ANDROID
  qInstallMsgHandler( myMessageOutput );
#endif

#if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
  signal( SIGQUIT, qgisCrash );
  signal( SIGILL, qgisCrash );
  signal( SIGFPE, qgisCrash );
  signal( SIGSEGV, qgisCrash );
  signal( SIGBUS, qgisCrash );
  signal( SIGSYS, qgisCrash );
  signal( SIGTRAP, qgisCrash );
  signal( SIGXCPU, qgisCrash );
  signal( SIGXFSZ, qgisCrash );
#endif

#ifdef Q_OS_WIN
  SetUnhandledExceptionFilter( QgsCrashHandler::handle );
#endif

  // initialize random number seed
  qsrand( time( nullptr ) );

  /////////////////////////////////////////////////////////////////
  // Command line options 'behavior' flag setup
  ////////////////////////////////////////////////////////////////

  //
  // Parse the command line arguments, looking to see if the user has asked for any
  // special behaviors. Any remaining non command arguments will be kept aside to
  // be passed as a list of layers and / or a project that should be loaded.
  //

  // This behavior is used to load the app, snapshot the map,
  // save the image to disk and then exit
  QString mySnapshotFileName;
  QString configLocalStorageLocation;
  QString profileName;
  int mySnapshotWidth = 800;
  int mySnapshotHeight = 600;

  bool myHideSplash = false;
  bool mySettingsMigrationForce = false;
  bool mySkipVersionCheck = false;
#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: Splash hidden" ) );
  myHideSplash = true;
#endif

  bool myRestoreDefaultWindowState = false;
  bool myRestorePlugins = true;
  bool myCustomization = true;

  QString dxfOutputFile;
  QgsDxfExport::SymbologyExport dxfSymbologyMode = QgsDxfExport::SymbolLayerSymbology;
  double dxfScale = 50000.0;
  QString dxfEncoding = QStringLiteral( "CP1252" );
  QString dxfPreset;
  QgsRectangle dxfExtent;

  // This behavior will set initial extent of map canvas, but only if
  // there are no command line arguments. This gives a usable map
  // extent when qgis starts with no layers loaded. When layers are
  // loaded, we let the layers define the initial extent.
  QString myInitialExtent;
  if ( argc == 1 )
    myInitialExtent = QStringLiteral( "-1,-1,1,1" );

  // This behavior will allow you to force the use of a translation file
  // which is useful for testing
  QString myTranslationCode;

  // The user can specify a path which will override the default path of custom
  // user settings (~/.qgis) and it will be used for QgsSettings INI file
  QString configpath;
  QString authdbdirectory;

  QString pythonfile;

  QString customizationfile;
  QString globalsettingsfile;

// TODO Fix android
#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
  //put all QGIS settings in the same place
  configpath = QgsApplication::qgisSettingsDirPath();
  QgsDebugMsg( QString( "Android: configpath set to %1" ).arg( configpath ) );
#endif

  QStringList args;

  if ( !bundleclicked( argc, argv ) )
  {
    // Build a local QCoreApplication from arguments. This way, arguments are correctly parsed from their native locale
    // It will use QString::fromLocal8Bit( argv ) under Unix and GetCommandLine() under Windows.
    QCoreApplication coreApp( argc, argv );
    args = QCoreApplication::arguments();

    for ( int i = 1; i < args.size(); ++i )
    {
      const QString &arg = args[i];

      if ( arg == QLatin1String( "--help" ) || arg == QLatin1String( "-?" ) )
      {
        usage( args[0] );
        return 2;
      }
      else if ( arg == QLatin1String( "--nologo" ) || arg == QLatin1String( "-n" ) )
      {
        myHideSplash = true;
      }
      else if ( arg == QLatin1String( "--version-migration" ) )
      {
        mySettingsMigrationForce = true;
      }
      else if ( arg == QLatin1String( "--noversioncheck" ) || arg == QLatin1String( "-V" ) )
      {
        mySkipVersionCheck = true;
      }
      else if ( arg == QLatin1String( "--noplugins" ) || arg == QLatin1String( "-P" ) )
      {
        myRestorePlugins = false;
      }
      else if ( arg == QLatin1String( "--nocustomization" ) || arg == QLatin1String( "-C" ) )
      {
        myCustomization = false;
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--profile" ) ) )
      {
        profileName = args[++i];
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--profiles-path" ) || arg == QLatin1String( "-s" ) ) )
      {
        configLocalStorageLocation = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--snapshot" ) || arg == QLatin1String( "-s" ) ) )
      {
        mySnapshotFileName = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--width" ) || arg == QLatin1String( "-w" ) ) )
      {
        mySnapshotWidth = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--height" ) || arg == QLatin1String( "-h" ) ) )
      {
        mySnapshotHeight = QString( args[++i] ).toInt();
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--lang" ) || arg == QLatin1String( "-l" ) ) )
      {
        myTranslationCode = args[++i];
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--project" ) || arg == QLatin1String( "-p" ) ) )
      {
        sProjectFileName = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--extent" ) || arg == QLatin1String( "-e" ) ) )
      {
        myInitialExtent = args[++i];
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--authdbdirectory" ) || arg == QLatin1String( "-a" ) ) )
      {
        authdbdirectory = QDir::toNativeSeparators( QDir( args[++i] ).absolutePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--code" ) || arg == QLatin1String( "-f" ) ) )
      {
        pythonfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--customizationfile" ) || arg == QLatin1String( "-z" ) ) )
      {
        customizationfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( i + 1 < argc && ( arg == QLatin1String( "--globalsettingsfile" ) || arg == QLatin1String( "-g" ) ) )
      {
        globalsettingsfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
      }
      else if ( arg == QLatin1String( "--defaultui" ) || arg == QLatin1String( "-d" ) )
      {
        myRestoreDefaultWindowState = true;
      }
      else if ( arg == QLatin1String( "--dxf-export" ) )
      {
        dxfOutputFile = args[++i];
      }
      else if ( arg == QLatin1String( "--dxf-extent" ) )
      {
        QgsLocaleNumC l;
        QString ext( args[++i] );
        QStringList coords( ext.split( ',' ) );

        if ( coords.size() != 4 )
        {
          std::cerr << "invalid dxf extent " << ext.toStdString() << std::endl;
          return 2;
        }

        for ( int i = 0; i < 4; i++ )
        {
          bool ok;
          double d;

          d = coords[i].toDouble( &ok );
          if ( !ok )
          {
            std::cerr << "invalid dxf coordinate " << coords[i].toStdString() << " in extent " << ext.toStdString() << std::endl;
            return 2;
          }

          switch ( i )
          {
            case 0:
              dxfExtent.setXMinimum( d );
              break;
            case 1:
              dxfExtent.setYMinimum( d );
              break;
            case 2:
              dxfExtent.setXMaximum( d );
              break;
            case 3:
              dxfExtent.setYMaximum( d );
              break;
          }
        }
      }
      else if ( arg == QLatin1String( "--dxf-symbology-mode" ) )
      {
        QString mode( args[++i] );
        if ( mode == QLatin1String( "none" ) )
        {
          dxfSymbologyMode = QgsDxfExport::NoSymbology;
        }
        else if ( mode == QLatin1String( "symbollayer" ) )
        {
          dxfSymbologyMode = QgsDxfExport::SymbolLayerSymbology;
        }
        else if ( mode == QLatin1String( "feature" ) )
        {
          dxfSymbologyMode = QgsDxfExport::FeatureSymbology;
        }
        else
        {
          std::cerr << "invalid dxf symbology mode " << mode.toStdString() << std::endl;
          return 2;
        }
      }
      else if ( arg == QLatin1String( "--dxf-scale-denom" ) )
      {
        bool ok;
        QString scale( args[++i] );
        dxfScale = scale.toDouble( &ok );
        if ( !ok )
        {
          std::cerr << "invalid dxf scale " << scale.toStdString() << std::endl;
          return 2;
        }
      }
      else if ( arg == QLatin1String( "--dxf-encoding" ) )
      {
        dxfEncoding = args[++i];
      }
      else if ( arg == QLatin1String( "--dxf-preset" ) )
      {
        dxfPreset = args[++i];
      }
      else if ( arg == QLatin1String( "--" ) )
      {
        for ( i++; i < args.size(); ++i )
          sFileList.append( QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() ) );
      }
      else
      {
        sFileList.append( QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() ) );
      }
    }
  }

  /////////////////////////////////////////////////////////////////////
  // If no --project was specified, parse the args to look for a     //
  // .qgs file and set myProjectFileName to it. This allows loading  //
  // of a project file by clicking on it in various desktop managers //
  // where an appropriate mime-type has been set up.                 //
  /////////////////////////////////////////////////////////////////////
  if ( sProjectFileName.isEmpty() )
  {
    // check for a .qgs
    for ( int i = 0; i < args.size(); i++ )
    {
      QString arg = QDir::toNativeSeparators( QFileInfo( args[i] ).absoluteFilePath() );
      if ( arg.endsWith( QLatin1String( ".qgs" ), Qt::CaseInsensitive ) )
      {
        sProjectFileName = arg;
        break;
      }
    }
  }


  /////////////////////////////////////////////////////////////////////
  // Now we have the handlers for the different behaviors...
  ////////////////////////////////////////////////////////////////////

  /////////////////////////////////////////////////////////////////////
  // Initialize the application and the translation stuff
  /////////////////////////////////////////////////////////////////////

#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(ANDROID)
  bool myUseGuiFlag = nullptr != getenv( "DISPLAY" );
#else
  bool myUseGuiFlag = true;
#endif
  if ( !myUseGuiFlag )
  {
    std::cerr << QObject::tr(
                "QGIS starting in non-interactive mode not supported.\n"
                "You are seeing this message most likely because you "
                "have no DISPLAY environment variable set.\n"
              ).toUtf8().constData();
    exit( 1 ); //exit for now until a version of qgis is capabable of running non interactive
  }

  // GUI customization is enabled according to settings (loaded when instance is created)
  // we force disabled here if --nocustomization argument is used
  if ( !myCustomization )
  {
    QgsCustomization::instance()->setEnabled( false );
  }

  QCoreApplication::setOrganizationName( QgsApplication::QGIS_ORGANIZATION_NAME );
  QCoreApplication::setOrganizationDomain( QgsApplication::QGIS_ORGANIZATION_DOMAIN );
  QCoreApplication::setApplicationName( QgsApplication::QGIS_APPLICATION_NAME );
  QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );

  QgsSettings settings;
  if ( configLocalStorageLocation.isEmpty() )
  {
    if ( getenv( "QGIS_CUSTOM_CONFIG_PATH" ) )
    {
      configLocalStorageLocation = getenv( "QGIS_CUSTOM_CONFIG_PATH" );
    }
    else if ( settings.contains( QStringLiteral( "profilesPath" ), QgsSettings::Core ) )
    {
      configLocalStorageLocation = settings.value( QStringLiteral( "profilesPath" ), "", QgsSettings::Core ).toString();
      QgsDebugMsg( QString( "Loading profiles path from global config at %1" ).arg( configLocalStorageLocation ) );
    }

    // If it is still empty at this point we get it from the standard location.
    if ( configLocalStorageLocation.isEmpty() )
    {
      configLocalStorageLocation = QStandardPaths::standardLocations( QStandardPaths::AppDataLocation ).value( 0 );
    }
  }

  QString rootProfileFolder = QgsUserProfileManager::resolveProfilesFolder( configLocalStorageLocation );
  QgsUserProfileManager manager( rootProfileFolder );
  QgsUserProfile *profile = manager.getProfile( profileName, true );
  QString profileFolder = profile->folder();
  profileName = profile->name();
  delete profile;

  QgsDebugMsg( "User profile details:" );
  QgsDebugMsg( QString( "\t - %1" ).arg( profileName ) );
  QgsDebugMsg( QString( "\t - %1" ).arg( profileFolder ) );
  QgsDebugMsg( QString( "\t - %1" ).arg( rootProfileFolder ) );

  QgsApplication myApp( argc, argv, myUseGuiFlag, profileFolder );

  // SetUp the QgsSettings Global Settings:
  // - use the path specified with --globalsettingsfile path,
  // - use the environment if not found
  // - use a default location as a fallback
  if ( globalsettingsfile.isEmpty() )
  {
    globalsettingsfile = getenv( "QGIS_GLOBAL_SETTINGS_FILE" );
  }
  if ( globalsettingsfile.isEmpty() )
  {
    QString default_globalsettingsfile = QgsApplication::pkgDataPath() + "/qgis_global_settings.ini";
    if ( QFile::exists( default_globalsettingsfile ) )
    {
      globalsettingsfile = default_globalsettingsfile;
    }
  }
  if ( !globalsettingsfile.isEmpty() )
  {
    if ( ! QgsSettings::setGlobalSettingsPath( globalsettingsfile ) )
    {
      QgsMessageLog::logMessage( QStringLiteral( "Invalid globalsettingsfile path: %1" ).arg( globalsettingsfile ), QStringLiteral( "QGIS" ) );
    }
    else
    {
      QgsMessageLog::logMessage( QStringLiteral( "Successfully loaded globalsettingsfile path: %1" ).arg( globalsettingsfile ), QStringLiteral( "QGIS" ) );
    }
  }

  // Settings migration is only supported on the default profile for now.
  if ( profileName == "default" )
  {
    std::unique_ptr< QgsVersionMigration > migration( QgsVersionMigration::canMigrate( 20000, Qgis::QGIS_VERSION_INT ) );
    if ( migration && ( mySettingsMigrationForce || migration->requiresMigration() ) )
    {
      QgsDebugMsg( "RUNNING MIGRATION" );
      migration->runMigration();
    }
  }

  // Redefine QgsApplication::libraryPaths as necessary.
  // IMPORTANT: Do *after* QgsApplication myApp(...), but *before* Qt uses any plugins,
  //            e.g. loading splash screen, setting window icon, etc.
  //            Always honor QT_PLUGIN_PATH env var or qt.conf, which will
  //            be part of libraryPaths just after QgsApplication creation.
#ifdef Q_OS_WIN
  // For non static builds on win (static builds are not supported)
  // we need to be sure we can find the qt image plugins.
  QCoreApplication::addLibraryPath( QApplication::applicationDirPath()
                                    + QDir::separator() + "qtplugins" );
#endif
#ifdef Q_OS_MAC
  // Resulting libraryPaths has critical QGIS plugin paths first, then any Qt plugin paths, then
  // any dev-defined paths (in app's qt.conf) and/or user-defined paths (QT_PLUGIN_PATH env var).
  //
  // NOTE: Minimizes, though does not fully protect against, crashes due to dev/user-defined libs
  //       built against a different Qt/QGIS, while still allowing custom C++ plugins to load.
  QStringList libPaths( QCoreApplication::libraryPaths() );

  QgsDebugMsgLevel( QStringLiteral( "Initial macOS QCoreApplication::libraryPaths: %1" )
                    .arg( libPaths.join( " " ) ), 4 );

  // Strip all critical paths that should always be prepended
  if ( libPaths.removeAll( QDir::cleanPath( QgsApplication::pluginPath() ) ) )
  {
    QgsDebugMsgLevel( QStringLiteral( "QgsApplication::pluginPath removed from initial libraryPaths" ), 4 );
  }
  if ( libPaths.removeAll( QCoreApplication::applicationDirPath() ) )
  {
    QgsDebugMsgLevel( QStringLiteral( "QCoreApplication::applicationDirPath removed from initial libraryPaths" ), 4 );
  }
  // Prepend path, so a standard Qt bundle directory is parsed
  QgsDebugMsgLevel( QStringLiteral( "Prepending QCoreApplication::applicationDirPath to libraryPaths" ), 4 );
  libPaths.prepend( QCoreApplication::applicationDirPath() );

  // Check if we are running in a 'release' app bundle, i.e. contains copied-in
  // standard Qt-specific plugin subdirectories (ones never created by QGIS, e.g. 'sqldrivers' is).
  // Note: bundleclicked(...) is inadequate to determine which *type* of bundle was opened, e.g. release or build dir.
  // An app bundled with QGIS_MACAPP_BUNDLE > 0 is considered a release bundle.
  QString  relLibPath( QDir::cleanPath( QCoreApplication::applicationDirPath().append( "/../PlugIns" ) ) );
  // Note: relLibPath becomes the defacto QT_PLUGINS_DIR of a release app bundle
  if ( QFile::exists( relLibPath + QStringLiteral( "/imageformats" ) )
       && QFile::exists( relLibPath + QStringLiteral( "/codecs" ) ) )
  {
    // We are in a release app bundle.
    // Strip QT_PLUGINS_DIR because it will crash a launched release app bundle, since
    // the appropriate Qt frameworks and plugins have been copied into the bundle.
    if ( libPaths.removeAll( QT_PLUGINS_DIR ) )
    {
      QgsDebugMsgLevel( QStringLiteral( "QT_PLUGINS_DIR removed from initial libraryPaths" ), 4 );
    }
    // Prepend the Plugins path, so copied-in Qt plugin bundle directories are parsed.
    QgsDebugMsgLevel( QStringLiteral( "Prepending <bundle>/Plugins to libraryPaths" ), 4 );
    libPaths.prepend( relLibPath );

    // TODO: see if this or another method can be used to avoid QCA's install prefix plugins
    //       from being parsed and loaded (causes multi-Qt-loaded errors when bundled Qt should
    //       be the only one loaded). QCA core (> v2.1.3) needs an update first.
    //setenv( "QCA_PLUGIN_PATH", relLibPath.toUtf8().constData(), 1 );
  }
  else
  {
    // We are either running from build dir bundle, or launching Mach-O binary directly.
    // Add system Qt plugins, since they are not bundled, and not always referenced by default.
    // An app bundled with QGIS_MACAPP_BUNDLE = 0 will still have Plugins/qgis in it.
    // Note: Don't always prepend.
    //       User may have already defined it in QT_PLUGIN_PATH in a specific order.
    if ( !libPaths.contains( QT_PLUGINS_DIR ) )
    {
      QgsDebugMsgLevel( QStringLiteral( "Prepending QT_PLUGINS_DIR to libraryPaths" ), 4 );
      libPaths.prepend( QT_PLUGINS_DIR );
    }
  }

  QgsDebugMsgLevel( QStringLiteral( "Prepending QgsApplication::pluginPath to libraryPaths" ), 4 );
  libPaths.prepend( QDir::cleanPath( QgsApplication::pluginPath() ) );

  // Redefine library search paths.
  QCoreApplication::setLibraryPaths( libPaths );

  QgsDebugMsgLevel( QStringLiteral( "Rewritten macOS QCoreApplication::libraryPaths: %1" )
                    .arg( QCoreApplication::libraryPaths().join( " " ) ), 4 );
#endif

#ifdef Q_OS_MAC
  // Set hidpi icons; use SVG icons, as PNGs will be relatively too small
  QCoreApplication::setAttribute( Qt::AA_UseHighDpiPixmaps );

  // Set 1024x1024 icon for dock, app switcher, etc., rendering
  myApp.setWindowIcon( QIcon( QgsApplication::iconsPath() + QStringLiteral( "qgis-icon-macos.png" ) ) );
#else
  myApp.setWindowIcon( QIcon( QgsApplication::appIconPath() ) );
#endif

  // TODO: use QgsSettings
  QSettings *customizationsettings = nullptr;

  // Using the customizationfile option always overrides the option and config path options.
  if ( !customizationfile.isEmpty() )
  {
    customizationsettings = new QSettings( customizationfile, QSettings::IniFormat );
    QgsCustomization::instance()->setEnabled( true );
  }
  else
  {
    customizationsettings = new QSettings( QStringLiteral( "QGIS" ), QStringLiteral( "QGISCUSTOMIZATION2" ) );
  }

  // Load and set possible default customization, must be done after QgsApplication init and QgsSettings ( QCoreApplication ) init
  QgsCustomization::instance()->setSettings( customizationsettings );
  QgsCustomization::instance()->loadDefault();

#ifdef Q_OS_MACX
  // If the GDAL plugins are bundled with the application and GDAL_DRIVER_PATH
  // is not already defined, use the GDAL plugins in the application bundle.
  QString gdalPlugins( QCoreApplication::applicationDirPath().append( "/lib/gdalplugins" ) );
  if ( QFile::exists( gdalPlugins ) && !getenv( "GDAL_DRIVER_PATH" ) )
  {
    setenv( "GDAL_DRIVER_PATH", gdalPlugins.toUtf8(), 1 );
  }

  // Point GDAL_DATA at any GDAL share directory embedded in the app bundle
  if ( !getenv( "GDAL_DATA" ) )
  {
    QStringList gdalShares;
    QString appResources( QDir::cleanPath( QgsApplication::pkgDataPath() ) );
    gdalShares << QCoreApplication::applicationDirPath().append( "/share/gdal" )
               << appResources.append( "/share/gdal" )
               << appResources.append( "/gdal" );
    Q_FOREACH ( const QString &gdalShare, gdalShares )
    {
      if ( QFile::exists( gdalShare ) )
      {
        setenv( "GDAL_DATA", gdalShare.toUtf8().constData(), 1 );
        break;
      }
    }
  }
Beispiel #4
0
int main( int argc, char *argv[] )
{
  QgsDebugMsg( QString( "Starting qgis main" ) );
#ifdef WIN32  // Windows
#ifdef _MSC_VER
  _set_fmode( _O_BINARY );
#else //MinGW
  _fmode = _O_BINARY;
#endif  // _MSC_VER
#endif  // WIN32

#if defined(linux) && !defined(ANDROID)
  // Set up the custom qWarning/qDebug custom handler
  qInstallMsgHandler( myMessageOutput );

  signal( SIGQUIT, qgisCrash );
  signal( SIGILL, qgisCrash );
  signal( SIGFPE, qgisCrash );
  signal( SIGSEGV, qgisCrash );
  signal( SIGBUS, qgisCrash );
  signal( SIGSYS, qgisCrash );
  signal( SIGTRAP, qgisCrash );
  signal( SIGXCPU, qgisCrash );
  signal( SIGXFSZ, qgisCrash );
#endif

#ifdef Q_OS_WIN
  SetUnhandledExceptionFilter( qgisCrashDump );
#endif

  // initialize random number seed
  srand( time( NULL ) );

  /////////////////////////////////////////////////////////////////
  // Command line options 'behaviour' flag setup
  ////////////////////////////////////////////////////////////////

  //
  // Parse the command line arguments, looking to see if the user has asked for any
  // special behaviours. Any remaining non command arguments will be kept aside to
  // be passed as a list of layers and / or a project that should be loaded.
  //

  // This behaviour is used to load the app, snapshot the map,
  // save the image to disk and then exit
  QString mySnapshotFileName = "";
  int mySnapshotWidth = 800;
  int mySnapshotHeight = 600;

  bool myHideSplash = false;
#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: Splash hidden" ) );
  myHideSplash = true;
#endif

  bool myRestorePlugins = true;
  bool myCustomization = true;

  // This behaviour will set initial extent of map canvas, but only if
  // there are no command line arguments. This gives a usable map
  // extent when qgis starts with no layers loaded. When layers are
  // loaded, we let the layers define the initial extent.
  QString myInitialExtent = "";
  if ( argc == 1 )
    myInitialExtent = "-1,-1,1,1";

  // This behaviour will allow you to force the use of a translation file
  // which is useful for testing
  QString myTranslationCode;

  // The user can specify a path which will override the default path of custom
  // user settings (~/.qgis) and it will be used for QSettings INI file
  QString configpath;
  QString optionpath;

  QString pythonfile;

  QString customizationfile;

#if defined(ANDROID)
  QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
  //put all QGIS settings in the same place
  configpath = QgsApplication::qgisSettingsPath();
  QgsDebugMsg( QString( "Android: configpath set to %1" ).arg( configpath ) );
#elif defined(Q_WS_WIN)
  for ( int i = 1; i < argc; i++ )
  {
    QString arg = argv[i];

    if ( arg == "--help" || arg == "-?" )
    {
      usage( argv[0] );
      return 2;
    }
    else if ( arg == "-nologo" || arg == "-n" )
    {
      myHideSplash = true;
    }
    else if ( arg == "--noplugins" || arg == "-P" )
    {
      myRestorePlugins = false;
    }
    else if ( arg == "--nocustomization" || arg == "-C" )
    {
      myCustomization = false;
    }
    else if ( i + 1 < argc && ( arg == "--snapshot" || arg == "-s" ) )
    {
      mySnapshotFileName = QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[++i] ) ).absoluteFilePath() );
    }
    else if ( i + 1 < argc && ( arg == "--width" || arg == "-w" ) )
    {
      mySnapshotWidth = QString( argv[++i] ).toInt();
    }
    else if ( i + 1 < argc && ( arg == "--height" || arg == "-h" ) )
    {
      mySnapshotHeight = QString( argv[++i] ).toInt();
    }
    else if ( i + 1 < argc && ( arg == "--lang" || arg == "-l" ) )
    {
      myTranslationCode = argv[++i];
    }
    else if ( i + 1 < argc && ( arg == "--project" || arg == "-p" ) )
    {
      myProjectFileName = QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[++i] ) ).absoluteFilePath() );
    }
    else if ( i + 1 < argc && ( arg == "--extent" || arg == "-e" ) )
    {
      myInitialExtent = argv[++i];
    }
    else if ( i + 1 < argc && ( arg == "--optionspath" || arg == "-o" ) )
    {
      optionpath = argv[++i];
    }
    else if ( i + 1 < argc && ( arg == "--configpath" || arg == "-c" ) )
    {
      configpath = argv[++i];
    }
    else if ( i + 1 < argc && ( arg == "--code" || arg == "-f" ) )
    {
      pythonfile = argv[++i];
    }
    else if ( i + 1 < argc && ( arg == "--customizationfile" || arg == "-z" ) )
    {
      customizationfile = argv[++i];
    }
    else
    {
      myFileList.append( QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[i] ) ).absoluteFilePath() ) );
    }
  }
#else
  if ( !bundleclicked( argc, argv ) )
  {

    ////////////////////////////////////////////////////////////////
    // Use the GNU Getopts utility to parse cli arguments
    // Invokes ctor `GetOpt (int argc, char **argv,  char *optstring);'
    ///////////////////////////////////////////////////////////////
    int optionChar;
    while ( 1 )
    {
      static struct option long_options[] =
      {
        /* These options set a flag. */
        {"help", no_argument, 0, '?'},
        {"nologo", no_argument, 0, 'n'},
        {"noplugins", no_argument, 0, 'P'},
        {"nocustomization", no_argument, 0, 'C'},
        /* These options don't set a flag.
         *  We distinguish them by their indices. */
        {"snapshot", required_argument, 0, 's'},
        {"width",    required_argument, 0, 'w'},
        {"height",   required_argument, 0, 'h'},
        {"lang",     required_argument, 0, 'l'},
        {"project",  required_argument, 0, 'p'},
        {"extent",   required_argument, 0, 'e'},
        {"optionspath", required_argument, 0, 'o'},
        {"configpath", required_argument, 0, 'c'},
        {"customizationfile", required_argument, 0, 'z'},
        {"code", required_argument, 0, 'f'},
        {"android", required_argument, 0, 'a'},
        {0, 0, 0, 0}
      };

      /* getopt_long stores the option index here. */
      int option_index = 0;

      optionChar = getopt_long( argc, argv, "swhlpeoc",
                                long_options, &option_index );
      QgsDebugMsg( QString( "Qgis main Debug" ) + optionChar );
      /* Detect the end of the options. */
      if ( optionChar == -1 )
        break;

      switch ( optionChar )
      {
        case 0:
          /* If this option set a flag, do nothing else now. */
          if ( long_options[option_index].flag != 0 )
            break;
          printf( "option %s", long_options[option_index].name );
          if ( optarg )
            printf( " with arg %s", optarg );
          printf( "\n" );
          break;

        case 's':
          mySnapshotFileName = QDir::convertSeparators( QFileInfo( QFile::decodeName( optarg ) ).absoluteFilePath() );
          break;

        case 'w':
          mySnapshotWidth = QString( optarg ).toInt();
          break;

        case 'h':
          mySnapshotHeight = QString( optarg ).toInt();
          break;

        case 'n':
          myHideSplash = true;
          break;

        case 'l':
          myTranslationCode = optarg;
          break;

        case 'p':
          myProjectFileName = QDir::convertSeparators( QFileInfo( QFile::decodeName( optarg ) ).absoluteFilePath() );
          break;

        case 'P':
          myRestorePlugins = false;
          break;

        case 'C':
          myCustomization = false;
          break;

        case 'e':
          myInitialExtent = optarg;
          break;

        case 'o':
          optionpath = optarg;
          break;

        case 'c':
          configpath = optarg;
          break;

        case 'f':
          pythonfile = optarg;
          break;

        case 'z':
          customizationfile = optarg;
          break;

        case '?':
          usage( argv[0] );
          return 2;   // XXX need standard exit codes
          break;

        default:
          QgsDebugMsg( QString( "%1: getopt returned character code %2" ).arg( argv[0] ).arg( optionChar ) );
          return 1;   // XXX need standard exit codes
      }
    }

    // Add any remaining args to the file list - we will attempt to load them
    // as layers in the map view further down....
    QgsDebugMsg( QString( "Files specified on command line: %1" ).arg( optind ) );
    if ( optind < argc )
    {
      while ( optind < argc )
      {
#ifdef QGISDEBUG
        int idx = optind;
        QgsDebugMsg( QString( "%1: %2" ).arg( idx ).arg( argv[idx] ) );
#endif
        myFileList.append( QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[optind++] ) ).absoluteFilePath() ) );
      }
    }
  }
#endif


  /////////////////////////////////////////////////////////////////////
  // Now we have the handlers for the different behaviours...
  ////////////////////////////////////////////////////////////////////

  /////////////////////////////////////////////////////////////////////
  // Initialise the application and the translation stuff
  /////////////////////////////////////////////////////////////////////

#ifdef Q_WS_X11
  bool myUseGuiFlag = getenv( "DISPLAY" ) != 0;
#else
  bool myUseGuiFlag = true;
#endif
  if ( !myUseGuiFlag )
  {
    std::cerr << QObject::tr(
                "QGIS starting in non-interactive mode not supported.\n"
                "You are seeing this message most likely because you "
                "have no DISPLAY environment variable set.\n"
              ).toUtf8().constData();
    exit( 1 ); //exit for now until a version of qgis is capabable of running non interactive
  }

  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, optionpath.isEmpty() ? configpath : optionpath );
  }

  // GUI customization is enabled according to settings (loaded when instance is created)
  // we force disabled here if --nocustomization argument is used
  if ( !myCustomization )
  {
    QgsCustomization::instance()->setEnabled( false );
  }

  QgsApplication myApp( argc, argv, myUseGuiFlag, configpath );

// (if Windows/Mac, use icon from resource)
#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC)
  myApp.setWindowIcon( QPixmap( qgis_xpm ) );        // Linux
#endif

  //
  // Set up the QSettings environment must be done after qapp is created
  QCoreApplication::setOrganizationName( "QGIS" );
  QCoreApplication::setOrganizationDomain( "qgis.org" );
  QCoreApplication::setApplicationName( "QGIS2" );
  QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );

  QSettings* customizationsettings;
  if ( !optionpath.isEmpty() || !configpath.isEmpty() )
  {
    // tell QSettings to use INI format and save the file in custom config path
    QSettings::setDefaultFormat( QSettings::IniFormat );
    QString path = optionpath.isEmpty() ? configpath : optionpath;
    QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, path );
    customizationsettings = new QSettings( QSettings::IniFormat, QSettings::UserScope, "QGIS", "QGISCUSTOMIZATION2" );
  }
  else
  {
    customizationsettings = new QSettings( "QGIS", "QGISCUSTOMIZATION2" );
  }

  // Using the customizationfile option always overrides the option and config path options.
  if ( !customizationfile.isEmpty() )
  {
    customizationsettings = new QSettings( customizationfile, QSettings::IniFormat );
    QgsCustomization::instance()->setEnabled( true );
  }

  // Load and set possible default customization, must be done afterQgsApplication init and QSettings ( QCoreApplication ) init
  QgsCustomization::instance()->setSettings( customizationsettings );
  QgsCustomization::instance()->loadDefault();

#ifdef Q_OS_MACX
  // If the GDAL plugins are bundled with the application and GDAL_DRIVER_PATH
  // is not already defined, use the GDAL plugins in the application bundle.
  QString gdalPlugins( QCoreApplication::applicationDirPath().append( "/lib/gdalplugins" ) );
  if ( QFile::exists( gdalPlugins ) && !getenv( "GDAL_DRIVER_PATH" ) )
  {
    setenv( "GDAL_DRIVER_PATH", gdalPlugins.toUtf8(), 1 );
  }
#endif

  QSettings mySettings;

  // update any saved setting for older themes to new default 'gis' theme (2013-04-15)
  if ( mySettings.contains( "/Themes" ) )
  {
    QString theme = mySettings.value( "/Themes", "default" ).toString();
    if ( theme == QString( "gis" )
         || theme == QString( "classic" )
         || theme == QString( "nkids" ) )
    {
      mySettings.setValue( "/Themes", QString( "default" ) );
    }
  }


  // custom environment variables
  QMap<QString, QString> systemEnvVars = QgsApplication::systemEnvVars();
  bool useCustomVars = mySettings.value( "qgis/customEnvVarsUse", QVariant( false ) ).toBool();
  if ( useCustomVars )
  {
    QStringList customVarsList = mySettings.value( "qgis/customEnvVars", "" ).toStringList();
    if ( !customVarsList.isEmpty() )
    {
      foreach ( const QString &varStr, customVarsList )
      {
        int pos = varStr.indexOf( QLatin1Char( '|' ) );
        if ( pos == -1 )
          continue;
        QString envVarApply = varStr.left( pos );
        QString varStrNameValue = varStr.mid( pos + 1 );
        pos = varStrNameValue.indexOf( QLatin1Char( '=' ) );
        if ( pos == -1 )
          continue;
        QString envVarName = varStrNameValue.left( pos );
        QString envVarValue = varStrNameValue.mid( pos + 1 );

        if ( systemEnvVars.contains( envVarName ) )
        {
          if ( envVarApply == "prepend" )
          {
            envVarValue += systemEnvVars.value( envVarName );
          }
          else if ( envVarApply == "append" )
          {
            envVarValue = systemEnvVars.value( envVarName ) + envVarValue;
          }
        }

        if ( systemEnvVars.contains( envVarName ) && envVarApply == "unset" )
        {
#ifdef Q_WS_WIN
          putenv( envVarName.toUtf8().constData() );
#else
          unsetenv( envVarName.toUtf8().constData() );
#endif
        }
        else
        {
#ifdef Q_WS_WIN
          if ( envVarApply != "undefined" || !getenv( envVarName.toUtf8().constData() ) )
            putenv( QString( "%1=%2" ).arg( envVarName ).arg( envVarValue ).toUtf8().constData() );
#else
          setenv( envVarName.toUtf8().constData(), envVarValue.toUtf8().constData(), envVarApply == "undefined" ? 0 : 1 );
#endif
        }
      }
    }