[QGIS Commit] r13044 - in trunk/qgis: python/core src/app src/app/postgres src/core src/providers/postgres src/ui

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed Mar 10 18:58:49 EST 2010


Author: jef
Date: 2010-03-10 18:58:48 -0500 (Wed, 10 Mar 2010)
New Revision: 13044

Modified:
   trunk/qgis/python/core/qgsdatasourceuri.sip
   trunk/qgis/src/app/postgres/qgspgnewconnection.cpp
   trunk/qgis/src/app/postgres/qgspgsourceselect.cpp
   trunk/qgis/src/app/postgres/qgspgsourceselect.h
   trunk/qgis/src/app/qgsmanageconnectionsdialog.cpp
   trunk/qgis/src/core/qgsdatasourceuri.cpp
   trunk/qgis/src/core/qgsdatasourceuri.h
   trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
   trunk/qgis/src/providers/postgres/qgspostgresprovider.h
   trunk/qgis/src/ui/qgspgnewconnectionbase.ui
Log:
apply #2460 (slightly modified).  Thanks Jeremy Palmer.

Modified: trunk/qgis/python/core/qgsdatasourceuri.sip
===================================================================
--- trunk/qgis/python/core/qgsdatasourceuri.sip	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/python/core/qgsdatasourceuri.sip	2010-03-10 23:58:48 UTC (rev 13044)
@@ -60,6 +60,11 @@
   QString table() const;
   QString sql() const;
   QString geometryColumn() const;
+  
+  //! set use Estimated Metadata
+  // added in 1.5
+  void setUseEstimatedMetadata( bool theFlag );
+  bool useEstimatedMetadata() const;
 
   // added in 1.1
   QString host() const;

Modified: trunk/qgis/src/app/postgres/qgspgnewconnection.cpp
===================================================================
--- trunk/qgis/src/app/postgres/qgspgnewconnection.cpp	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/app/postgres/qgspgnewconnection.cpp	2010-03-10 23:58:48 UTC (rev 13044)
@@ -56,17 +56,13 @@
       port = "5432";
     }
     txtPort->setText( port );
-    Qt::CheckState s = Qt::Checked;
-    if ( ! settings.value( key + "/publicOnly", false ).toBool() )
-      s = Qt::Unchecked;
-    cb_publicSchemaOnly->setCheckState( s );
-    s = Qt::Checked;
-    if ( ! settings.value( key + "/geometrycolumnsOnly", false ).toBool() )
-      s = Qt::Unchecked;
-    cb_geometryColumnsOnly->setCheckState( s );
+    cb_publicSchemaOnly->setChecked( settings.value( key + "/publicOnly", false ).toBool() );
+    cb_geometryColumnsOnly->setChecked( settings.value( key + "/geometrycolumnsOnly", false ).toBool() );
     // Ensure that cb_plublicSchemaOnly is set correctly
     on_cb_geometryColumnsOnly_clicked();
 
+    cb_useEstimatedMetadata->setChecked( settings.value( key + "/estimatedMetadata", false ).toBool() );
+
     cbxSSLmode->setCurrentIndex( cbxSSLmode->findData( settings.value( key + "/sslmode", QgsDataSourceURI::SSLprefer ).toInt() ) );
 
     if ( settings.value( key + "/saveUsername" ).toString() == "true" )
@@ -132,6 +128,7 @@
   settings.setValue( baseKey + "/sslmode", cbxSSLmode->itemData( cbxSSLmode->currentIndex() ).toInt() );
   settings.setValue( baseKey + "/saveUsername", chkStoreUsername->isChecked() ? "true" : "false" );
   settings.setValue( baseKey + "/savePassword", chkStorePassword->isChecked() ? "true" : "false" );
+  settings.setValue( baseKey + "/estimatedMetadata", cb_useEstimatedMetadata->isChecked() );
 
   // remove old save setting
   settings.remove( baseKey + "/save" );

