long QgsProjectionSelectionTreeWidget::getLargestCrsIdMatch( const QString &sql )
{
  long srsId = 0;

  //
  // Now perform the actual search
  //

  sqlite3      *database = nullptr;
  const char   *tail = nullptr;
  sqlite3_stmt *stmt = nullptr;
  int           result;

  // first we search the users db as any srsid there will be definition be greater than in sys db

  //check the db is available
  QString databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
  if ( QFileInfo::exists( databaseFileName ) ) //only bother trying to open if the file exists
  {
    result = sqlite3_open_v2( databaseFileName.toUtf8().data(), &database, SQLITE_OPEN_READONLY, nullptr );
    if ( result )
    {
      // XXX This will likely never happen since on open, sqlite creates the
      //     database if it does not exist. But we checked earlier for its existence
      //     and aborted in that case. This is because we may be running from read only
      //     media such as live cd and don't want to force trying to create a db.
      showDBMissingWarning( databaseFileName );
      return 0;
    }

    result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
    // XXX Need to free memory from the error msg if one is set
    if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
    {
      QString srsIdString = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
      srsId = srsIdString.toLong();
      // close the sqlite3 statement
      sqlite3_finalize( stmt );
      sqlite3_close( database );
      return srsId;
    }
  }
  else
  {
    //only bother looking in srs.db if it wasn't found above
    result = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().data(), &database, SQLITE_OPEN_READONLY, nullptr );
    if ( result )
    {
      QgsDebugMsg( QString( "Can't open * user * database: %1" ).arg( sqlite3_errmsg( database ) ) );
      //no need for assert because user db may not have been created yet
      return 0;
    }
  }

  result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
  // XXX Need to free memory from the error msg if one is set
  if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
  {
    QString srsIdString = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
    srsId = srsIdString.toLong();
  }

  // close the sqlite3 statement
  sqlite3_finalize( stmt );
  sqlite3_close( database );

  return srsId;
}
void QgsProjectionSelectionTreeWidget::loadUserCrsList( QSet<QString> *crsFilter )
{
  if ( mUserProjListDone )
    return;

  QgsDebugMsgLevel( "Fetching user projection list...", 4 );

  // convert our Coordinate Reference System filter into the SQL expression
  QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );

  // User defined coordinate system node
  // Make in an italic font to distinguish them from real projections
  mUserProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "User Defined Coordinate Systems" ) ) );

  QFont fontTemp = mUserProjList->font( 0 );
  fontTemp.setItalic( true );
  fontTemp.setBold( true );
  mUserProjList->setFont( 0, fontTemp );
  mUserProjList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) ) );

  //determine where the user proj database lives for this user. If none is found an empty
  //now only will be shown
  QString databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
  // first we look for ~/.qgis/qgis.db
  // if it doesn't exist we copy it in from the global resources dir

  //return straight away if the user has not created any custom projections
  if ( !QFileInfo::exists( databaseFileName ) )
  {
    QgsDebugMsg( "Users qgis.db not found...skipping" );
    mUserProjListDone = true;
    return;
  }

  sqlite3      *database = nullptr;
  const char   *tail = nullptr;
  sqlite3_stmt *stmt = nullptr;
  //check the db is available
  int result = sqlite3_open_v2( databaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
  if ( result )
  {
    // XXX This will likely never happen since on open, sqlite creates the
    //     database if it does not exist. But we checked earlier for its existence
    //     and aborted in that case. This is because we may be running from read only
    //     media such as live cd and don't want to force trying to create a db.
    showDBMissingWarning( databaseFileName );
    return;
  }

  // Set up the query to retrieve the projection information needed to populate the list
  QString sql = QStringLiteral( "select description, srs_id from vw_srs where %1" ).arg( sqlFilter );

  result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
  // XXX Need to free memory from the error msg if one is set
  if ( result == SQLITE_OK )
  {
    QTreeWidgetItem *newItem = nullptr;
    while ( sqlite3_step( stmt ) == SQLITE_ROW )
    {
      newItem = new QTreeWidgetItem( mUserProjList, QStringList( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) ) ) );
      // EpsgCrsId for user projections is not always defined in some dbases.
      // It's also not written from customprojections dialog.
      // display the epsg (field 2) in the second column of the list view
      // newItem->setText( EPSG_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( stmt, 2 ) ) );
      // display the qgis srs_id (field 1) in the third column of the list view
      newItem->setText( QgisCrsIdColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ) );
      newItem->setText( AuthidColumn, QStringLiteral( "USER:%1" ).arg( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ).toInt() ) );
    }
  }
  // close the sqlite3 statement
  sqlite3_finalize( stmt );
  sqlite3_close( database );

  mUserProjListDone = true;
}
void QgsProjectionSelectionTreeWidget::loadCrsList( QSet<QString> *crsFilter )
{
  if ( mProjListDone )
    return;

  // convert our Coordinate Reference System filter into the SQL expression
  QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );

  // Create the top-level nodes for the list view of projections
  // Make in an italic font to distinguish them from real projections
  //
  // Geographic coordinate system node
  mGeoList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Geographic Coordinate Systems" ) ) );

  QFont fontTemp = mGeoList->font( 0 );
  fontTemp.setItalic( true );
  fontTemp.setBold( true );
  mGeoList->setFont( 0, fontTemp );
  mGeoList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) ) );

  // Projected coordinate system node
  mProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Projected Coordinate Systems" ) ) );

  fontTemp = mProjList->font( 0 );
  fontTemp.setItalic( true );
  fontTemp.setBold( true );
  mProjList->setFont( 0, fontTemp );
  mProjList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) ) );

  //bail out in case the projections db does not exist
  //this is necessary in case the pc is running linux with a
  //read only filesystem because otherwise sqlite will try
  //to create the db file on the fly

  if ( !QFileInfo::exists( mSrsDatabaseFileName ) )
  {
    mProjListDone = true;
    return;
  }

  // open the database containing the spatial reference data
  sqlite3 *database = nullptr;
  int rc = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().data(), &database, SQLITE_OPEN_READONLY, nullptr );
  if ( rc )
  {
    // XXX This will likely never happen since on open, sqlite creates the
    //     database if it does not exist.
    showDBMissingWarning( mSrsDatabaseFileName );
    return;
  }

  const char *tail = nullptr;
  sqlite3_stmt *stmt = nullptr;
  // Set up the query to retrieve the projection information needed to populate the list
  //note I am giving the full field names for clarity here and in case someone
  //changes the underlying view TS
  QString sql = QStringLiteral( "select description, srs_id, upper(auth_name||':'||auth_id), is_geo, name, parameters, deprecated from vw_srs where %1 order by name,description" )
                .arg( sqlFilter );

  rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
  // XXX Need to free memory from the error msg if one is set
  if ( rc == SQLITE_OK )
  {
    QTreeWidgetItem *newItem = nullptr;
    // Cache some stuff to speed up creating of the list of projected
    // spatial reference systems
    QString previousSrsType;
    QTreeWidgetItem *previousSrsTypeNode = nullptr;

    while ( sqlite3_step( stmt ) == SQLITE_ROW )
    {
      // check to see if the srs is geographic
      int isGeo = sqlite3_column_int( stmt, 3 );
      if ( isGeo )
      {
        // this is a geographic coordinate system
        // Add it to the tree (field 0)
        newItem = new QTreeWidgetItem( mGeoList, QStringList( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) ) ) );

        // display the authority name (field 2) in the second column of the list view
        newItem->setText( AuthidColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 2 ) ) );

        // display the qgis srs_id (field 1) in the third column of the list view
        newItem->setText( QgisCrsIdColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ) );
      }
      else
      {
        // This is a projected srs
        QTreeWidgetItem *node = nullptr;
        QString srsType = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 4 ) );
        // Find the node for this type and add the projection to it
        // If the node doesn't exist, create it
        if ( srsType == previousSrsType )
        {
          node = previousSrsTypeNode;
        }
        else
        {
          // Different from last one, need to search
          QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( srsType, Qt::MatchExactly | Qt::MatchRecursive, NameColumn );
          if ( nodes.isEmpty() )
          {
            // the node doesn't exist -- create it
            // Make in an italic font to distinguish them from real projections
            node = new QTreeWidgetItem( mProjList, QStringList( srsType ) );
            QFont fontTemp = node->font( 0 );
            fontTemp.setItalic( true );
            node->setFont( 0, fontTemp );
          }
          else
          {
            node = nodes.first();
          }
          // Update the cache.
          previousSrsType = srsType;
          previousSrsTypeNode = node;
        }
        // add the item, setting the projection name in the first column of the list view
        newItem = new QTreeWidgetItem( node, QStringList( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) ) ) );
        // display the authority id (field 2) in the second column of the list view
        newItem->setText( AuthidColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 2 ) ) );
        // display the qgis srs_id (field 1) in the third column of the list view
        newItem->setText( QgisCrsIdColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ) );
        // expand also parent node
        newItem->parent()->setExpanded( true );
      }

      // display the qgis deprecated in the user data of the item
      newItem->setData( 0, RoleDeprecated, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 6 ) ) );
      newItem->setHidden( cbxHideDeprecated->isChecked() );
    }
    mProjList->setExpanded( true );
  }

  // close the sqlite3 statement
  sqlite3_finalize( stmt );
  // close the database
  sqlite3_close( database );

  mProjListDone = true;
}
long QgsProjectionSelector::getLargestCRSIDMatch( QString theSql )
{
    long mySrsId = 0;
    //
    // Now perform the actual search
    //

    sqlite3      *myDatabase;
    const char   *myTail;
    sqlite3_stmt *myPreparedStatement;
    int           myResult;

    // first we search the users db as any srsid there will be definition be greater than in sys db

    //check the db is available
    QString myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
    QFileInfo myFileInfo;
    myFileInfo.setFile( myDatabaseFileName );
    if ( myFileInfo.exists( ) ) //only bother trying to open if the file exists
    {
        myResult = sqlite3_open( myDatabaseFileName.toUtf8().data(), &myDatabase );
        if ( myResult )
        {
            // XXX This will likely never happen since on open, sqlite creates the
            //     database if it does not exist. But we checked earlier for its existance
            //     and aborted in that case. This is because we may be runnig from read only
            //     media such as live cd and dont want to force trying to create a db.
            showDBMissingWarning( myDatabaseFileName );
            return 0;
        }
        else
        {
            myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.length(), &myPreparedStatement, &myTail );
            // XXX Need to free memory from the error msg if one is set
            if ( myResult == SQLITE_OK )
            {
                myResult = sqlite3_step( myPreparedStatement );
                if ( myResult == SQLITE_ROW )
                {
                    QString mySrsIdString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
                    mySrsId = mySrsIdString.toLong();
                    // close the sqlite3 statement
                    sqlite3_finalize( myPreparedStatement );
                    sqlite3_close( myDatabase );
                    return mySrsId;
                }
            }
        }
    }

    //only bother looking in srs.db if it wasnt found above

    myResult = sqlite3_open( mSrsDatabaseFileName.toUtf8().data(), &myDatabase );
    if ( myResult )
    {
        QgsDebugMsg( QString( "Can't open * user * database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
        //no need for assert because user db may not have been created yet
        return 0;
    }

    myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.length(), &myPreparedStatement, &myTail );
    // XXX Need to free memory from the error msg if one is set
    if ( myResult == SQLITE_OK )
    {
        myResult = sqlite3_step( myPreparedStatement );
        if ( myResult == SQLITE_ROW )
        {
            QString mySrsIdString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
            mySrsId =  mySrsIdString.toLong();
            // close the sqlite3 statement
            sqlite3_finalize( myPreparedStatement );
            sqlite3_close( myDatabase );
        }
    }
    return mySrsId;
}
// Returns the whole proj4 string for the selected projection node
QString QgsProjectionSelectionTreeWidget::selectedProj4String()
{
  // Only return the projection if there is a node in the tree
  // selected that has an srid. This prevents error if the user
  // selects a top-level node rather than an actual coordinate
  // system
  //
  // Get the selected node
  QTreeWidgetItem *item = lstCoordinateSystems->currentItem();
  if ( !item || item->text( QgisCrsIdColumn ).isEmpty() )
    return QString();

  QString srsId = item->text( QgisCrsIdColumn );

  QgsDebugMsgLevel( "srsId = " + srsId, 4 );
  QgsDebugMsgLevel( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ), 4 );

  //
  // Determine if this is a user projection or a system on
  // user projection defs all have srs_id >= 100000
  //
  QString databaseFileName;
  if ( srsId.toLong() >= USER_CRS_START_ID )
  {
    databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
    if ( !QFileInfo::exists( databaseFileName ) ) //its unlikely that this condition will ever be reached
      return QString();
  }
  else //must be a system projection then
  {
    databaseFileName = mSrsDatabaseFileName;
  }

  QgsDebugMsgLevel( "db = " + databaseFileName, 4 );

  sqlite3 *database = nullptr;
  int rc = sqlite3_open_v2( databaseFileName.toUtf8().data(), &database, SQLITE_OPEN_READONLY, nullptr );
  if ( rc )
  {
    showDBMissingWarning( databaseFileName );
    return QString();
  }

  // prepare the sql statement
  const char *tail = nullptr;
  sqlite3_stmt *stmt = nullptr;
  QString sql = QStringLiteral( "select parameters from tbl_srs where srs_id=%1" ).arg( srsId );

  QgsDebugMsgLevel( "Selection sql: " + sql, 4 );

  rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
  // XXX Need to free memory from the error msg if one is set
  QString projString;
  if ( rc == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
  {
    projString = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
  }

  // close the statement
  sqlite3_finalize( stmt );
  // close the database
  sqlite3_close( database );

  Q_ASSERT( !projString.isEmpty() );

  return projString;
}
void QgsProjectionSelector::on_pbnFind_clicked()
{

    QgsDebugMsg( "pbnFind..." );

    QString mySearchString( sqlSafeString( leSearch->text() ) );
    // Set up the query to retrieve the projection information needed to populate the list
    QString mySql;
    if ( radEpsgCrsId->isChecked() )
    {
        mySql = "select srs_id from tbl_srs where epsg=" + mySearchString;
    }
    else if ( radName->isChecked() ) //name search
    {
        //we need to find what the largest srsid matching our query so we know whether to
        //loop backto the beginning
        mySql = "select srs_id from tbl_srs where description like '%" + mySearchString + "%'" +
                " order by srs_id desc limit 1";
        long myLargestSrsId = getLargestCRSIDMatch( mySql );
        QgsDebugMsg( QString( "Largest CRSID%1" ).arg( myLargestSrsId ) );
        //a name search is ambiguous, so we find the first srsid after the current seelcted srsid
        // each time the find button is pressed. This means we can loop through all matches.
        if ( myLargestSrsId <= selectedCrsId() )
        {
            //roll search around to the beginning
            mySql = "select srs_id from tbl_srs where description like '%" + mySearchString + "%'" +
                    " order by srs_id limit 1";
        }
        else
        {
            // search ahead of the current postion
            mySql = "select srs_id from tbl_srs where description like '%" + mySearchString + "%'" +
                    " and srs_id > " + QString::number( selectedCrsId() ) + " order by srs_id limit 1";
        }
    }
    QgsDebugMsg( QString( " Search sql: %1" ).arg( mySql ) );

    //
    // Now perform the actual search
    //

    sqlite3      *myDatabase;
    const char   *myTail;
    sqlite3_stmt *myPreparedStatement;
    int           myResult;
    //check the db is available
    myResult = sqlite3_open( mSrsDatabaseFileName.toUtf8().data(), &myDatabase );
    if ( myResult )
    {
        // XXX This will likely never happen since on open, sqlite creates the
        //     database if it does not exist. But we checked earlier for its existance
        //     and aborted in that case. This is because we may be runnig from read only
        //     media such as live cd and dont want to force trying to create a db.
        showDBMissingWarning( mSrsDatabaseFileName );
        return;
    }

    myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
    // XXX Need to free memory from the error msg if one is set
    if ( myResult == SQLITE_OK )
    {
        myResult = sqlite3_step( myPreparedStatement );
        if ( myResult == SQLITE_ROW )
        {
            QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
            setSelectedCrsId( mySrsId.toLong() );
            // close the sqlite3 statement
            sqlite3_finalize( myPreparedStatement );
            sqlite3_close( myDatabase );
            return;
        }
    }
    //search the users db
    QString myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
    QFileInfo myFileInfo;
    myFileInfo.setFile( myDatabaseFileName );
    if ( !myFileInfo.exists( ) ) //its not critical if this happens
    {
        qDebug( "%s\nUser db does not exist", myDatabaseFileName.toUtf8().constData() );
        return ;
    }
    myResult = sqlite3_open( myDatabaseFileName.toUtf8().data(), &myDatabase );
    if ( myResult )
    {
        QgsDebugMsg( QString( "Can't open * user * database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
        //no need for assert because user db may not have been created yet
        return;
    }

    myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
    // XXX Need to free memory from the error msg if one is set
    if ( myResult == SQLITE_OK )
    {
        myResult = sqlite3_step( myPreparedStatement );
        if ( myResult == SQLITE_ROW )
        {
            QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
            setSelectedCrsId( mySrsId.toLong() );
            // close the sqlite3 statement
            sqlite3_finalize( myPreparedStatement );
            sqlite3_close( myDatabase );
        }
    }
}
void QgsProjectionSelector::loadCrsList( QSet<QString> * crsFilter )
{
    // convert our Coordinate Reference System filter into the SQL expression
    QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );

    // Create the top-level nodes for the list view of projections
    // Make in an italic font to distinguish them from real projections
    //
    // Geographic coordinate system node
    mGeoList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Geographic Coordinate Systems" ) ) );

    QFont fontTemp = mGeoList->font( 0 );
    fontTemp.setItalic( TRUE );
    fontTemp.setBold( TRUE );
    mGeoList->setFont( 0, fontTemp );
    mGeoList->setIcon( 0, QIcon( QgsApplication::activeThemePath() + "geographic.png" ) );

    // Projected coordinate system node
    mProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Projected Coordinate Systems" ) ) );

    fontTemp = mProjList->font( 0 );
    fontTemp.setItalic( TRUE );
    fontTemp.setBold( TRUE );
    mProjList->setFont( 0, fontTemp );
    mProjList->setIcon( 0, QIcon( QgsApplication::activeThemePath() + "transformed.png" ) );

    //bail out in case the projections db does not exist
    //this is neccessary in case the pc is running linux with a
    //read only filesystem because otherwise sqlite will try
    //to create the db file on the fly

    QFileInfo myFileInfo;
    myFileInfo.setFile( mSrsDatabaseFileName );
    if ( !myFileInfo.exists( ) )
    {
        mProjListDone = TRUE;
        return;
    }

    // open the database containing the spatial reference data
    sqlite3 *db;
    int rc;
    rc = sqlite3_open( mSrsDatabaseFileName.toUtf8().data(), &db );
    if ( rc )
    {
        // XXX This will likely never happen since on open, sqlite creates the
        //     database if it does not exist.
        showDBMissingWarning( mSrsDatabaseFileName );
        return ;
    }
    // prepare the sql statement
    const char *pzTail;
    sqlite3_stmt *ppStmt;
    // get total count of records in the projection table
    QString sql = "select count(*) from tbl_srs";

    rc = sqlite3_prepare( db, sql.toUtf8(), sql.length(), &ppStmt, &pzTail );
    assert( rc == SQLITE_OK );
    sqlite3_step( ppStmt );

    sqlite3_finalize( ppStmt );

    // Set up the query to retrieve the projection information needed to populate the list
    //note I am giving the full field names for clarity here and in case someown
    //changes the underlying view TS
    sql = "select description, srs_id, epsg, is_geo, name, parameters from vw_srs ";
    sql += "where ";
    sql += sqlFilter;
    sql += " order by name, description";

    rc = sqlite3_prepare( db, sql.toUtf8(), sql.length(), &ppStmt, &pzTail );
    // XXX Need to free memory from the error msg if one is set
    if ( rc == SQLITE_OK )
    {
        QTreeWidgetItem *newItem;
        // Cache some stuff to speed up creating of the list of projected
        // spatial reference systems
        QString previousSrsType( "" );
        QTreeWidgetItem* previousSrsTypeNode = NULL;

        while ( sqlite3_step( ppStmt ) == SQLITE_ROW )
        {
            // check to see if the srs is geographic
            int isGeo = sqlite3_column_int( ppStmt, 3 );
            if ( isGeo )
            {
                // this is a geographic coordinate system
                // Add it to the tree (field 0)
                newItem = new QTreeWidgetItem( mGeoList, QStringList( QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 0 ) ) ) );

                // display the epsg (field 2) in the second column of the list view
                newItem->setText( EPSG_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 2 ) ) );

                // display the qgis srs_id (field 1) in the third column of the list view
                newItem->setText( QGIS_CRS_ID_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 1 ) ) );
            }
            else
            {
                // This is a projected srs
                QTreeWidgetItem *node;
                QString srsType = QString::fromUtf8(( char* )sqlite3_column_text( ppStmt, 4 ) );
                // Find the node for this type and add the projection to it
                // If the node doesn't exist, create it
                if ( srsType == previousSrsType )
                {
                    node = previousSrsTypeNode;
                }
                else
                {   // Different from last one, need to search
                    QList<QTreeWidgetItem*> nodes = lstCoordinateSystems->findItems( srsType, Qt::MatchExactly | Qt::MatchRecursive, 0 );
                    if ( nodes.count() == 0 )
                    {
                        // the node doesn't exist -- create it
                        // Make in an italic font to distinguish them from real projections
                        node = new QTreeWidgetItem( mProjList, QStringList( srsType ) );

                        QFont fontTemp = node->font( 0 );
                        fontTemp.setItalic( TRUE );
                        node->setFont( 0, fontTemp );
                    }
                    else
                    {
                        node = nodes.first();
                    }
                    // Update the cache.
                    previousSrsType = srsType;
                    previousSrsTypeNode = node;
                }
                // add the item, setting the projection name in the first column of the list view
                newItem = new QTreeWidgetItem( node, QStringList( QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 0 ) ) ) );
                // display the epsg (field 2) in the second column of the list view
                newItem->setText( EPSG_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 2 ) ) );
                // display the qgis srs_id (field 1) in the third column of the list view
                newItem->setText( QGIS_CRS_ID_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 1 ) ) );
            }
        }
        mProjList->setExpanded( true );
    }
    // close the sqlite3 statement
    sqlite3_finalize( ppStmt );
    // close the database
    sqlite3_close( db );

    mProjListDone = TRUE;
}
void QgsProjectionSelector::loadUserCrsList( QSet<QString> * crsFilter )
{
    QgsDebugMsg( "Fetching user projection list..." );

    // convert our Coordinate Reference System filter into the SQL expression
    QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );

    // User defined coordinate system node
    // Make in an italic font to distinguish them from real projections
    mUserProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "User Defined Coordinate Systems" ) ) );

    QFont fontTemp = mUserProjList->font( 0 );
    fontTemp.setItalic( TRUE );
    fontTemp.setBold( TRUE );
    mUserProjList->setFont( 0, fontTemp );
    mUserProjList->setIcon( 0, QIcon( QgsApplication::activeThemePath() + "user.png" ) );

    //determine where the user proj database lives for this user. If none is found an empty
    //now only will be shown
    QString myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
    // first we look for ~/.qgis/qgis.db
    // if it doesnt exist we copy it in from the global resources dir
    QFileInfo myFileInfo;
    myFileInfo.setFile( myDatabaseFileName );
    //return straight away if the user has not created any custom projections
    if ( !myFileInfo.exists( ) )
    {
        QgsDebugMsg( "Users qgis.db not found...skipping" );

        mUserProjListDone = TRUE;
        return;
    }

    sqlite3      *myDatabase;
    const char   *myTail;
    sqlite3_stmt *myPreparedStatement;
    int           myResult;
    //check the db is available
    myResult = sqlite3_open( QString( myDatabaseFileName ).toUtf8().data(), &myDatabase );
    if ( myResult )
    {
        // XXX This will likely never happen since on open, sqlite creates the
        //     database if it does not exist. But we checked earlier for its existance
        //     and aborted in that case. This is because we may be runnig from read only
        //     media such as live cd and dont want to force trying to create a db.
        showDBMissingWarning( myDatabaseFileName );
        return;
    }

    // Set up the query to retrieve the projection information needed to populate the list
    QString mySql = "select description, srs_id from vw_srs ";
    mySql += "where ";
    mySql += sqlFilter;

    myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
    // XXX Need to free memory from the error msg if one is set
    if ( myResult == SQLITE_OK )
    {
        QTreeWidgetItem *newItem;
        while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
        {
            newItem = new QTreeWidgetItem( mUserProjList, QStringList( QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ) ) );
            // EpsgCrsId for user projections is not always defined in some dbases.
            // It's also not written from customprojections dialog.
            // display the epsg (field 2) in the second column of the list view
            // newItem->setText( EPSG_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 2 ) ) );
            // display the qgis srs_id (field 1) in the third column of the list view
            newItem->setText( QGIS_CRS_ID_COLUMN, QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) ) );
        }
    }
    // close the sqlite3 statement
    sqlite3_finalize( myPreparedStatement );
    sqlite3_close( myDatabase );

    mUserProjListDone = TRUE;
}
long QgsProjectionSelector::getSelectedLongAttribute( QString attributeName )
{
    // Only return the attribute if there is a node in the tree
    // selected that has an srs_id.  This prevents error if the user
    // selects a top-level node rather than an actual coordinate
    // system
    //
    // Get the selected node
    QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
    if ( lvi )
    {
        // Make sure the selected node is a srs and not a top-level projection node
        if ( lvi->text( QGIS_CRS_ID_COLUMN ).length() > 0 )
        {
            QString myDatabaseFileName;
            //
            // Determine if this is a user projection or a system on
            // user projection defs all have srs_id >= 100000
            //
            if ( lvi->text( QGIS_CRS_ID_COLUMN ).toLong() >= USER_CRS_START_ID )
            {
                myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
                QFileInfo myFileInfo;
                myFileInfo.setFile( myDatabaseFileName );
                if ( !myFileInfo.exists( ) )
                {
                    QgsDebugMsg( " Projection selector :  users qgis.db not found" );
                    return 0;
                }
            }
            else //must be  a system projection then
            {
                myDatabaseFileName = mSrsDatabaseFileName;
            }
            //
            // set up the database
            // XXX We could probabaly hold the database open for the life of this object,
            // assuming that it will never be used anywhere else. Given the low overhead,
            // opening it each time seems to be a reasonable approach at this time.
            sqlite3 *db;
            int rc;
            rc = sqlite3_open( myDatabaseFileName.toUtf8().data(), &db );
            if ( rc )
            {
                showDBMissingWarning( myDatabaseFileName );
                return 0;
            }
            // prepare the sql statement
            const char *pzTail;
            sqlite3_stmt *ppStmt;
            QString sql = "select ";
            sql += attributeName;
            sql += " from tbl_srs where srs_id = ";
            sql += lvi->text( QGIS_CRS_ID_COLUMN );

            QgsDebugMsg( QString( "Finding selected attribute using : %1" ).arg( sql ) );
            rc = sqlite3_prepare( db, sql.toUtf8(), sql.length(), &ppStmt, &pzTail );
            // XXX Need to free memory from the error msg if one is set
            QString myAttributeValue;
            if ( rc == SQLITE_OK )
            {
                // get the first row of the result set
                if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
                {
                    // get the attribute
                    myAttributeValue = QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 0 ) );
                }
            }
            // close the statement
            sqlite3_finalize( ppStmt );
            // close the database
            sqlite3_close( db );
            // return the srs wkt
            return myAttributeValue.toLong();
        }
    }

    // No node is selected, return null
    return 0;
}
// Returns the whole proj4 string for the selected projection node
QString QgsProjectionSelector::selectedProj4String()
{
    // Only return the projection if there is a node in the tree
    // selected that has an srid. This prevents error if the user
    // selects a top-level node rather than an actual coordinate
    // system
    //
    // Get the selected node
    QTreeWidgetItem *myItem = lstCoordinateSystems->currentItem();
    if ( myItem )
    {

        if ( myItem->text( QGIS_CRS_ID_COLUMN ).length() > 0 )
        {
            QString myDatabaseFileName;
            QString mySrsId = myItem->text( QGIS_CRS_ID_COLUMN );

            QgsDebugMsg( "mySrsId = " + mySrsId );
            QgsDebugMsg( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ) );
            //
            // Determine if this is a user projection or a system on
            // user projection defs all have srs_id >= 100000
            //
            if ( mySrsId.toLong() >= USER_CRS_START_ID )
            {
                myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
                QFileInfo myFileInfo;
                myFileInfo.setFile( myDatabaseFileName );
                if ( !myFileInfo.exists( ) ) //its unlikely that this condition will ever be reached
                {
                    QgsDebugMsg( "users qgis.db not found" );
                    return QString( "" );
                }
                else
                {
                    QgsDebugMsg( "users qgis.db found" );
                }
            }
            else //must be  a system projection then
            {
                myDatabaseFileName =  mSrsDatabaseFileName;
            }
            QgsDebugMsg( "db = " + myDatabaseFileName );


            sqlite3 *db;
            int rc;
            rc = sqlite3_open( myDatabaseFileName.toUtf8().data(), &db );
            if ( rc )
            {
                showDBMissingWarning( myDatabaseFileName );
                return QString( "" );
            }
            // prepare the sql statement
            const char *pzTail;
            sqlite3_stmt *ppStmt;
            QString sql = "select parameters from tbl_srs where srs_id = ";
            sql += mySrsId;

            QgsDebugMsg( "Selection sql: " + sql );

            rc = sqlite3_prepare( db, sql.toUtf8(), sql.length(), &ppStmt, &pzTail );
            // XXX Need to free memory from the error msg if one is set
            QString myProjString;
            if ( rc == SQLITE_OK )
            {
                if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
                {
                    myProjString = QString::fromUtf8(( char * )sqlite3_column_text( ppStmt, 0 ) );
                }
            }
            // close the statement
            sqlite3_finalize( ppStmt );
            // close the database
            sqlite3_close( db );
            assert( myProjString.length() > 0 );
            return myProjString;
        }
        else
        {
            // No node is selected, return null
            return QString( "" );
        }
    }
    else
    {
        // No node is selected, return null
        return QString( "" );
    }

}