[QGIS Commit] r11366 - trunk/qgis/src/core

svn_qgis at osgeo.org svn_qgis at osgeo.org
Thu Aug 13 19:10:33 EDT 2009


Author: homann
Date: 2009-08-13 19:10:32 -0400 (Thu, 13 Aug 2009)
New Revision: 11366

Modified:
   trunk/qgis/src/core/qgscoordinatereferencesystem.cpp
   trunk/qgis/src/core/qgscoordinatereferencesystem.h
Log:
Automatically adds projections previously unknown to QGIS (but still valid) as a Custom CRS. This can later be edited for name etc. No user interaction required, one new text to translate. Fixes #418.

Modified: trunk/qgis/src/core/qgscoordinatereferencesystem.cpp
===================================================================
--- trunk/qgis/src/core/qgscoordinatereferencesystem.cpp	2009-08-13 20:43:26 UTC (rev 11365)
+++ trunk/qgis/src/core/qgscoordinatereferencesystem.cpp	2009-08-13 23:10:32 UTC (rev 11366)
@@ -31,6 +31,7 @@
 #include "qgsmessageoutput.h"
 #include "qgis.h" //const vals declared here
 
+#include <cassert>
 #include <sqlite3.h>
 
 //gdal and ogr includes (needed for == operator)
@@ -349,18 +350,20 @@
   *   have been set if this method has been delegated to from createFromWkt.
   * Normally we wouldnt expect this to work, but its worth trying first
   * as its quicker than methods below..
-  */
+  */  
   long mySrsId = 0;
   QgsCoordinateReferenceSystem::RecordMap myRecord;
-  if ( !mDescription.trimmed().isEmpty() )
-  {
-    myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
-  }
 
+  // *** Matching on descriptions feels iffy. Different projs can have same description. Homann ***
+  // if ( !mDescription.trimmed().isEmpty() )
+  //{
+  //  myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
+  //}
+
   /*
   * - if the above does not match perform a whole text search on proj4 string (if not null)
   */
-  QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
+  // QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
   myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
   if ( !myRecord.empty() )
   {
@@ -434,7 +437,34 @@
   // if we failed to look up the projection in database, don't worry. we can still use it :)
   if ( !mIsValidFlag )
   {
+    QgsDebugMsg( "Projection is not found in databases." );
     setProj4String( theProj4String );
+    // Is the SRS is valid now, we know it's a decent +proj string that can be entered into the srs.db
+    if ( mIsValidFlag )
+    {
+      // Try to save. If not possible, set to invalid. Problems on read only systems?
+      QgsDebugMsg( "Projection appears to be valid. Save to database!" );
+      mIsValidFlag = saveAsUserCRS();
+      // The srsid is not set, we should do that now.
+      if ( mIsValidFlag )
+      {
+	myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
+	if ( !myRecord.empty() )
+	{
+	  mySrsId = myRecord["srs_id"].toLong();
+	  QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
+	  if ( mySrsId > 0 )
+	  {
+	    createFromSrsId( mySrsId );
+	  }
+	  else
+	  {
+	    QgsDebugMsg( "Couldn't find newly added proj string?" );
+	    mIsValidFlag = false;
+	  }
+	}
+      }
+    }
   }
 
 
@@ -610,7 +640,8 @@
   toProj4 = proj4src;
   CPLFree( proj4src );
 
-  return toProj4;
+  // Stray spaces at the end?
+  return toProj4.trimmed();
 }
 
 bool QgsCoordinateReferenceSystem::geographicFlag() const