Modified: trunk/qgis/src/app/postgres/qgspgsourceselect.cpp
===================================================================
--- trunk/qgis/src/app/postgres/qgspgsourceselect.cpp	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/app/postgres/qgspgsourceselect.cpp	2010-03-10 23:58:48 UTC (rev 13044)
@@ -41,6 +41,10 @@
 #include <pg_config.h>
 #endif
 
+// Note: Because the the geometry type select SQL is also in the qgspostgresprovider
+// code this parameter is duplicated there.
+static const int sGeomTypeSelectLimit = 100;
+
 QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WFlags fl )
     : QDialog( parent, fl ), mColumnTypeThread( NULL ), pd( 0 )
 {
@@ -142,6 +146,7 @@
   settings.remove( key + "/sslmode" );
   settings.remove( key + "/publicOnly" );
   settings.remove( key + "/geometryColumnsOnly" );
+  settings.remove( key + "/estimatedMetadata" );
   settings.remove( key + "/saveUsername" );
   settings.remove( key + "/savePassword" );
   settings.remove( key + "/save" );
@@ -352,6 +357,11 @@
     uri += QString( " key=\"%1\"" ).arg( pkColumnName );
   }
 
+  if ( mUseEstimatedMetadata )
+  {
+    uri += QString( " estimatedmetadata=true" );
+  }
+
   uri += QString( " table=\"%1\".\"%2\" (%3) sql=%4" )
          .arg( schemaName ).arg( tableName )
          .arg( geomColumnName )
@@ -419,7 +429,7 @@
 
   bool searchPublicOnly = settings.value( key + "/publicOnly" ).toBool();
   bool searchGeometryColumnsOnly = settings.value( key + "/geometryColumnsOnly" ).toBool();
-
+  mUseEstimatedMetadata = settings.value( key + "/estimatedMetadata" ).toBool();
   // Need to escape the password to allow for single quotes and backslashes
 
   QgsDebugMsg( "Connection info: " + uri.connectionInfo() );
@@ -562,7 +572,7 @@
   if ( mColumnTypeThread == NULL )
   {
     mColumnTypeThread = new QgsGeomColumnTypeThread();
-    mColumnTypeThread->setConnInfo( m_privConnInfo );
+    mColumnTypeThread->setConnInfo( m_privConnInfo, mUseEstimatedMetadata );
   }
   mColumnTypeThread->addGeometryColumn( schema, table, column );
 }
@@ -794,9 +804,10 @@
 {
 }
 
-void QgsGeomColumnTypeThread::setConnInfo( QString s )
+void QgsGeomColumnTypeThread::setConnInfo( QString conninfo, bool useEstimatedMetadata )
 {
-  mConnInfo = s;
+  mConnInfo = conninfo;
+  mUseEstimatedMetadata = useEstimatedMetadata;
 }
 
 void QgsGeomColumnTypeThread::addGeometryColumn( QString schema, QString table, QString column )
@@ -828,8 +839,19 @@
                                " when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
                                " when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
                                " end "
-                               "from "
-                               "\"%2\".\"%3\"" ).arg( "\"" + columns[i] + "\"" ).arg( schemas[i] ).arg( tables[i] );
+                               "from " ).arg( "\"" + columns[i] + "\"" );
+      if ( mUseEstimatedMetadata )
+      {
+        query += QString( "(select %1 from %2 where %1 is not null limit %3) as t" )
+                 .arg( "\"" + columns[i] + "\"" )
+                 .arg( "\"" + schemas[i] + "\".\"" + tables[i] + "\"" )
+                 .arg( sGeomTypeSelectLimit );
+      }
+      else
+      {
+        query += "\"" + schemas[i] + "\".\"" + tables[i] + "\"";
+      }
+
       PGresult* gresult = PQexec( pd, query.toUtf8() );
       QString type;
       if ( PQresultStatus( gresult ) == PGRES_TUPLES_OK )

