1
/***************************************************************************
2
qgsgrassprovider.cpp - Data provider for GRASS format
5
copyright : (C) 2004 by Gary E.Sherman, Radim Blazek
6
email : sherman@mrcc.com, blazek@itc.it
7
***************************************************************************/
8
/***************************************************************************
10
* This program is free software; you can redistribute it and/or modify *
11
* it under the terms of the GNU General Public License as published by *
12
* the Free Software Foundation; either version 2 of the License, or *
13
* (at your option) any later version. *
15
***************************************************************************/
25
#include <qdatetime.h>
26
#include <qmessagebox.h>
28
#include "../../src/qgis.h"
29
#include "../../src/qgsdataprovider.h"
30
#include "../../src/qgsfeature.h"
31
#include "../../src/qgsfield.h"
32
#include "../../src/qgsrect.h"
33
#include "../../src/qgsfeatureattribute.h"
36
#include <gprojects.h>
43
#include "qgsgrassprovider.h"
45
std::vector<GLAYER> QgsGrassProvider::mLayers;
46
std::vector<GMAP> QgsGrassProvider::mMaps;
48
QgsGrassProvider::QgsGrassProvider(QString uri):mDataSourceUri(uri)
51
std::cerr << "QgsGrassProvider URI: " << uri << std::endl;
60
QDir dir ( uri ); // it is not a directory in fact
61
uri = dir.path(); // no dupl '/'
63
mLayer = dir.dirName();
64
uri = uri.left( dir.path().findRev('/') );
66
mMapName = dir.dirName();
68
mMapset = dir.dirName();
70
mLocation = dir.dirName();
72
mGisdbase = dir.path();
75
std::cerr << "gisdbase: " << mGisdbase << std::endl;
76
std::cerr << "location: " << mLocation << std::endl;
77
std::cerr << "mapset: " << mMapset << std::endl;
78
std::cerr << "mapName: " << mMapName << std::endl;
79
std::cerr << "layer: " << mLayer << std::endl;
82
/* Parse Layer, supported layers <field>_point, <field>_line, <field>_area
83
* Layer is opened even if it is empty (has no features)
86
if ( mLayer.compare("boundary") == 0 ) { // currently not used
87
mLayerType = BOUNDARY;
88
mGrassType = GV_BOUNDARY;
89
} else if ( mLayer.compare("centroid") == 0 ) { // currently not used
90
mLayerType = CENTROID;
91
mGrassType = GV_CENTROID;
94
int pos = mLayer.find('_');
97
std::cerr << "Invalid layer name, no underscore found: " << mLayer << std::endl;
101
mLayerField = mLayer.left(pos).toInt();
103
QString ts = mLayer.right( mLayer.length() - pos - 1 );
104
if ( ts.compare("point") == 0 ) {
106
mGrassType = GV_POINT; // ?! centroids may be points
107
} else if ( ts.compare("line") == 0 ) {
109
mGrassType = GV_LINE | GV_BOUNDARY;
110
} else if ( ts.compare("polygon") == 0 ) {
111
mLayerType = POLYGON;
112
mGrassType = GV_AREA;
114
std::cerr << "Invalid layer name, wrong type: " << ts << std::endl;
119
std::cerr << "mLayerField: " << mLayerField << std::endl;
120
std::cerr << "mLayerType: " << mLayerType << std::endl;
123
if ( mLayerType == BOUNDARY || mLayerType == CENTROID ) {
124
std::cerr << "Layer type not supported." << std::endl;
129
switch ( mLayerType ) {
132
mQgisType = QGis::WKBPoint;
136
mQgisType = QGis::WKBLineString;
139
mQgisType = QGis::WKBPolygon;
143
mLayerId = openLayer(mGisdbase, mLocation, mMapset, mMapName, mLayerField);
144
if ( mLayerId < 0 ) {
145
std::cerr << "Cannot open GRASS layer:" << uri << std::endl;
149
std::cerr << "mLayerId: " << mLayerId << std::endl;
152
mMap = layerMap(mLayerId);
154
// Getting the total number of features in the layer
156
mCidxFieldIndex = -1;
157
if ( mLayerField >= 0 ) {
158
mCidxFieldIndex = Vect_cidx_get_field_index ( mMap, mLayerField);
159
if ( mCidxFieldIndex >= 0 ) {
160
mNumberFeatures = Vect_cidx_get_type_count ( mMap, mLayerField, mGrassType );
161
mCidxFieldNumCats = Vect_cidx_get_num_cats_by_index ( mMap, mCidxFieldIndex );
164
// TODO nofield layers
166
mCidxFieldNumCats = 0;
171
std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
172
<< " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
176
// Create selection array
177
mSelectionSize = allocateSelection ( mMap, &mSelection );
178
resetSelection(1); // TODO ? - where what reset
180
mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
183
mPoints = Vect_new_line_struct ();
184
mCats = Vect_new_cats_struct ();
185
mList = Vect_new_list ();
190
std::cerr << "New GRASS layer opened, time (ms): " << time.elapsed() << std::endl;
194
void QgsGrassProvider::update ( void )
197
std::cerr << "*** QgsGrassProvider::update ***" << std::endl;
201
// TODO check if reopened map is valid
203
// Getting the total number of features in the layer
204
// It may happen that the field disappeares from the map (deleted features, new map without that field)
206
mCidxFieldIndex = -1;
207
if ( mLayerField >= 0 ) {
208
mCidxFieldIndex = Vect_cidx_get_field_index ( mMap, mLayerField);
209
if ( mCidxFieldIndex >= 0 ) {
210
mNumberFeatures = Vect_cidx_get_type_count ( mMap, mLayerField, mGrassType );
211
mCidxFieldNumCats = Vect_cidx_get_num_cats_by_index ( mMap, mCidxFieldIndex );
214
// TODO nofield layers
216
mCidxFieldNumCats = 0;
221
std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
222
<< " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
225
// Create selection array
226
if ( mSelection ) free ( mSelection );
227
mSelectionSize = allocateSelection ( mMap, &mSelection );
230
mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
235
int QgsGrassProvider::allocateSelection( struct Map_info *map, char **selection )
239
std::cerr << "QgsGrassProvider::allocateSellection" << std::endl;
242
int nlines = Vect_get_num_lines ( map );
243
int nareas = Vect_get_num_areas ( map );
245
if ( nlines > nareas ) {
251
std::cerr << "nlines = " << nlines << " nareas = " << nareas << " size = " << size << std::endl;
254
*selection = (char *) malloc ( size );
259
QgsGrassProvider::~QgsGrassProvider()
262
std::cerr << "QgsGrassProvider::~QgsGrassProvider()" << std::endl;
264
closeLayer ( mLayerId );
268
* Get the first feature resutling from a select operation
271
QgsFeature *QgsGrassProvider::getFirstFeature(bool fetchAttributes)
274
std::cout << "QgsGrassProvider::getFirstFeature()" << std::endl;
280
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
284
return ( getNextFeature(fetchAttributes) );
288
* Get the next feature resulting from a select operation
289
* @return false if there are no features in the selection set
291
bool QgsGrassProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes)
294
std::cout << "QgsGrassProvider::getNextFeature()" << std::endl;
300
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
302
// TODO once clear how to do that
307
* Get the next feature resulting from a select operation
308
* Return 0 if there are no features in the selection set
311
QgsFeature *QgsGrassProvider::getNextFeature(bool fetchAttributes)
314
std::cout << "QgsGrassProvider::getNextFeature() mNextCidx = " << mNextCidx
315
<< " fetchAttributes = " << fetchAttributes << std::endl;
321
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
323
std::list<int> attlist;
325
if ( fetchAttributes ) {
326
int fc = fieldCount();
327
for ( int i = 0; i < fc; i++ ) {
328
attlist.push_back(i);
332
return ( getNextFeature(attlist) );
335
QgsFeature* QgsGrassProvider::getNextFeature(std::list<int> const& attlist)
337
int cat, type, id, idx;
342
std::cout << "QgsGrassProvider::getNextFeature( attlist )" << std::endl;
348
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
350
// Get next line/area id
352
while ( mNextCidx < mCidxFieldNumCats ) {
353
Vect_cidx_get_cat_by_index ( mMap, mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
354
// Warning: selection array is only of type line/area of current layer -> check type first
356
if ( !(type & mGrassType) ) continue;
357
if ( !mSelection[id] ) continue;
361
if ( !found ) return 0; // No more features
363
std::cout << "cat = " << cat << " type = " << type << " id = " << id << std::endl;
366
QgsFeature *f = new QgsFeature(id);
368
// TODO int may be 64 bits (memcpy)
369
if ( type & (GV_POINTS | GV_LINES) ) { /* points or lines */
370
Vect_read_line ( mMap, mPoints, mCats, id);
371
int npoints = mPoints->n_points;
373
if ( type & GV_POINTS ) {
374
wkbsize = 1 + 4 + 2*8;
376
wkbsize = 1+4+4+npoints*2*8;
378
wkb = new unsigned char[wkbsize];
379
unsigned char *wkbp = wkb;
380
wkbp[0] = (unsigned char) endian();
384
memcpy (wkbp, &mQgisType, 4);
387
/* number of points */
388
if ( type & GV_LINES ) {
389
memcpy (wkbp, &npoints, 4);
393
for ( int i = 0; i < npoints; i++ ) {
394
memcpy (wkbp, &(mPoints->x[i]), 8);
395
memcpy (wkbp+8, &(mPoints->y[i]), 8);
399
Vect_get_area_points ( mMap, id, mPoints );
400
int npoints = mPoints->n_points;
402
wkbsize = 1+4+4+4+npoints*2*8; // size without islands
403
wkb = new unsigned char[wkbsize];
404
wkb[0] = (unsigned char) endian();
408
memcpy ( wkb+offset, &mQgisType, 4);
411
/* Number of rings */
412
int nisles = Vect_get_area_num_isles ( mMap, id );
413
int nrings = 1 + nisles;
414
memcpy (wkb+offset, &nrings, 4);
418
memcpy (wkb+offset, &npoints, 4);
420
for ( int i = 0; i < npoints; i++ ) {
421
memcpy (wkb+offset, &(mPoints->x[i]), 8);
422
memcpy (wkb+offset+8, &(mPoints->y[i]), 8);
427
for ( int i = 0; i < nisles; i++ ) {
428
Vect_get_isle_points ( mMap, Vect_get_area_isle (mMap, id, i), mPoints );
429
npoints = mPoints->n_points;
432
wkbsize += 4+npoints*2*8;
433
wkb = (unsigned char *) realloc (wkb, wkbsize);
435
memcpy (wkb+offset, &npoints, 4);
437
for ( int i = 0; i < npoints; i++ ) {
438
memcpy (wkb+offset, &(mPoints->x[i]), 8);
439
memcpy (wkb+offset+8, &(mPoints->y[i]), 8);
445
f->setGeometry(wkb, wkbsize);
447
setFeatureAttributes( mLayerId, cat, f, attlist );
454
void QgsGrassProvider::resetSelection( bool sel)
457
std::cout << "QgsGrassProvider::resetSelection()" << std::endl;
459
memset ( mSelection, (int) sel, mSelectionSize );
464
* Select features based on a bounding rectangle. Features can be retrieved
465
* with calls to getFirstFeature and getNextFeature.
466
* @param mbr QgsRect containing the extent to use in selecting features
468
void QgsGrassProvider::select(QgsRect *rect, bool useIntersect)
471
std::cout << "QgsGrassProvider::select() useIntersect = " << useIntersect << std::endl;
477
// check if outdated and update if necessary
478
int mapId = mLayers[mLayerId].mapId;
479
if ( mapOutdated(mapId) ) {
482
if ( mMapVersion < mMaps[mapId].version ) {
485
if ( attributesOutdated(mapId) ) {
486
loadAttributes (mLayers[mLayerId]);
491
if ( !useIntersect ) { // select by bounding boxes only
493
box.N = rect->yMax(); box.S = rect->yMin();
494
box.E = rect->xMax(); box.W = rect->xMin();
495
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;
496
if ( mLayerType == POINT || mLayerType == CENTROID || mLayerType == LINE || mLayerType == BOUNDARY ) {
497
Vect_select_lines_by_box(mMap, &box, mGrassType, mList);
498
} else if ( mLayerType == POLYGON ) {
499
Vect_select_areas_by_box(mMap, &box, mList);
502
} else { // check intersection
503
struct line_pnts *Polygon;
505
Polygon = Vect_new_line_struct();
507
Vect_append_point( Polygon, rect->xMin(), rect->yMin(), 0);
508
Vect_append_point( Polygon, rect->xMax(), rect->yMin(), 0);
509
Vect_append_point( Polygon, rect->xMax(), rect->yMax(), 0);
510
Vect_append_point( Polygon, rect->xMin(), rect->yMax(), 0);
511
Vect_append_point( Polygon, rect->xMin(), rect->yMin(), 0);
513
if ( mLayerType == POINT || mLayerType == CENTROID || mLayerType == LINE || mLayerType == BOUNDARY ) {
514
Vect_select_lines_by_polygon ( mMap, Polygon, 0, NULL, mGrassType, mList);
515
} else if ( mLayerType == POLYGON ) {
516
Vect_select_areas_by_polygon ( mMap, Polygon, 0, NULL, mList);
519
Vect_destroy_line_struct (Polygon);
521
for ( int i = 0; i < mList->n_values; i++ ) {
522
if ( mList->value[i] <= mSelectionSize ) {
523
mSelection[mList->value[i]] = 1;
525
std::cerr << "Selected element out of range" << std::endl;
530
std::cout << mList->n_values << " features selected" << std::endl;
535
* Set the data source specification. This may be a path or database
537
* @uri data source specification
539
void QgsGrassProvider::setDataSourceUri(QString uri)
541
mDataSourceUri = uri;
545
* Get the data source specification. This may be a path or database
547
* @return data source specification
549
QString QgsGrassProvider::getDataSourceUri()
551
return mDataSourceUri;
555
* Identify features within the search radius specified by rect
556
* @param rect Bounding rectangle of search radius
557
* @return std::vector containing QgsFeature objects that intersect rect
559
std::vector<QgsFeature>& QgsGrassProvider::identify(QgsRect * rect)
562
std::cout << "QgsGrassProvider::identify()" << std::endl;
565
// TODO: does not return vector of features! Should it?
572
QgsRect *QgsGrassProvider::extent()
575
Vect_get_map_box ( mMap, &box );
577
return new QgsRect( box.W, box.S, box.E, box.N);
581
* Return the feature type
583
int QgsGrassProvider::geometryType() const
588
* Return the feature type
590
long QgsGrassProvider::featureCount() const
592
return mNumberFeatures;
596
* Return the number of fields
598
int QgsGrassProvider::fieldCount() const
601
std::cerr << "QgsGrassProvider::fieldCount() return:" << mLayers[mLayerId].fields.size() << std::endl;
603
return mLayers[mLayerId].fields.size();
609
std::vector<QgsField> const & QgsGrassProvider::fields() const
611
return mLayers[mLayerId].fields;
614
void QgsGrassProvider::reset()
619
int mapId = mLayers[mLayerId].mapId;
620
if ( mapOutdated(mapId) ) {
623
if ( mMapVersion < mMaps[mapId].version ) {
626
if ( attributesOutdated(mapId) ) {
627
loadAttributes (mLayers[mLayerId]);
634
QString QgsGrassProvider::minValue(int position)
636
if ( position >= fieldCount() ) {
637
std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::minValue()"
640
return QString::number( mLayers[mLayerId].minmax[position][0], 'f', 2 );
644
QString QgsGrassProvider::maxValue(int position)
646
if ( position >= fieldCount() ) {
647
std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::maxValue()"
650
return QString::number( mLayers[mLayerId].minmax[position][1], 'f', 2 );
653
bool QgsGrassProvider::isValid(){
655
QString validString = mValid?"true":"false";
656
std::cerr << "QgsGrassProvider::isValid() returned: " << validString << std::endl;
661
// ------------------------------------------------------------------------------------------------------
662
// Compare categories in GATT
663
static int cmpAtt ( const void *a, const void *b ) {
664
GATT *p1 = (GATT *) a;
665
GATT *p2 = (GATT *) b;
666
return (p1->cat - p2->cat);
669
/* returns layerId or -1 on error */
670
int QgsGrassProvider::openLayer(QString gisdbase, QString location, QString mapset, QString mapName, int field)
673
std::cerr << "QgsGrassProvider::openLayer()" << std::endl;
674
std::cerr << "gisdbase: " << gisdbase << std::endl;
675
std::cerr << "location: " << location << std::endl;
676
std::cerr << "mapset: " << mapset << std::endl;
677
std::cerr << "mapName: " << mapName << std::endl;
678
std::cerr << "field: " << field << std::endl;
681
// Check if this layer is already opened
683
for ( int i = 0; i < mLayers.size(); i++) {
684
if ( !(mLayers[i].valid) ) continue;
686
GMAP *mp = &(mMaps[mLayers[i].mapId]);
688
if ( mp->gisdbase == gisdbase && mp->location == location &&
689
mp->mapset == mapset && mp->mapName == mapName && mLayers[i].field == field )
691
// the layer already exists, return layer id
693
std::cerr << "The layer is already opened with ID = " << i << std::endl;
700
// Create a new layer
707
layer.mapId = openMap ( gisdbase, location, mapset, mapName );
708
if ( layer.mapId < 0 ) {
709
std::cerr << "Cannot open vector map" << std::endl;
713
std::cerr << "layer.mapId = " << layer.mapId << std::endl;
715
layer.map = mMaps[layer.mapId].map;
717
layer.attributes = 0; // because loadLayerSourcesFromMap will release old
718
loadLayerSourcesFromMap ( layer );
722
// Add new layer to layers
723
mLayers.push_back(layer);
726
std::cerr << "New layer successfully opened" << layer.nAttributes << std::endl;
729
return mLayers.size() - 1;
732
void QgsGrassProvider::loadLayerSourcesFromMap ( GLAYER &layer )
735
std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
739
layer.fields.clear();
740
if ( layer.attributes ) {
741
for ( int i = 0; i < layer.nAttributes; i ++ ) {
742
for ( int j = 0; j < layer.nColumns; j ++ ) {
743
if ( layer.attributes[i].values[j] )
744
free ( layer.attributes[i].values[j] );
746
free ( layer.attributes[i].values );
748
free ( layer.attributes );
750
loadAttributes ( layer );
753
void QgsGrassProvider::loadAttributes ( GLAYER &layer )
756
std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
760
layer.fieldInfo = Vect_get_field( layer.map, layer.field); // should work also with field = 0
764
layer.nAttributes = 0;
765
layer.attributes = 0;
766
layer.fields.clear();
767
layer.keyColumn = -1;
768
if ( layer.fieldInfo == NULL ) {
770
std::cerr << "No field info -> no attribute table" << std::endl;
774
std::cerr << "Field info found -> open database" << std::endl;
776
dbDriver *databaseDriver = db_start_driver_open_database ( layer.fieldInfo->driver,
777
layer.fieldInfo->database );
779
if ( databaseDriver == NULL ) {
780
std::cerr << "Cannot open database " << layer.fieldInfo->database << " by driver "
781
<< layer.fieldInfo->driver << std::endl;
784
std::cerr << "Database opened -> open select cursor" << std::endl;
787
db_init_string (&dbstr);
788
db_set_string (&dbstr, "select * from ");
789
db_append_string (&dbstr, layer.fieldInfo->table);
792
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
794
dbCursor databaseCursor;
795
if ( db_open_select_cursor(databaseDriver, &dbstr, &databaseCursor, DB_SCROLL) != DB_OK ){
797
db_close_database_shutdown_driver ( databaseDriver );
798
QMessageBox::warning( 0, "Warning", "Cannot select attributes from table '" +
799
QString(layer.fieldInfo->table) + "'" );
801
int nRecords = db_get_num_rows ( &databaseCursor );
803
std::cerr << "Number of records: " << nRecords << std::endl;
806
dbTable *databaseTable = db_get_cursor_table (&databaseCursor);
807
layer.nColumns = db_get_table_number_of_columns(databaseTable);
809
layer.minmax = new double[layer.nColumns][2];
811
// Read columns' description
812
for (int i = 0; i < layer.nColumns; i++) {
813
layer.minmax[i][0] = DBL_MAX;
814
layer.minmax[i][1] = -DBL_MAX;
816
dbColumn *column = db_get_table_column (databaseTable, i);
818
int ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) );
820
std::cerr << "column = " << db_get_column_name(column)
821
<< " ctype = " << ctype << std::endl;
827
ctypeStr = "integer";
829
case DB_C_TYPE_DOUBLE:
832
case DB_C_TYPE_STRING:
835
case DB_C_TYPE_DATETIME:
836
ctypeStr = "datetime";
839
layer.fields.push_back ( QgsField( db_get_column_name(column), ctypeStr,
840
db_get_column_length(column), db_get_column_precision(column) ) );
842
if ( G_strcasecmp ( db_get_column_name(column), layer.fieldInfo->key) == 0 ) {
847
if ( layer.keyColumn < 0 ) {
848
layer.fields.clear();
851
QMessageBox::warning( 0, "Warning", "Key column '" + QString(layer.fieldInfo->key) +
852
"' not found in the table '" + QString(layer.fieldInfo->table) + "'" );
854
// Read attributes to the memory
855
layer.attributes = (GATT *) malloc ( nRecords * sizeof(GATT) );
859
if ( db_fetch (&databaseCursor, DB_NEXT, &more) != DB_OK ) {
860
std::cout << "Cannot fetch DB record" << std::endl;
863
if ( !more ) break; // no more records
866
dbColumn *column = db_get_table_column (databaseTable, layer.keyColumn);
867
dbValue *value = db_get_column_value(column);
869
if ( db_test_value_isnull(value) ) continue;
870
layer.attributes[layer.nAttributes].cat = db_get_value_int (value);
871
if ( layer.attributes[layer.nAttributes].cat < 0 ) continue;
873
layer.attributes[layer.nAttributes].values = (char **) malloc ( layer.nColumns * sizeof(char*) );
875
for (int i = 0; i < layer.nColumns; i++) {
876
column = db_get_table_column (databaseTable, i);
877
int sqltype = db_get_column_sqltype(column);
878
int ctype = db_sqltype_to_Ctype ( sqltype );
879
value = db_get_column_value(column);
880
db_convert_value_to_string ( value, sqltype, &dbstr);
883
std::cout << "column: " << db_get_column_name(column) << std::endl;
884
std::cout << "value: " << db_get_string(&dbstr) << std::endl;
887
layer.attributes[layer.nAttributes].values[i] = strdup ( db_get_string(&dbstr) );
890
if ( ctype == DB_C_TYPE_INT ) {
891
dbl = db_get_value_int ( value );
892
} else if ( ctype == DB_C_TYPE_DOUBLE ) {
893
dbl = db_get_value_double ( value );
898
if ( dbl < layer.minmax[i][0] ) {
899
layer.minmax[i][0] = dbl;
901
if ( dbl > layer.minmax[i][1] ) {
902
layer.minmax[i][1] = dbl;
907
// Sort attributes by category
908
qsort ( layer.attributes, layer.nAttributes, sizeof(GATT), cmpAtt );
910
db_close_cursor (&databaseCursor);
911
db_close_database_shutdown_driver ( databaseDriver );
912
db_free_string(&dbstr);
915
std::cerr << "fields.size = " << layer.fields.size() << std::endl;
916
std::cerr << "number of attributes = " << layer.nAttributes << std::endl;
923
// Add cat if no attribute fields exist (otherwise qgis crashes)
924
if ( layer.nColumns == 0 ) {
925
layer.fields.push_back ( QgsField( "cat", "integer", 10, 0) );
926
layer.minmax = new double[1][2];
927
layer.minmax[0][0] = 0;
928
layer.minmax[0][1] = 0;
930
int cidx = Vect_cidx_get_field_index ( layer.map, layer.field );
932
int ncats, cat, type, id;
934
ncats = Vect_cidx_get_num_cats_by_index ( layer.map, cidx );
937
Vect_cidx_get_cat_by_index ( layer.map, cidx, 0, &cat, &type, &id );
938
layer.minmax[0][0] = cat;
940
Vect_cidx_get_cat_by_index ( layer.map, cidx, ncats-1, &cat, &type, &id );
941
layer.minmax[0][1] = cat;
946
GMAP *map = &(mMaps[layer.mapId]);
948
QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
949
map->lastAttributesModified = di.lastModified();
952
void QgsGrassProvider::closeLayer( int layerId )
955
std::cerr << "Close layer " << layerId << " nUsers = " << mLayers[layerId].nUsers << std::endl;
958
// TODO: not tested because delete is never used for providers
959
mLayers[layerId].nUsers--;
961
if ( mLayers[layerId].nUsers == 0 ) { // No more users, free sources
963
std::cerr << "No more users -> delete layer" << std::endl;
966
mLayers[layerId].valid = false;
968
// Column names/types
969
mLayers[layerId].fields.resize(0);
973
std::cerr << "Delete attribute values" << std::endl;
975
for ( int i = 0; i < mLayers[layerId].nAttributes; i++ ) {
976
free ( mLayers[layerId].attributes[i].values );
978
free ( mLayers[layerId].attributes );
980
delete[] mLayers[layerId].minmax;
983
free ( mLayers[layerId].fieldInfo );
985
closeMap ( mLayers[layerId].mapId );
989
/* returns mapId or -1 on error */
990
int QgsGrassProvider::openMap(QString gisdbase, QString location, QString mapset, QString mapName)
993
std::cerr << "QgsGrassProvider::openMap()" << std::endl;
996
QString tmpPath = gisdbase + "/" + location + "/" + mapset + "/" + mapName;
998
// Check if this map is already opened
999
for ( int i = 0; i < mMaps.size(); i++) {
1000
if ( mMaps[i].valid && mMaps[i].path == tmpPath )
1002
// the map is already opened, return map id
1004
std::cerr << "The map is already opened with ID = " << i << std::endl;
1012
map.gisdbase = gisdbase;
1013
map.location = location;
1014
map.mapset = mapset;
1015
map.mapName = mapName;
1020
map.map = (struct Map_info *) malloc ( sizeof(struct Map_info) );
1022
// Set GRASS location
1023
QgsGrass::setLocation ( gisdbase, location );
1025
std::cerr << "Setting gisdbase, location: " << gisdbase << ", " << location << std::endl;
1029
char *ms = G_find_vector2 ( (char *) mapName.ascii(), (char *) mapset.ascii()) ;
1032
std::cerr << "Cannot find GRASS vector" << std::endl;
1036
// Read the time of vector dir before Vect_open_old, because it may take long time (when the vector
1037
// could be owerwritten)
1038
QFileInfo di ( gisdbase + "/" + location + "/" + mapset + "/vector/" + mapName );
1039
map.lastModified = di.lastModified();
1041
di.setFile ( gisdbase + "/" + location + "/" + mapset + "/vector/" + mapName + "/dbln" );
1042
map.lastAttributesModified = di.lastModified();
1045
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1046
Vect_set_open_level (2);
1047
Vect_open_old ( map.map, (char *) mapName.ascii(), (char *) mapset.ascii());
1049
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1050
std::cerr << "Cannot open GRASS vector: " << QgsGrass::getErrorMessage() << std::endl;
1054
std::cerr << "GRASS map successfully opened" << std::endl;
1057
// Add new map to maps
1058
mMaps.push_back(map);
1060
return mMaps.size() - 1; // map id
1063
void QgsGrassProvider::updateMap ( int mapId )
1066
std::cerr << "QgsGrassProvider::updateMap() mapId = " << mapId << std::endl;
1070
GMAP *map = &(mMaps[mapId]);
1075
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1077
// TODO: Should be done better / in other place ?
1078
// TODO: Is it necessary for close ?
1079
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1081
Vect_close ( map->map );
1083
QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName );
1084
map->lastModified = di.lastModified();
1086
di.setFile ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
1087
map->lastAttributesModified = di.lastModified();
1090
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1091
Vect_set_open_level (2);
1092
Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii());
1094
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1095
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage() << std::endl;
1097
// TODO if reopen fails, mLayers should be also updated
1102
std::cerr << "GRASS map successfully reopened for reading." << std::endl;
1105
for ( int i = 0; i < mLayers.size(); i++) {
1106
// if ( !(mLayers[i].valid) ) continue; // ?
1108
if ( mLayers[i].mapId == mapId ) {
1109
loadLayerSourcesFromMap ( mLayers[i] );
1116
void QgsGrassProvider::closeMap( int mapId )
1119
std::cerr << "Close map " << mapId << " nUsers = " << mMaps[mapId].nUsers << std::endl;
1122
// TODO: not tested because delete is never used for providers
1123
mMaps[mapId].nUsers--;
1125
if ( mMaps[mapId].nUsers == 0 ) { // No more users, free sources
1127
std::cerr << "No more users -> delete map" << std::endl;
1130
// TODO: do this better, probably maintain QgsGrassEdit as one user
1131
if ( mMaps[mapId].update ) {
1132
QMessageBox::warning( 0, "Warning", "The vector was currently edited, "
1133
"you can expect crash soon." );
1136
mMaps[mapId].valid = false;
1137
Vect_close ( mMaps[mapId].map );
1141
bool QgsGrassProvider::mapOutdated( int mapId )
1144
std::cerr << "QgsGrassProvider::mapOutdated()" << std::endl;
1147
GMAP *map = &(mMaps[mapId]);
1149
QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName;
1150
QFileInfo di ( dp );
1152
if ( map->lastModified < di.lastModified() ) {
1154
std::cerr << "**** The map " << mapId << " was modified ****" << std::endl;
1163
bool QgsGrassProvider::attributesOutdated( int mapId )
1166
std::cerr << "QgsGrassProvider::attributesOutdated()" << std::endl;
1169
GMAP *map = &(mMaps[mapId]);
1171
QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln";
1172
QFileInfo di ( dp );
1174
if ( map->lastAttributesModified < di.lastModified() ) {
1176
std::cerr << "**** The attributes of the map " << mapId << " were modified ****" << std::endl;
1185
/** Set feature attributes */
1186
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature )
1189
std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
1191
if ( mLayers[layerId].nColumns > 0 ) {
1196
GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
1197
sizeof(GATT), cmpAtt);
1199
for (int i = 0; i < mLayers[layerId].nColumns; i++) {
1200
if ( att != NULL ) {
1201
QCString cstr( att->values[i] );
1202
feature->addAttribute ( mLayers[layerId].fields[i].name(), mEncoding->toUnicode(cstr) );
1203
} else { /* it may happen that attributes are missing -> set to empty string */
1204
feature->addAttribute ( mLayers[layerId].fields[i].name(), "");
1209
tmp.sprintf("%d", cat );
1210
feature->addAttribute ( "cat", tmp);
1214
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature, std::list<int> const& attlist)
1217
std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
1219
if ( mLayers[layerId].nColumns > 0 ) {
1223
GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
1224
sizeof(GATT), cmpAtt);
1226
for (std::list<int>::const_iterator iter=attlist.begin(); iter!=attlist.end();++iter) {
1227
if ( att != NULL ) {
1228
QCString cstr( att->values[*iter] );
1229
feature->addAttribute ( mLayers[layerId].fields[*iter].name(), mEncoding->toUnicode(cstr) );
1230
} else { /* it may happen that attributes are missing -> set to empty string */
1231
feature->addAttribute ( mLayers[layerId].fields[*iter].name(), "");
1236
tmp.sprintf("%d", cat );
1237
feature->addAttribute ( "cat", tmp);
1241
/** Get pointer to map */
1242
struct Map_info *QgsGrassProvider::layerMap ( int layerId )
1244
return ( mMaps[mLayers[layerId].mapId].map );
1247
QString QgsGrassProvider::getProjectionWKT(void)
1251
struct Cell_head cellhd;
1253
QgsGrass::setLocation ( mGisdbase, mLocation );
1254
G_get_default_window(&cellhd);
1255
if (cellhd.proj != PROJECTION_XY) {
1256
struct Key_Value *projinfo = G_get_projinfo();
1257
struct Key_Value *projunits = G_get_projunits();
1258
char *wkt = GPJ_grass_to_wkt ( projinfo, projunits, 0, 0 );
1266
int QgsGrassProvider::grassLayer()
1271
//----------------------------------------- Edit -------------------------------------------------------
1273
bool QgsGrassProvider::isGrassEditable ( void )
1276
std::cerr << "QgsGrassProvider::isGrassEditable" << std::endl;
1282
/* Check if current user is owner of mapset */
1283
if ( G__mapset_permissions2((char*)mGisdbase.ascii(),(char*)mLocation.ascii(),(char*)mMapset.ascii()) != 1 )
1286
// TODO: check format? (cannot edit OGR layers)
1291
bool QgsGrassProvider::isEdited ( void )
1294
std::cerr << "QgsGrassProvider::isEdited" << std::endl;
1297
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1298
return (map->update);
1301
bool QgsGrassProvider::startEdit ( void )
1304
std::cerr << "QgsGrassProvider::startEdit" << std::endl;
1305
std::cerr << " uri = " << mDataSourceUri << std::endl;
1306
std::cerr << " mMaps.size() = " << mMaps.size() << std::endl;
1309
if ( !isGrassEditable() )
1312
// Check number of maps (the problem may appear if static variables are not shared - runtime linker)
1313
if ( mMaps.size() == 0 ) {
1314
QMessageBox::warning( 0, "Warning", "No maps opened in mMaps, probably problem in runtime linking, "
1315
"static variables are not shared by provider and plugin." );
1320
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1323
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1325
// Set current mapset (mapset was previously checked by isGrassEditable() )
1326
// TODO: Should be done better / in other place ?
1327
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1329
Vect_close ( map->map );
1331
// TODO: Catch error
1333
QgsGrass::resetError();
1334
int level = Vect_open_update ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii() );
1336
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1337
std::cerr << "Cannot open GRASS vector for update: " << QgsGrass::getErrorMessage() << std::endl;
1339
std::cerr << "Cannot open GRASS vector for update on level 2." << std::endl;
1342
// reopen vector for reading
1343
QgsGrass::resetError();
1344
Vect_set_open_level (2);
1345
level = Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii() );
1348
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1349
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage() << std::endl;
1351
std::cerr << "Cannot reopen GRASS vector on level 2." << std::endl;
1361
Vect_hist_command ( map->map );
1364
std::cerr << "Vector successfully reopened for update." << std::endl;
1373
bool QgsGrassProvider::closeEdit ( void )
1376
std::cerr << "QgsGrassProvider::closeEdit" << std::endl;
1383
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1385
if ( !(map->update) )
1391
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1393
// Set current mapset (mapset was previously checked by isGrassEditable() )
1394
// TODO: Should be done better / in other place ?
1395
// TODO: Is it necessary for build/close ?
1396
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1398
Vect_build_partial ( map->map, GV_BUILD_NONE, NULL);
1399
Vect_build ( map->map, stderr );
1400
Vect_close ( map->map );
1402
QFileInfo di ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapName );
1403
map->lastModified = di.lastModified();
1405
di.setFile ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapset + "/dbln" );
1406
map->lastAttributesModified = di.lastModified();
1409
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1410
Vect_set_open_level (2);
1411
Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii());
1413
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1414
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage() << std::endl;
1419
std::cerr << "GRASS map successfully reopened for reading." << std::endl;
1422
// Reload sources to layers
1423
for ( int i = 0; i < mLayers.size(); i++) {
1424
// if ( !(mLayers[i].valid) ) continue; // ?
1426
if ( mLayers[i].mapId == mLayers[mLayerId].mapId ) {
1427
loadLayerSourcesFromMap ( mLayers[i] );
1431
map->update = false;
1437
int QgsGrassProvider::numLines ( void )
1440
std::cerr << "QgsGrassProvider::numLines" << std::endl;
1443
return ( Vect_get_num_lines(mMap) );
1446
int QgsGrassProvider::numNodes ( void )
1449
std::cerr << "QgsGrassProvider::numNodes" << std::endl;
1452
return ( Vect_get_num_nodes(mMap) );
1455
int QgsGrassProvider::readLine ( struct line_pnts *Points, struct line_cats *Cats, int line )
1458
std::cerr << "QgsGrassProvider::readLine" << std::endl;
1462
Vect_reset_line ( Points );
1465
Vect_reset_cats ( Cats );
1467
if ( !Vect_line_alive(mMap, line) ) return -1;
1469
return ( Vect_read_line(mMap, Points, Cats, line) );
1472
bool QgsGrassProvider::nodeCoor ( int node, double *x, double *y )
1475
std::cerr << "QgsGrassProvider::nodeCoor" << std::endl;
1478
if ( !Vect_node_alive ( mMap, node) ) {
1484
Vect_get_node_coor ( mMap, node, x, y, NULL);
1488
bool QgsGrassProvider::lineNodes ( int line, int *node1, int *node2 )
1491
std::cerr << "QgsGrassProvider::lineNodes" << std::endl;
1494
if ( !Vect_line_alive(mMap, line) ) {
1500
Vect_get_line_nodes ( mMap, line, node1, node2 );
1504
int QgsGrassProvider::writeLine ( int type, struct line_pnts *Points, struct line_cats *Cats )
1507
std::cerr << "QgsGrassProvider::writeLine n_points = " << Points->n_points
1508
<< " n_cats = " << Cats->n_cats << std::endl;
1514
return ( (int) Vect_write_line(mMap,type,Points,Cats) );
1517
int QgsGrassProvider::rewriteLine ( int line, int type, struct line_pnts *Points, struct line_cats *Cats )
1520
std::cerr << "QgsGrassProvider::rewriteLine n_points = " << Points->n_points
1521
<< " n_cats = " << Cats->n_cats << std::endl;
1527
return ( Vect_rewrite_line(mMap,line,type,Points,Cats) );
1531
int QgsGrassProvider::deleteLine ( int line )
1534
std::cerr << "QgsGrassProvider::deleteLine" << std::endl;
1540
return ( Vect_delete_line(mMap,line) );
1543
int QgsGrassProvider::findLine ( double x, double y, int type, double threshold )
1546
std::cerr << "QgsGrassProvider::findLine" << std::endl;
1549
return ( Vect_find_line(mMap,x,y,0,type,threshold,0,0) );
1552
int QgsGrassProvider::findNode ( double x, double y, double threshold )
1554
return ( Vect_find_node ( mMap, x, y, 0, threshold, 0 ) );
1557
bool QgsGrassProvider::lineAreas ( int line, int *left, int *right )
1560
std::cerr << "QgsGrassProvider::lineAreas" << std::endl;
1563
if ( !Vect_line_alive(mMap, line) ) {
1569
Vect_get_line_areas ( mMap, line, left, right );
1573
int QgsGrassProvider::centroidArea ( int centroid )
1576
std::cerr << "QgsGrassProvider::centroidArea" << std::endl;
1579
if ( !Vect_line_alive(mMap, centroid) ) {
1583
return ( Vect_get_centroid_area(mMap,centroid) );
1586
int QgsGrassProvider::nodeNLines ( int node )
1589
std::cerr << "QgsGrassProvider::nodeNLines" << std::endl;
1592
if ( !Vect_node_alive(mMap, node) ) {
1596
return ( Vect_get_node_n_lines(mMap,node) );
1599
int QgsGrassProvider::nodeLine ( int node, int idx )
1602
std::cerr << "QgsGrassProvider::nodeLine" << std::endl;
1605
if ( !Vect_node_alive(mMap, node) ) {
1609
return ( Vect_get_node_line(mMap,node,idx) );
1612
int QgsGrassProvider::lineAlive ( int line )
1615
std::cerr << "QgsGrassProvider::lineAlive" << std::endl;
1618
return ( Vect_line_alive(mMap, line) ) ;
1621
int QgsGrassProvider::nodeAlive ( int node )
1624
std::cerr << "QgsGrassProvider::nodeAlive" << std::endl;
1627
return ( Vect_node_alive(mMap, node) ) ;
1630
int QgsGrassProvider::numUpdatedLines ( void )
1633
std::cerr << "QgsGrassProvider::numUpdatedLines" << std::endl;
1634
std::cerr << " numUpdatedLines = " << Vect_get_num_updated_lines(mMap) << std::endl;
1637
return ( Vect_get_num_updated_lines(mMap) ) ;
1640
int QgsGrassProvider::numUpdatedNodes ( void )
1643
std::cerr << "QgsGrassProvider::numUpdatedNodes" << std::endl;
1644
std::cerr << " numUpdatedNodes = " << Vect_get_num_updated_nodes(mMap) << std::endl;
1647
return ( Vect_get_num_updated_nodes(mMap) ) ;
1650
int QgsGrassProvider::updatedLine ( int idx )
1653
std::cerr << "QgsGrassProvider::updatedLine idx = " << idx << std::endl;
1654
std::cerr << " updatedLine = " << Vect_get_updated_line( mMap, idx ) << std::endl;
1657
return ( Vect_get_updated_line( mMap, idx ) ) ;
1660
int QgsGrassProvider::updatedNode ( int idx )
1663
std::cerr << "QgsGrassProvider::updatedNode idx = " << idx << std::endl;
1664
std::cerr << " updatedNode = " << Vect_get_updated_node( mMap, idx ) << std::endl;
1667
return ( Vect_get_updated_node( mMap, idx ) ) ;
1670
// ------------------ Attributes -------------------------------------------------
1672
QString *QgsGrassProvider::key ( int field )
1675
std::cerr << "QgsGrassProvider::key() field = " << field << std::endl;
1678
QString *key = new QString();
1680
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1684
std::cerr << "No field info -> no attributes" << std::endl;
1689
key->setAscii(fi->key);
1693
std::vector<QgsField> *QgsGrassProvider::columns ( int field )
1696
std::cerr << "QgsGrassProvider::columns() field = " << field << std::endl;
1699
std::vector<QgsField> *col = new std::vector<QgsField>;
1701
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1706
std::cerr << "No field info -> no attributes" << std::endl;
1712
std::cerr << "Field info found -> open database" << std::endl;
1714
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1715
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1717
if ( driver == NULL ) {
1718
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1723
std::cerr << "Database opened -> describe table" << std::endl;
1727
db_init_string ( &tableName );
1728
db_set_string ( &tableName, fi->table);
1731
if(db_describe_table (driver, &tableName, &table) != DB_OK) {
1732
std::cerr << "Cannot describe table" << std::endl;
1736
int nCols = db_get_table_number_of_columns(table);
1738
for (int c = 0; c < nCols; c++) {
1739
dbColumn *column = db_get_table_column (table, c);
1741
int ctype = db_sqltype_to_Ctype( db_get_column_sqltype (column) );
1747
case DB_C_TYPE_DOUBLE:
1750
case DB_C_TYPE_STRING:
1753
case DB_C_TYPE_DATETIME:
1757
col->push_back ( QgsField( db_get_column_name (column), type, db_get_column_length(column), 0) );
1760
db_close_database_shutdown_driver ( driver );
1765
std::vector<QgsFeatureAttribute> *QgsGrassProvider::attributes ( int field, int cat )
1768
std::cerr << "QgsGrassProvider::attributes() field = " << field << " cat = " << cat << std::endl;
1771
std::vector<QgsFeatureAttribute> *att = new std::vector<QgsFeatureAttribute>;
1773
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1778
std::cerr << "No field info -> no attributes" << std::endl;
1784
std::cerr << "Field info found -> open database" << std::endl;
1786
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1787
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1789
if ( driver == NULL ) {
1790
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1795
std::cerr << "Database opened -> read attributes" << std::endl;
1799
db_init_string (&dbstr);
1801
query.sprintf("select * from %s where %s = %d", fi->table, fi->key, cat );
1802
db_set_string (&dbstr, (char *)query.ascii());
1805
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
1808
dbCursor databaseCursor;
1809
if ( db_open_select_cursor(driver, &dbstr, &databaseCursor, DB_SCROLL) != DB_OK ){
1810
db_close_database_shutdown_driver ( driver );
1811
std::cerr << "Cannot select attributes from table" << std::endl;
1815
int nRecords = db_get_num_rows ( &databaseCursor );
1817
std::cerr << "Number of records: " << nRecords << std::endl;
1820
if ( nRecords < 1 ) {
1821
std::cerr << "No DB record" << std::endl;
1825
dbTable *databaseTable = db_get_cursor_table (&databaseCursor);
1826
int nColumns = db_get_table_number_of_columns(databaseTable);
1829
if ( db_fetch (&databaseCursor, DB_NEXT, &more) != DB_OK ) {
1830
std::cout << "Cannot fetch DB record" << std::endl;
1834
// Read columns' description
1835
for (int i = 0; i < nColumns; i++) {
1836
dbColumn *column = db_get_table_column (databaseTable, i);
1837
db_convert_column_value_to_string (column, &dbstr);
1839
QString v = mEncoding->toUnicode(db_get_string(&dbstr));
1840
std::cerr << "Value: " << v << std::endl;
1841
att->push_back ( QgsFeatureAttribute( db_get_column_name(column), v ) );
1844
db_close_cursor (&databaseCursor);
1845
db_close_database_shutdown_driver ( driver );
1846
db_free_string(&dbstr);
1851
QString *QgsGrassProvider::updateAttributes ( int field, int cat, const QString &values )
1854
std::cerr << "QgsGrassProvider::updateAttributes() field = " << field << " cat = " << cat << std::endl;
1857
QString *error = new QString();
1858
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1863
std::cerr << "No field info -> no attributes" << std::endl;
1865
error->setLatin1( "Cannot get field info" );
1870
std::cerr << "Field info found -> open database" << std::endl;
1872
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1873
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1875
if ( driver == NULL ) {
1876
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1877
error->setAscii("Cannot open database");
1882
std::cerr << "Database opened -> read attributes" << std::endl;
1886
db_init_string (&dbstr);
1889
query = "update " + QString(fi->table) + " set " + values + " where " + QString(fi->key)
1890
+ " = " + QString::number(cat);
1893
std::cerr << "query: " << query << std::endl;
1896
// For some strange reason, mEncoding->fromUnicode(query) does not work,
1897
// but probably it is not correct, because Qt widgets will use current locales for input
1898
// -> it is possible to edit only in current locales at present
1899
// QCString qcs = mEncoding->fromUnicode(query);
1901
QCString qcs = query.local8Bit();
1903
std::cerr << "qcs: " << qcs << std::endl;
1906
char *cs = new char[qcs.length() + 1];
1907
strcpy(cs, (const char *)qcs);
1908
db_set_string (&dbstr, cs );
1912
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
1915
int ret = db_execute_immediate (driver, &dbstr);
1917
if ( ret != DB_OK) {
1918
std::cerr << "Error: " << db_get_error_msg() << std::endl;
1919
error->setLatin1( db_get_error_msg() );
1922
db_close_database_shutdown_driver ( driver );
1923
db_free_string(&dbstr);
1928
int QgsGrassProvider::numDbLinks ( void )
1931
std::cerr << "QgsGrassProvider::numDbLinks()" << std::endl;
1934
return ( Vect_get_num_dblinks(mMap) );
1937
int QgsGrassProvider::dbLinkField ( int link )
1940
std::cerr << "QgsGrassProvider::dbLinkField()" << std::endl;
1943
struct field_info *fi = Vect_get_dblink ( mMap, link );
1945
if ( fi == NULL ) return 0;
1947
return ( fi->number );
1952
QString *QgsGrassProvider::createTable ( int field, const QString &key, const QString &columns )
1955
std::cerr << "QgsGrassProvider::createTable() field = " << field << std::endl;
1958
QString *error = new QString();
1959
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1964
std::cerr << "The table for this field already exists" << std::endl;
1966
error->setLatin1( "The table for this field already exists" );
1971
std::cerr << "Field info not found -> create new table" << std::endl;
1974
int nLinks = Vect_get_num_dblinks( mMap );
1975
if ( nLinks == 0 ) {
1976
fi = Vect_default_field_info ( mMap, field, NULL, GV_1TABLE );
1978
fi = Vect_default_field_info ( mMap, field, NULL, GV_MTABLE );
1981
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1982
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1984
if ( driver == NULL ) {
1985
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1986
error->setAscii("Cannot open database");
1991
std::cerr << "Database opened -> create table" << std::endl;
1995
db_init_string (&dbstr);
1998
query.sprintf("create table %s ( %s )", fi->table, columns.latin1() );
1999
db_set_string (&dbstr, (char *)query.latin1());
2002
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2005
int ret = db_execute_immediate (driver, &dbstr);
2007
if ( ret != DB_OK) {
2008
std::cerr << "Error: " << db_get_error_msg() << std::endl;
2009
error->setLatin1( db_get_error_msg() );
2012
db_close_database_shutdown_driver ( driver );
2013
db_free_string(&dbstr);
2015
if ( !error->isEmpty() ) return error;
2017
ret = Vect_map_add_dblink ( mMap, field, NULL, fi->table, (char *)key.latin1(),
2018
fi->database, fi->driver);
2021
std::cerr << "Error: Cannot add dblink" << std::endl;
2022
error->setLatin1( "Cannot create link to the table. The table was created!" );
2028
QString *QgsGrassProvider::addColumn ( int field, const QString &column )
2031
std::cerr << "QgsGrassProvider::addColumn() field = " << field << std::endl;
2034
QString *error = new QString();
2035
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2040
std::cerr << "No field info" << std::endl;
2042
error->setLatin1( "Cannot get field info" );
2047
std::cerr << "Field info found -> open database" << std::endl;
2049
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2050
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2052
if ( driver == NULL ) {
2053
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2054
error->setAscii("Cannot open database");
2059
std::cerr << "Database opened -> add column" << std::endl;
2063
db_init_string (&dbstr);
2066
query.sprintf("alter table %s add column %s", fi->table, column.latin1() );
2067
db_set_string (&dbstr, (char *)query.latin1());
2070
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2073
int ret = db_execute_immediate (driver, &dbstr);
2075
if ( ret != DB_OK) {
2076
std::cerr << "Error: " << db_get_error_msg() << std::endl;
2077
error->setLatin1( db_get_error_msg() );
2080
db_close_database_shutdown_driver ( driver );
2081
db_free_string(&dbstr);
2086
QString *QgsGrassProvider::insertAttributes ( int field, int cat )
2089
std::cerr << "QgsGrassProvider::insertAttributes() field = " << field << " cat = " << cat << std::endl;
2092
QString *error = new QString();
2093
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2098
std::cerr << "No field info -> no attributes" << std::endl;
2100
error->setLatin1( "Cannot get field info" );
2105
std::cerr << "Field info found -> open database" << std::endl;
2107
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2108
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2110
if ( driver == NULL ) {
2111
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2112
error->setAscii("Cannot open database");
2117
std::cerr << "Database opened -> insert new record" << std::endl;
2121
db_init_string (&dbstr);
2124
query.sprintf("insert into %s ( %s ) values ( %d )", fi->table, fi->key, cat );
2125
db_set_string (&dbstr, (char *)query.latin1());
2128
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2131
int ret = db_execute_immediate (driver, &dbstr);
2133
if ( ret != DB_OK) {
2134
std::cerr << "Error: " << db_get_error_msg() << std::endl;
2135
error->setLatin1( db_get_error_msg() );
2138
db_close_database_shutdown_driver ( driver );
2139
db_free_string(&dbstr);
2145
// -------------------------------------------------------------------------------
2147
int QgsGrassProvider::cidxGetNumFields( )
2149
return ( Vect_cidx_get_num_fields(mMap) );
2152
int QgsGrassProvider::cidxGetFieldNumber( int idx )
2154
return ( Vect_cidx_get_field_number(mMap, idx) );
2157
int QgsGrassProvider::cidxGetMaxCat( int idx )
2159
int ncats = Vect_cidx_get_num_cats_by_index ( mMap, idx);
2162
Vect_cidx_get_cat_by_index ( mMap, idx, ncats-1, &cat, &type, &id );