@@ -740,7 +771,7 @@
   QgsDebugMsg( "entered." );
   if ( mEllipsoidAcronym.isNull() ||  mProjectionAcronym.isNull() || !mIsValidFlag )
   {
-    QgsLogger::warning( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
+    QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
     return 0;
   }
 
@@ -1122,3 +1153,127 @@
 {
   return mValidationHint;
 }
+
+/// Copied from QgsCustomProjectionDialog ///
+/// Please refactor into SQL handler !!!  ///
+
+bool QgsCoordinateReferenceSystem::saveAsUserCRS() 
+{
+
+  if ( ! mIsValidFlag )
+  {
+    QgsDebugMsg( "Can't save an invalid CRS!" );
+    return false;
+  }
+
+  QString mySql;
+  QString myName = QString( " * %1 (%2)" )
+    .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ))
+    .arg( toProj4() );
+
+  //if this is the first record we need to ensure that its srs_id is 10000. For
+  //any rec after that sqlite3 will take care of the autonumering
+  //this was done to support sqlite 3.0 as it does not yet support
+  //the autoinc related system tables.
+  if ( getRecordCount() == 0 )
+  {
+    mySql = QString( "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) " )
+      + " values (" + QString::number( USER_CRS_START_ID ) + ",'"
+      + sqlSafeString( myName ) + "','" + projectionAcronym()
+      + "','" + ellipsoidAcronym()  + "','" + sqlSafeString( toProj4() )
+      + "',0)"; // <-- is_geo shamelessly hard coded for now
+  }
+  else
+  {
+    mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ('"
+      + sqlSafeString( myName ) + "','" + projectionAcronym()
+      + "','" + ellipsoidAcronym()  + "','" + sqlSafeString( toProj4() )
+      + "',0)"; // <-- is_geo shamelessly hard coded for now
+  }
+  sqlite3      *myDatabase;
+  const char   *myTail;
+  sqlite3_stmt *myPreparedStatement;
+  int           myResult;
+  //check the db is available
+  myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
+  if ( myResult != SQLITE_OK )
+  {
+    QgsDebugMsg( QString( "Can't open database: %1 \n please notify  QGIS developers of this error \n %2 (file name) " ).arg( sqlite3_errmsg( myDatabase ) ).arg( QgsApplication::qgisUserDbFilePath() ) );
+    // XXX This will likely never happen since on open, sqlite creates the
+    //     database if it does not exist.
+    assert( myResult == SQLITE_OK );
+  }
+  QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
+  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
+  sqlite3_step( myPreparedStatement );
+  // XXX Need to free memory from the error msg if one is set
+  return myResult == SQLITE_OK;
+
+}
+
+long QgsCoordinateReferenceSystem::getRecordCount()
+{
+  sqlite3      *myDatabase;
+  const char   *myTail;
+  sqlite3_stmt *myPreparedStatement;
+  int           myResult;
+  long          myRecordCount = 0;
+  //check the db is available
+  myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
+  if ( myResult != SQLITE_OK )
+  {
+    QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
+    // XXX This will likely never happen since on open, sqlite creates the
+    //     database if it does not exist.
+    assert( myResult == SQLITE_OK );
+  }
+  // Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
+  QString mySql = "select count(*) from tbl_srs";
+  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 )
+  {
+    if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
+    {
+      QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
+      myRecordCount = myRecordCountString.toLong();
+    }
+  }
+  // close the sqlite3 statement
+  sqlite3_finalize( myPreparedStatement );
+  sqlite3_close( myDatabase );
+  return myRecordCount;
+
+}
+
+const QString QgsCoordinateReferenceSystem::sqlSafeString( const QString theSQL )
+{
+
+  QString myRetval;
+  QChar *it = ( QChar * )theSQL.unicode();
+  for ( int i = 0; i < theSQL.length(); i++ )
+  {
+    if ( *it == '\"' )
+    {
+      myRetval += "\\\"";
+    }
+    else if ( *it == '\'' )
+    {
+      myRetval += "\\'";
+    }
+    else if ( *it == '\\' )
+    {
+      myRetval += "\\\\";
+    }
+    else if ( *it == '%' )
+    {
+      myRetval += "\\%";
+    }
+    else
+    {
+      myRetval += *it;
+    }
+    it++;
+  }
+  return myRetval;
+}

Modified: trunk/qgis/src/core/qgscoordinatereferencesystem.h
===================================================================
--- trunk/qgis/src/core/qgscoordinatereferencesystem.h	2009-08-13 20:43:26 UTC (rev 11365)
+++ trunk/qgis/src/core/qgscoordinatereferencesystem.h	2009-08-13 23:10:32 UTC (rev 11366)
@@ -387,6 +387,15 @@
     //! Work out the projection units and set the appropriate local variable
     void setMapUnits();
 
+    //! Save the proj4-string as a custom CRS 
+    bool saveAsUserCRS();
+
+    //! Helper for getting number of user CRS already in db
+    long getRecordCount();
+
+    //! Helper for sql-safin strings
+    const QString sqlSafeString( const QString theSQL );
+
     void *mCRS;
 
     bool loadFromDb( QString db, QString field, long id );



More information about the QGIS-commit mailing list