Modified: trunk/qgis/src/app/postgres/qgspgsourceselect.h
===================================================================
--- trunk/qgis/src/app/postgres/qgspgsourceselect.h	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/app/postgres/qgspgsourceselect.h	2010-03-10 23:58:48 UTC (rev 13044)
@@ -154,11 +154,6 @@
     typedef QPair<QString, QString> geomPair;
     typedef QList<geomPair> geomCol;
 
-    bool getGeometryColumnInfo( PGconn *pd,
-                                geomCol& details,
-                                bool searchGeometryColumnsOnly,
-                                bool searchPublicOnly );
-
     /**Inserts information about the spatial tables into mTableModel*/
     bool getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly );
 
@@ -181,6 +176,7 @@
     QString m_connInfo;
     QString m_privConnInfo;
     QStringList m_selectedTables;
+    bool mUseEstimatedMetadata;
     // Storage for the range of layer type icons
     QMap<QString, QPair<QString, QIcon> > mLayerIcons;
     PGconn *pd;
@@ -205,7 +201,7 @@
     Q_OBJECT
   public:
 
-    void setConnInfo( QString s );
+    void setConnInfo( QString s, bool useEstimatedMetadata );
     void addGeometryColumn( QString schema, QString table, QString column );
 
     // These functions get the layer types and pass that information out
@@ -226,6 +222,7 @@
 
   private:
     QString mConnInfo;
+    bool mUseEstimatedMetadata;
     bool mStopped;
     std::vector<QString> schemas, tables, columns;
 };

Modified: trunk/qgis/src/app/qgsmanageconnectionsdialog.cpp
===================================================================
--- trunk/qgis/src/app/qgsmanageconnectionsdialog.cpp	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/app/qgsmanageconnectionsdialog.cpp	2010-03-10 23:58:48 UTC (rev 13044)
@@ -291,6 +291,7 @@
     el.setAttribute( "port", settings.value( path + "/port", "" ).toString() );
     el.setAttribute( "database", settings.value( path + "/database", "" ).toString() );
     el.setAttribute( "sslmode", settings.value( path + "/sslmode", "1" ).toString() );
+    el.setAttribute( "estimatedMetadata", settings.value( path + "/estimatedMetadata", "0" ).toString() );
 
     el.setAttribute( "saveUsername", settings.value( path + "/saveUsername", "false" ).toString() );
 
@@ -415,9 +416,10 @@
     settings.setValue( "/port", child.attribute( "port" ) );
     settings.setValue( "/database", child.attribute( "database" ) );
     settings.setValue( "/sslmode", child.attribute( "sslmode" ) );
-		settings.setValue( "/saveUsername", child.attribute( "saveUsername" ) );
+    settings.setValue( "/estimatedMetadata", child.attribute( "estimatedMetadata" ) );
+    settings.setValue( "/saveUsername", child.attribute( "saveUsername" ) );
     settings.setValue( "/username", child.attribute( "username" ) );
-		settings.setValue( "/savePassword", child.attribute( "savePassword" ) );
+    settings.setValue( "/savePassword", child.attribute( "savePassword" ) );
     settings.setValue( "/password", child.attribute( "password" ) );
     settings.endGroup();
 

Modified: trunk/qgis/src/core/qgsdatasourceuri.cpp
===================================================================
--- trunk/qgis/src/core/qgsdatasourceuri.cpp	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/core/qgsdatasourceuri.cpp	2010-03-10 23:58:48 UTC (rev 13044)
@@ -23,12 +23,12 @@
 #include <QStringList>
 #include <QRegExp>
 
-QgsDataSourceURI::QgsDataSourceURI() : mSSLmode( SSLprefer ), mKeyColumn( "" )
+QgsDataSourceURI::QgsDataSourceURI() : mSSLmode( SSLprefer ), mKeyColumn( "" ), mUseEstimatedMetadata( false )
 {
   // do nothing
 }
 
-QgsDataSourceURI::QgsDataSourceURI( QString uri ) : mSSLmode( SSLprefer ), mKeyColumn( "" )
+QgsDataSourceURI::QgsDataSourceURI( QString uri ) : mSSLmode( SSLprefer ), mKeyColumn( "" ), mUseEstimatedMetadata( false )
 {
   int i = 0;
   while ( i < uri.length() )
@@ -108,6 +108,10 @@
       {
         mKeyColumn = pval;
       }
+      else if ( pname == "estimatedmetadata" )
+      {
+        mUseEstimatedMetadata = pval == "true";
+      }
       else if ( pname == "service" )
       {
         QgsDebugMsg( "service keyword ignored" );
@@ -281,6 +285,17 @@
   mKeyColumn = column;
 }
 
+
+void QgsDataSourceURI::setUseEstimatedMetadata( bool theFlag )
+{
+  mUseEstimatedMetadata = theFlag;
+}
+
+bool QgsDataSourceURI::useEstimatedMetadata() const
+{
+  return mUseEstimatedMetadata;
+}
+
 void QgsDataSourceURI::setSql( QString sql )
 {
   mSql = sql;
@@ -419,6 +434,11 @@
     theUri += QString( " key='%1'" ).arg( escape( mKeyColumn ) );
   }
 
+  if ( mUseEstimatedMetadata )
+  {
+    theUri += QString( " estimatedmetadata=true" );
+  }
+
   theUri += QString( " table=%1 (%2) sql=%3" )
             .arg( quotedTablename() )
             .arg( mGeometryColumn )

Modified: trunk/qgis/src/core/qgsdatasourceuri.h
===================================================================
--- trunk/qgis/src/core/qgsdatasourceuri.h	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/core/qgsdatasourceuri.h	2010-03-10 23:58:48 UTC (rev 13044)
@@ -85,6 +85,11 @@
     QString sql() const;
     QString geometryColumn() const;
 
+    //! set use Estimated Metadata
+    // added in 1.5
+    void setUseEstimatedMetadata( bool theFlag );
+    bool useEstimatedMetadata() const;
+
     void clearSchema();
     void setSql( QString sql );
 
@@ -128,6 +133,8 @@
     enum SSLmode mSSLmode;
     //! key column
     QString mKeyColumn;
+    //Use estimated metadata flag
+    bool mUseEstimatedMetadata;
 };
 
 #endif //QGSDATASOURCEURI_H

Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp	2010-03-10 23:58:48 UTC (rev 13044)
@@ -49,17 +49,23 @@
 const QString POSTGRES_KEY = "postgres";
 const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
 
+// Note: Because the the geometry type select SQL is also in the qgspgsourceselect
+// code this parameter is duplicated there.
+static const int sGeomTypeSelectLimit = 100;
+
 QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::Conn::connectionsRO;
 QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::Conn::connectionsRW;
 QMap<QString, QString> QgsPostgresProvider::Conn::passwordCache;
 int QgsPostgresProvider::providerIds = 0;
 
 QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
-    : QgsVectorDataProvider( uri ),
-    mFetching( false ),
-    geomType( QGis::WKBUnknown ),
-    mFeatureQueueSize( 200 ),
-    mPrimaryKeyDefault( QString::null )
+    : QgsVectorDataProvider( uri )
+    , mFetching( false )
+    , mIsDbPrimaryKey( false )
+    , geomType( QGis::WKBUnknown )
+    , mFeatureQueueSize( 200 )
+    , mUseEstimatedMetadata( false )
+    , mPrimaryKeyDefault( QString::null )
 {
   // assume this is a valid layer until we determine otherwise
   valid = true;
@@ -77,6 +83,7 @@
   geometryColumn = mUri.geometryColumn();
   sqlWhereClause = mUri.sql();
   primaryKey = mUri.keyColumn();
+  mUseEstimatedMetadata = mUri.useEstimatedMetadata();
 
   // Keep a schema qualified table name for convenience later on.
   mSchemaTableName = mUri.quotedTablename();
@@ -1029,6 +1036,10 @@
 
 QString QgsPostgresProvider::getPrimaryKey()
 {
+  // If we find a database primary key we will set this to true.  If it is a column which is serving
+  // as a primary key, then this will remain false.
+  mIsDbPrimaryKey = false;
+
   // check to see if there is an unique index on the relation, which
   // can be used as a key into the table. Primary keys are always
   // unique indices, so we catch them as well.
@@ -1079,6 +1090,7 @@
         // primary key to the table)
         primaryKey = "oid";
         primaryKeyType = "int4";
+        mIsDbPrimaryKey = true;
       }
       else
       {
@@ -1102,6 +1114,7 @@
               // fallback to ctid
               primaryKey = "ctid";
               primaryKeyType = "tid";
+              mIsDbPrimaryKey = true;
             }
           }
         }
@@ -1188,7 +1201,10 @@
             log.append( tr( "The unique index on column '%1' is unsuitable because Qgis does not currently "
                             "support non-int4 type columns as a key into the table.\n" ).arg( columnName ) );
           else
+          {
+            mIsDbPrimaryKey = true;
             suitableKeyColumns.push_back( std::make_pair( columnName, columnType ) );
+          }
         }
         else
         {
@@ -2647,7 +2663,7 @@
 
   sqlWhereClause = theSQL;
 
-  if ( !uniqueData( mSchemaName, mTableName, primaryKey ) )
+  if ( !mIsDbPrimaryKey && !uniqueData( mSchemaName, mTableName, primaryKey ) )
   {
     sqlWhereClause = prevWhere;
     return false;
@@ -2672,19 +2688,22 @@
 
   // First get an approximate count; then delegate to
   // a thread the task of getting the full count.
+  QString sql;
 
-#ifdef POSTGRESQL_THREADS
-  QString sql = QString( "select reltuples from pg_catalog.pg_class where relname=%1" ).arg( quotedValue( tableName ) );
-  QgsDebugMsg( "Running SQL: " + sql );
-#else
-  QString sql = QString( "select count(*) from %1" ).arg( mSchemaTableName );
-
-  if ( sqlWhereClause.length() > 0 )
+  if ( mUseEstimatedMetadata )
   {
-    sql += " where " + sqlWhereClause;
+    sql = QString( "select reltuples::int from pg_catalog.pg_class where oid=regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
   }
-#endif
+  else
+  {
+    sql = QString( "select count(*) from %1" ).arg( mSchemaTableName );
 
+    if ( sqlWhereClause.length() > 0 )
+    {
+      sql += " where " + sqlWhereClause;
+    }
+  }
+
   Result result = connectionRO->PQexec( sql );
 
   QgsDebugMsg( "Approximate Number of features as text: " +
@@ -2746,7 +2765,7 @@
   QString ext;
 
   // get the extents
-  if ( sqlWhereClause.isEmpty() && !connectionRO->hasNoExtentEstimate() )
+  if (( mUseEstimatedMetadata || sqlWhereClause.isEmpty() ) && !connectionRO->hasNoExtentEstimate() )
   {
     result = connectionRO->PQexec( QString( "select estimated_extent(%1,%2,%3)" )
                                    .arg( quotedValue( mSchemaName ) )
@@ -2955,7 +2974,19 @@
                      " when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
                      " when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
                      " end "
-                     "from %2" ).arg( quotedIdentifier( geometryColumn ) ).arg( mSchemaTableName );
+                     "from " ).arg( quotedIdentifier( geometryColumn ) );
+      if ( mUseEstimatedMetadata )
+      {
+        sql += QString( "(select %1 from %2 where %1 is not null limit %3) as t" )
+               .arg( quotedIdentifier( geometryColumn ) )
+               .arg( mSchemaTableName )
+               .arg( sGeomTypeSelectLimit );
+      }
+      else
+      {
+        sql += mSchemaTableName;
+      }
+
       if ( mUri.sql() != "" )
         sql += " where " + mUri.sql();
 

Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h	2010-03-10 23:58:48 UTC (rev 13044)
@@ -372,7 +372,6 @@
     //! Data source URI struct for this layer
     QgsDataSourceURI mUri;
 
-
     //! Child thread for calculating extents.
     QgsPostgresExtentThread mExtentThread;
 
@@ -409,6 +408,10 @@
      */
     QString primaryKey;
     /**
+     * Primary key column is "real" primary key
+     */
+    bool mIsDbPrimaryKey;
+    /**
      * Data type for the primary key
      */
     QString primaryKeyType;
@@ -461,10 +464,13 @@
     bool deduceEndian();
     bool getGeometryDetails();
 
+    /* Use estimated metadata. Uses fast table counts, geometry type and extent determination */
+    bool mUseEstimatedMetadata;
+
     // Produces a QMessageBox with the given title and text. Doesn't
     // return until the user has dismissed the dialog box.
-    static void showMessageBox( const QString& title, const QString& text );
-    static void showMessageBox( const QString& title, const QStringList& text );
+    static void showMessageBox( const QString& title, const QString &text );
+    static void showMessageBox( const QString& title, const QStringList &text );
 
     // A simple class to store the rows of the sql executed in the
     // findColumns() function.

Modified: trunk/qgis/src/ui/qgspgnewconnectionbase.ui
===================================================================
--- trunk/qgis/src/ui/qgspgnewconnectionbase.ui	2010-03-10 22:40:21 UTC (rev 13043)
+++ trunk/qgis/src/ui/qgspgnewconnectionbase.ui	2010-03-10 23:58:48 UTC (rev 13044)
@@ -228,6 +228,27 @@
         </item>
        </layout>
       </item>
+      <item row="4" column="0">
+       <widget class="QCheckBox" name="cb_useEstimatedMetadata">
+        <property name="toolTip">
+         <string>Use estimated table statistics for the layer metadata.</string>
+        </property>
+        <property name="whatsThis">
+         <string>&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;When the layer is setup various metadata is required for the PostGIS table. This includes information such as the table row count, geometry type and spatial extents of the data in the geometry column. If the table contains a large number of rows determining this metadata is time consuming.&lt;/p&gt;
+&lt;p&gt;By activating this option the following fast table metadata operations are done:&lt;/p&gt;
+&lt;p&gt;1) Row count is determined from table statistics obtained from running the PostgreSQL table analyse function.&lt;/p&gt;
+&lt;p&gt;2) Table extents are always determined with the estimated_extent PostGIS function even if a layer filter is applied.&lt;/p&gt;
+&lt;p&gt;3) If the table geometry type is unknown and is not exclusively taken from the geometry_columns table, then it is determined from the first 100 non-null geometry rows in the table.&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;</string>
+        </property>
+        <property name="text">
+         <string>Use estimated table metadata</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
@@ -246,10 +267,15 @@
   <tabstop>txtHost</tabstop>
   <tabstop>txtDatabase</tabstop>
   <tabstop>txtPort</tabstop>
+  <tabstop>cbxSSLmode</tabstop>
   <tabstop>txtUsername</tabstop>
   <tabstop>txtPassword</tabstop>
+  <tabstop>chkStoreUsername</tabstop>
+  <tabstop>chkStorePassword</tabstop>
   <tabstop>cb_geometryColumnsOnly</tabstop>
   <tabstop>cb_publicSchemaOnly</tabstop>
+  <tabstop>cb_useEstimatedMetadata</tabstop>
+  <tabstop>btnConnect</tabstop>
   <tabstop>buttonBox</tabstop>
  </tabstops>
  <resources/>



More information about the QGIS-commit mailing list