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
***************************************************************************/
16
/* $Id: qgsgrassprovider.cpp 6293 2006-12-21 18:00:15Z rblazek $ */
27
#include <qdatetime.h>
28
#include <qmessagebox.h>
33
#include "qgsdataprovider.h"
34
#include "qgsfeature.h"
37
#include "qgsfeatureattribute.h"
40
#include <grass/gprojects.h>
41
#include <grass/gis.h>
42
#include <grass/dbmi.h>
43
#include <grass/Vect.h>
47
#include "qgsgrassprovider.h"
49
std::vector<GLAYER> QgsGrassProvider::mLayers;
50
std::vector<GMAP> QgsGrassProvider::mMaps;
53
static QString GRASS_KEY = "grass"; // XXX verify this
54
static QString GRASS_DESCRIPTION = "Grass provider"; // XXX verify this
58
QgsGrassProvider::QgsGrassProvider(QString const & uri)
59
: QgsVectorDataProvider(uri)
62
std::cerr << "QgsGrassProvider URI: " << uri.toLocal8Bit().data() << std::endl;
73
QDir dir ( uri ); // it is not a directory in fact
74
QString myURI = dir.path(); // no dupl '/'
76
mLayer = dir.dirName();
77
myURI = myURI.left( dir.path().findRev('/') );
79
mMapName = dir.dirName();
81
mMapset = dir.dirName();
83
mLocation = dir.dirName();
85
mGisdbase = dir.path();
88
std::cerr << "gisdbase: " << mGisdbase.toLocal8Bit().data() << std::endl;
89
std::cerr << "location: " << mLocation.toLocal8Bit().data() << std::endl;
90
std::cerr << "mapset: " << mMapset.toLocal8Bit().data() << std::endl;
91
std::cerr << "mapName: " << mMapName.toLocal8Bit().data() << std::endl;
92
std::cerr << "layer: " << mLayer.toLocal8Bit().data() << std::endl;
95
/* Parse Layer, supported layers <field>_point, <field>_line, <field>_area
96
* Layer is opened even if it is empty (has no features)
99
if ( mLayer.compare("boundary") == 0 ) { // currently not used
100
mLayerType = BOUNDARY;
101
mGrassType = GV_BOUNDARY;
102
} else if ( mLayer.compare("centroid") == 0 ) { // currently not used
103
mLayerType = CENTROID;
104
mGrassType = GV_CENTROID;
106
mLayerField = grassLayer ( mLayer );
107
if ( mLayerField == -1 ) {
108
std::cerr << "Invalid layer name, no underscore found: " << mLayer.toLocal8Bit().data() << std::endl;
112
mGrassType = grassLayerType ( mLayer );
114
if ( mGrassType == GV_POINT ) {
116
} else if ( mGrassType == GV_LINES ) {
118
} else if ( mGrassType == GV_AREA ) {
119
mLayerType = POLYGON;
121
std::cerr << "Invalid layer name, wrong type: " << mLayer.toLocal8Bit().data() << std::endl;
127
std::cerr << "mLayerField: " << mLayerField << std::endl;
128
std::cerr << "mLayerType: " << mLayerType << std::endl;
131
if ( mLayerType == BOUNDARY || mLayerType == CENTROID ) {
132
std::cerr << "Layer type not supported." << std::endl;
137
switch ( mLayerType ) {
140
mQgisType = QGis::WKBPoint;
144
mQgisType = QGis::WKBLineString;
147
mQgisType = QGis::WKBPolygon;
151
mLayerId = openLayer(mGisdbase, mLocation, mMapset, mMapName, mLayerField);
152
if ( mLayerId < 0 ) {
153
std::cerr << "Cannot open GRASS layer:" << myURI.toLocal8Bit().data() << std::endl;
157
std::cerr << "mLayerId: " << mLayerId << std::endl;
160
mMap = layerMap(mLayerId);
162
// Getting the total number of features in the layer
164
mCidxFieldIndex = -1;
165
if ( mLayerField >= 0 ) {
166
mCidxFieldIndex = Vect_cidx_get_field_index ( mMap, mLayerField);
167
if ( mCidxFieldIndex >= 0 ) {
168
mNumberFeatures = Vect_cidx_get_type_count ( mMap, mLayerField, mGrassType );
169
mCidxFieldNumCats = Vect_cidx_get_num_cats_by_index ( mMap, mCidxFieldIndex );
172
// TODO nofield layers
174
mCidxFieldNumCats = 0;
179
std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
180
<< " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
184
// Create selection array
185
mSelectionSize = allocateSelection ( mMap, &mSelection );
186
resetSelection(1); // TODO ? - where what reset
188
mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
191
mPoints = Vect_new_line_struct ();
192
mCats = Vect_new_cats_struct ();
193
mList = Vect_new_list ();
198
std::cerr << "New GRASS layer opened, time (ms): " << time.elapsed() << std::endl;
202
void QgsGrassProvider::update ( void )
205
std::cerr << "*** QgsGrassProvider::update ***" << std::endl;
210
if ( ! mMaps[mLayers[mLayerId].mapId].valid ) return;
212
// Getting the total number of features in the layer
213
// It may happen that the field disappeares from the map (deleted features, new map without that field)
215
mCidxFieldIndex = -1;
216
if ( mLayerField >= 0 ) {
217
mCidxFieldIndex = Vect_cidx_get_field_index ( mMap, mLayerField);
218
if ( mCidxFieldIndex >= 0 ) {
219
mNumberFeatures = Vect_cidx_get_type_count ( mMap, mLayerField, mGrassType );
220
mCidxFieldNumCats = Vect_cidx_get_num_cats_by_index ( mMap, mCidxFieldIndex );
223
// TODO nofield layers
225
mCidxFieldNumCats = 0;
230
std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
231
<< " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
234
// Create selection array
235
if ( mSelection ) free ( mSelection );
236
mSelectionSize = allocateSelection ( mMap, &mSelection );
239
mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
244
int QgsGrassProvider::allocateSelection( struct Map_info *map, char **selection )
248
std::cerr << "QgsGrassProvider::allocateSellection" << std::endl;
251
int nlines = Vect_get_num_lines ( map );
252
int nareas = Vect_get_num_areas ( map );
254
if ( nlines > nareas ) {
260
std::cerr << "nlines = " << nlines << " nareas = " << nareas << " size = " << size << std::endl;
263
*selection = (char *) malloc ( size );
268
QgsGrassProvider::~QgsGrassProvider()
271
std::cerr << "QgsGrassProvider::~QgsGrassProvider()" << std::endl;
273
closeLayer ( mLayerId );
277
QString QgsGrassProvider::storageType()
279
return "GRASS (Geographic Resources Analysis and Support System) file";
284
* Get the first feature resutling from a select operation
287
QgsFeature *QgsGrassProvider::getFirstFeature(bool fetchAttributes)
290
std::cout << "QgsGrassProvider::getFirstFeature()" << std::endl;
293
if ( isEdited() || isFrozen() || !mValid )
296
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
300
return ( getNextFeature(fetchAttributes) );
304
* Get the next feature resulting from a select operation
305
* @return false if there are no features in the selection set
307
bool QgsGrassProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes)
310
std::cout << "QgsGrassProvider::getNextFeature()" << std::endl;
313
if ( isEdited() || isFrozen() || !mValid )
316
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
318
// TODO once clear how to do that
323
* Get the next feature resulting from a select operation
324
* Return 0 if there are no features in the selection set
327
QgsFeature *QgsGrassProvider::getNextFeature(bool fetchAttributes)
330
std::cout << "QgsGrassProvider::getNextFeature() mNextCidx = " << mNextCidx
331
<< " fetchAttributes = " << fetchAttributes << std::endl;
334
if ( isEdited() || isFrozen() || !mValid )
337
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
339
std::list<int> attlist;
341
if ( fetchAttributes ) {
342
int fc = fieldCount();
343
for ( int i = 0; i < fc; i++ ) {
344
attlist.push_back(i);
348
return ( getNextFeature(attlist) );
351
QgsFeature* QgsGrassProvider::getNextFeature(std::list<int> const& attlist, int featureQueueSize)
353
int cat, type, id, idx;
358
std::cout << "QgsGrassProvider::getNextFeature( attlist )" << std::endl;
361
if ( isEdited() || isFrozen() || !mValid )
364
if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
366
// Get next line/area id
368
while ( mNextCidx < mCidxFieldNumCats ) {
369
Vect_cidx_get_cat_by_index ( mMap, mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
370
// Warning: selection array is only of type line/area of current layer -> check type first
372
if ( !(type & mGrassType) ) continue;
373
if ( !mSelection[id] ) continue;
377
if ( !found ) return 0; // No more features
379
std::cout << "cat = " << cat << " type = " << type << " id = " << id << std::endl;
382
QgsFeature *f = new QgsFeature(id);
384
// TODO int may be 64 bits (memcpy)
385
if ( type & (GV_POINTS | GV_LINES) ) { /* points or lines */
386
Vect_read_line ( mMap, mPoints, mCats, id);
387
int npoints = mPoints->n_points;
389
if ( type & GV_POINTS ) {
390
wkbsize = 1 + 4 + 2*8;
392
wkbsize = 1+4+4+npoints*2*8;
394
wkb = new unsigned char[wkbsize];
395
unsigned char *wkbp = wkb;
396
wkbp[0] = (unsigned char) endian();
400
memcpy (wkbp, &mQgisType, 4);
403
/* number of points */
404
if ( type & GV_LINES ) {
405
memcpy (wkbp, &npoints, 4);
409
for ( int i = 0; i < npoints; i++ ) {
410
memcpy (wkbp, &(mPoints->x[i]), 8);
411
memcpy (wkbp+8, &(mPoints->y[i]), 8);
415
Vect_get_area_points ( mMap, id, mPoints );
416
int npoints = mPoints->n_points;
418
wkbsize = 1+4+4+4+npoints*2*8; // size without islands
419
wkb = new unsigned char[wkbsize];
420
wkb[0] = (unsigned char) endian();
424
memcpy ( wkb+offset, &mQgisType, 4);
427
/* Number of rings */
428
int nisles = Vect_get_area_num_isles ( mMap, id );
429
int nrings = 1 + nisles;
430
memcpy (wkb+offset, &nrings, 4);
434
memcpy (wkb+offset, &npoints, 4);
436
for ( int i = 0; i < npoints; i++ ) {
437
memcpy (wkb+offset, &(mPoints->x[i]), 8);
438
memcpy (wkb+offset+8, &(mPoints->y[i]), 8);
443
for ( int i = 0; i < nisles; i++ ) {
444
Vect_get_isle_points ( mMap, Vect_get_area_isle (mMap, id, i), mPoints );
445
npoints = mPoints->n_points;
448
wkbsize += 4+npoints*2*8;
449
wkb = (unsigned char *) realloc (wkb, wkbsize);
451
memcpy (wkb+offset, &npoints, 4);
453
for ( int i = 0; i < npoints; i++ ) {
454
memcpy (wkb+offset, &(mPoints->x[i]), 8);
455
memcpy (wkb+offset+8, &(mPoints->y[i]), 8);
461
f->setGeometryAndOwnership(wkb, wkbsize);
463
setFeatureAttributes( mLayerId, cat, f, attlist );
470
void QgsGrassProvider::resetSelection( bool sel)
473
std::cout << "QgsGrassProvider::resetSelection()" << std::endl;
475
if ( !mValid ) return;
476
memset ( mSelection, (int) sel, mSelectionSize );
481
* Select features based on a bounding rectangle. Features can be retrieved
482
* with calls to getFirstFeature and getNextFeature.
483
* @param mbr QgsRect containing the extent to use in selecting features
485
void QgsGrassProvider::select(QgsRect *rect, bool useIntersect)
488
std::cout << "QgsGrassProvider::select() useIntersect = " << useIntersect << std::endl;
491
if ( isEdited() || isFrozen() || !mValid )
494
// check if outdated and update if necessary
495
int mapId = mLayers[mLayerId].mapId;
496
if ( mapOutdated(mapId) ) {
499
if ( mMapVersion < mMaps[mapId].version ) {
502
if ( attributesOutdated(mapId) ) {
503
loadAttributes (mLayers[mLayerId]);
508
if ( !useIntersect ) { // select by bounding boxes only
510
box.N = rect->yMax(); box.S = rect->yMin();
511
box.E = rect->xMax(); box.W = rect->xMin();
512
box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX;
513
if ( mLayerType == POINT || mLayerType == CENTROID || mLayerType == LINE || mLayerType == BOUNDARY ) {
514
Vect_select_lines_by_box(mMap, &box, mGrassType, mList);
515
} else if ( mLayerType == POLYGON ) {
516
Vect_select_areas_by_box(mMap, &box, mList);
519
} else { // check intersection
520
struct line_pnts *Polygon;
522
Polygon = Vect_new_line_struct();
524
Vect_append_point( Polygon, rect->xMin(), rect->yMin(), 0);
525
Vect_append_point( Polygon, rect->xMax(), rect->yMin(), 0);
526
Vect_append_point( Polygon, rect->xMax(), rect->yMax(), 0);
527
Vect_append_point( Polygon, rect->xMin(), rect->yMax(), 0);
528
Vect_append_point( Polygon, rect->xMin(), rect->yMin(), 0);
530
if ( mLayerType == POINT || mLayerType == CENTROID || mLayerType == LINE || mLayerType == BOUNDARY ) {
531
Vect_select_lines_by_polygon ( mMap, Polygon, 0, NULL, mGrassType, mList);
532
} else if ( mLayerType == POLYGON ) {
533
Vect_select_areas_by_polygon ( mMap, Polygon, 0, NULL, mList);
536
Vect_destroy_line_struct (Polygon);
538
for ( int i = 0; i < mList->n_values; i++ ) {
539
if ( mList->value[i] <= mSelectionSize ) {
540
mSelection[mList->value[i]] = 1;
542
std::cerr << "Selected element out of range" << std::endl;
547
std::cout << mList->n_values << " features selected" << std::endl;
553
* Identify features within the search radius specified by rect
554
* @param rect Bounding rectangle of search radius
555
* @return std::vector containing QgsFeature objects that intersect rect
557
std::vector<QgsFeature>& QgsGrassProvider::identify(QgsRect * rect)
560
std::cout << "QgsGrassProvider::identify()" << std::endl;
563
// TODO: does not return vector of features! Should it?
565
if ( !isEdited() && !isFrozen() && mValid ) {
570
QgsRect *QgsGrassProvider::extent()
573
Vect_get_map_box ( mMap, &box );
575
return new QgsRect( box.W, box.S, box.E, box.N);
579
* Return the feature type
581
int QgsGrassProvider::geometryType() const
586
* Return the feature type
588
long QgsGrassProvider::featureCount() const
590
return mNumberFeatures;
594
* Return the number of fields
596
int QgsGrassProvider::fieldCount() const
599
std::cerr << "QgsGrassProvider::fieldCount() return:" << mLayers[mLayerId].fields.size() << std::endl;
601
return mLayers[mLayerId].fields.size();
607
std::vector<QgsField> const & QgsGrassProvider::fields() const
609
return mLayers[mLayerId].fields;
612
int QgsGrassProvider::keyField()
614
return mLayers[mLayerId].keyColumn;
617
void QgsGrassProvider::reset()
619
if ( isEdited() || isFrozen() || !mValid )
622
int mapId = mLayers[mLayerId].mapId;
623
if ( mapOutdated(mapId) ) {
626
if ( mMapVersion < mMaps[mapId].version ) {
629
if ( attributesOutdated(mapId) ) {
630
loadAttributes (mLayers[mLayerId]);
637
QString QgsGrassProvider::minValue(int position)
639
if ( position >= fieldCount() ) {
640
std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::minValue()"
643
return QString::number( mLayers[mLayerId].minmax[position][0], 'f', 2 );
647
QString QgsGrassProvider::maxValue(int position)
649
if ( position >= fieldCount() ) {
650
std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::maxValue()"
653
return QString::number( mLayers[mLayerId].minmax[position][1], 'f', 2 );
656
bool QgsGrassProvider::isValid(){
658
QString validString = mValid?"true":"false";
659
std::cerr << "QgsGrassProvider::isValid() returned: " << validString.toLocal8Bit().data() << std::endl;
664
// ------------------------------------------------------------------------------------------------------
665
// Compare categories in GATT
666
static int cmpAtt ( const void *a, const void *b ) {
667
GATT *p1 = (GATT *) a;
668
GATT *p2 = (GATT *) b;
669
return (p1->cat - p2->cat);
672
/* returns layerId or -1 on error */
673
int QgsGrassProvider::openLayer(QString gisdbase, QString location, QString mapset, QString mapName, int field)
676
std::cerr << "QgsGrassProvider::openLayer()" << std::endl;
677
std::cerr << "gisdbase: " << gisdbase.toLocal8Bit().data() << std::endl;
678
std::cerr << "location: " << location.toLocal8Bit().data() << std::endl;
679
std::cerr << "mapset: " << mapset.toLocal8Bit().data() << std::endl;
680
std::cerr << "mapName: " << mapName.toLocal8Bit().data() << std::endl;
681
std::cerr << "field: " << field << std::endl;
684
// Check if this layer is already opened
686
for ( int i = 0; i < mLayers.size(); i++) {
687
if ( !(mLayers[i].valid) ) continue;
689
GMAP *mp = &(mMaps[mLayers[i].mapId]);
691
if ( mp->gisdbase == gisdbase && mp->location == location &&
692
mp->mapset == mapset && mp->mapName == mapName && mLayers[i].field == field )
694
// the layer already exists, return layer id
696
std::cerr << "The layer is already opened with ID = " << i << std::endl;
703
// Create a new layer
710
layer.mapId = openMap ( gisdbase, location, mapset, mapName );
711
if ( layer.mapId < 0 ) {
712
std::cerr << "Cannot open vector map" << std::endl;
716
std::cerr << "layer.mapId = " << layer.mapId << std::endl;
718
layer.map = mMaps[layer.mapId].map;
720
layer.attributes = 0; // because loadLayerSourcesFromMap will release old
721
loadLayerSourcesFromMap ( layer );
725
// Add new layer to layers
726
mLayers.push_back(layer);
729
std::cerr << "New layer successfully opened" << layer.nAttributes << std::endl;
732
return mLayers.size() - 1;
735
void QgsGrassProvider::loadLayerSourcesFromMap ( GLAYER &layer )
738
std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
742
layer.fields.clear();
743
if ( layer.attributes ) {
744
for ( int i = 0; i < layer.nAttributes; i ++ ) {
745
for ( int j = 0; j < layer.nColumns; j ++ ) {
746
if ( layer.attributes[i].values[j] )
747
free ( layer.attributes[i].values[j] );
749
free ( layer.attributes[i].values );
751
free ( layer.attributes );
753
loadAttributes ( layer );
756
void QgsGrassProvider::loadAttributes ( GLAYER &layer )
759
std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
762
// TODO: free old attributes
764
if ( !layer.map ) return;
767
layer.fieldInfo = Vect_get_field( layer.map, layer.field); // should work also with field = 0
771
layer.nAttributes = 0;
772
layer.attributes = 0;
773
layer.fields.clear();
774
layer.keyColumn = -1;
775
if ( layer.fieldInfo == NULL ) {
777
std::cerr << "No field info -> no attribute table" << std::endl;
781
std::cerr << "Field info found -> open database" << std::endl;
783
dbDriver *databaseDriver = db_start_driver_open_database ( layer.fieldInfo->driver,
784
layer.fieldInfo->database );
786
if ( databaseDriver == NULL ) {
787
std::cerr << "Cannot open database " << layer.fieldInfo->database << " by driver "
788
<< layer.fieldInfo->driver << std::endl;
791
std::cerr << "Database opened -> open select cursor" << std::endl;
794
db_init_string (&dbstr);
795
db_set_string (&dbstr, "select * from ");
796
db_append_string (&dbstr, layer.fieldInfo->table);
799
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
801
dbCursor databaseCursor;
802
if ( db_open_select_cursor(databaseDriver, &dbstr, &databaseCursor, DB_SCROLL) != DB_OK ){
804
db_close_database_shutdown_driver ( databaseDriver );
805
QMessageBox::warning( 0, "Warning", "Cannot select attributes from table '" +
806
QString(layer.fieldInfo->table) + "'" );
808
int nRecords = db_get_num_rows ( &databaseCursor );
810
std::cerr << "Number of records: " << nRecords << std::endl;
813
dbTable *databaseTable = db_get_cursor_table (&databaseCursor);
814
layer.nColumns = db_get_table_number_of_columns(databaseTable);
816
layer.minmax = new double[layer.nColumns][2];
818
// Read columns' description
819
for (int i = 0; i < layer.nColumns; i++) {
820
layer.minmax[i][0] = DBL_MAX;
821
layer.minmax[i][1] = -DBL_MAX;
823
dbColumn *column = db_get_table_column (databaseTable, i);
825
int ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) );
827
std::cerr << "column = " << db_get_column_name(column)
828
<< " ctype = " << ctype << std::endl;
834
ctypeStr = "integer";
836
case DB_C_TYPE_DOUBLE:
839
case DB_C_TYPE_STRING:
842
case DB_C_TYPE_DATETIME:
843
ctypeStr = "datetime";
846
layer.fields.push_back ( QgsField( db_get_column_name(column), ctypeStr,
847
db_get_column_length(column), db_get_column_precision(column) ) );
849
if ( G_strcasecmp ( db_get_column_name(column), layer.fieldInfo->key) == 0 ) {
854
if ( layer.keyColumn < 0 ) {
855
layer.fields.clear();
858
QMessageBox::warning( 0, "Warning", "Key column '" + QString(layer.fieldInfo->key) +
859
"' not found in the table '" + QString(layer.fieldInfo->table) + "'" );
861
// Read attributes to the memory
862
layer.attributes = (GATT *) malloc ( nRecords * sizeof(GATT) );
866
if ( db_fetch (&databaseCursor, DB_NEXT, &more) != DB_OK ) {
867
std::cout << "Cannot fetch DB record" << std::endl;
870
if ( !more ) break; // no more records
873
dbColumn *column = db_get_table_column (databaseTable, layer.keyColumn);
874
dbValue *value = db_get_column_value(column);
876
if ( db_test_value_isnull(value) ) continue;
877
layer.attributes[layer.nAttributes].cat = db_get_value_int (value);
878
if ( layer.attributes[layer.nAttributes].cat < 0 ) continue;
880
layer.attributes[layer.nAttributes].values = (char **) malloc ( layer.nColumns * sizeof(char*) );
882
for (int i = 0; i < layer.nColumns; i++) {
883
column = db_get_table_column (databaseTable, i);
884
int sqltype = db_get_column_sqltype(column);
885
int ctype = db_sqltype_to_Ctype ( sqltype );
886
value = db_get_column_value(column);
887
db_convert_value_to_string ( value, sqltype, &dbstr);
890
std::cout << "column: " << db_get_column_name(column) << std::endl;
891
std::cout << "value: " << db_get_string(&dbstr) << std::endl;
894
layer.attributes[layer.nAttributes].values[i] = strdup ( db_get_string(&dbstr) );
895
if ( !db_test_value_isnull(value) )
898
if ( ctype == DB_C_TYPE_INT ) {
899
dbl = db_get_value_int ( value );
900
} else if ( ctype == DB_C_TYPE_DOUBLE ) {
901
dbl = db_get_value_double ( value );
906
if ( dbl < layer.minmax[i][0] ) {
907
layer.minmax[i][0] = dbl;
909
if ( dbl > layer.minmax[i][1] ) {
910
layer.minmax[i][1] = dbl;
916
// Sort attributes by category
917
qsort ( layer.attributes, layer.nAttributes, sizeof(GATT), cmpAtt );
919
db_close_cursor (&databaseCursor);
920
db_close_database_shutdown_driver ( databaseDriver );
921
db_free_string(&dbstr);
924
std::cerr << "fields.size = " << layer.fields.size() << std::endl;
925
std::cerr << "number of attributes = " << layer.nAttributes << std::endl;
932
// Add cat if no attribute fields exist (otherwise qgis crashes)
933
if ( layer.nColumns == 0 ) {
935
layer.fields.push_back ( QgsField( "cat", "integer", 10, 0) );
936
layer.minmax = new double[1][2];
937
layer.minmax[0][0] = 0;
938
layer.minmax[0][1] = 0;
940
int cidx = Vect_cidx_get_field_index ( layer.map, layer.field );
942
int ncats, cat, type, id;
944
ncats = Vect_cidx_get_num_cats_by_index ( layer.map, cidx );
947
Vect_cidx_get_cat_by_index ( layer.map, cidx, 0, &cat, &type, &id );
948
layer.minmax[0][0] = cat;
950
Vect_cidx_get_cat_by_index ( layer.map, cidx, ncats-1, &cat, &type, &id );
951
layer.minmax[0][1] = cat;
956
GMAP *map = &(mMaps[layer.mapId]);
958
QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
959
map->lastAttributesModified = di.lastModified();
962
void QgsGrassProvider::closeLayer( int layerId )
965
std::cerr << "Close layer " << layerId << " nUsers = " << mLayers[layerId].nUsers << std::endl;
968
// TODO: not tested because delete is never used for providers
969
mLayers[layerId].nUsers--;
971
if ( mLayers[layerId].nUsers == 0 ) { // No more users, free sources
973
std::cerr << "No more users -> delete layer" << std::endl;
976
mLayers[layerId].valid = false;
978
// Column names/types
979
mLayers[layerId].fields.resize(0);
983
std::cerr << "Delete attribute values" << std::endl;
985
for ( int i = 0; i < mLayers[layerId].nAttributes; i++ ) {
986
free ( mLayers[layerId].attributes[i].values );
988
free ( mLayers[layerId].attributes );
990
delete[] mLayers[layerId].minmax;
993
free ( mLayers[layerId].fieldInfo );
995
closeMap ( mLayers[layerId].mapId );
999
/* returns mapId or -1 on error */
1000
int QgsGrassProvider::openMap(QString gisdbase, QString location, QString mapset, QString mapName)
1003
std::cerr << "QgsGrassProvider::openMap()" << std::endl;
1006
QString tmpPath = gisdbase + "/" + location + "/" + mapset + "/" + mapName;
1008
// Check if this map is already opened
1009
for ( int i = 0; i < mMaps.size(); i++) {
1010
if ( mMaps[i].valid && mMaps[i].path == tmpPath )
1012
// the map is already opened, return map id
1014
std::cerr << "The map is already opened with ID = " << i << std::endl;
1024
map.gisdbase = gisdbase;
1025
map.location = location;
1026
map.mapset = mapset;
1027
map.mapName = mapName;
1032
map.map = (struct Map_info *) malloc ( sizeof(struct Map_info) );
1034
// Set GRASS location
1035
QgsGrass::setLocation ( gisdbase, location );
1037
std::cerr << "Setting gisdbase, location: " << gisdbase.toLocal8Bit().data() << ", " << location.toLocal8Bit().data() << std::endl;
1041
char *ms = G_find_vector2 ( (char *) mapName.ascii(), (char *) mapset.ascii()) ;
1044
std::cerr << "Cannot find GRASS vector" << std::endl;
1048
// Read the time of vector dir before Vect_open_old, because it may take long time (when the vector
1049
// could be owerwritten)
1050
QFileInfo di ( gisdbase + "/" + location + "/" + mapset + "/vector/" + mapName );
1051
map.lastModified = di.lastModified();
1053
di.setFile ( gisdbase + "/" + location + "/" + mapset + "/vector/" + mapName + "/dbln" );
1054
map.lastAttributesModified = di.lastModified();
1056
// Do we have topology and cidx (level2)
1058
QgsGrass::resetError();
1059
Vect_set_open_level (2);
1060
Vect_open_old_head ( map.map, (char *) mapName.ascii(), (char *) mapset.ascii());
1061
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1062
std::cerr << "Cannot open GRASS vector head on level2: "
1063
<< QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1068
Vect_close ( map.map );
1073
int ret = QMessageBox::question ( 0, "Warning",
1074
"GRASS vector map " + mapName +
1075
+ " does not have topology. Build topology?",
1076
QMessageBox::Yes, QMessageBox::No );
1078
if ( ret == QMessageBox::No ) return -1;
1082
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1083
Vect_set_open_level (level);
1084
Vect_open_old ( map.map, (char *) mapName.ascii(), (char *) mapset.ascii());
1086
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1087
std::cerr << "Cannot open GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1093
QgsGrass::resetError();
1094
Vect_build ( map.map, stderr );
1096
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1097
std::cerr << "Cannot build topology: "
1098
<< QgsGrass::getErrorMessage().toLocal8Bit().data()
1105
std::cerr << "GRASS map successfully opened" << std::endl;
1110
// Add new map to maps
1111
mMaps.push_back(map);
1113
return mMaps.size() - 1; // map id
1116
void QgsGrassProvider::updateMap ( int mapId )
1119
std::cerr << "QgsGrassProvider::updateMap() mapId = " << mapId << std::endl;
1123
GMAP *map = &(mMaps[mapId]);
1125
bool closeMap = map->valid;
1129
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1131
// TODO: Should be done better / in other place ?
1132
// TODO: Is it necessary for close ?
1133
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1135
if ( closeMap ) Vect_close ( map->map );
1137
QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName );
1138
map->lastModified = di.lastModified();
1140
di.setFile ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
1141
map->lastAttributesModified = di.lastModified();
1144
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1145
Vect_set_open_level (2);
1146
Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii());
1148
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1149
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1151
// TODO if reopen fails, mLayers should be also updated
1156
std::cerr << "GRASS map successfully reopened for reading." << std::endl;
1159
for ( int i = 0; i < mLayers.size(); i++) {
1160
// if ( !(mLayers[i].valid) ) continue; // ?
1162
if ( mLayers[i].mapId == mapId ) {
1163
loadLayerSourcesFromMap ( mLayers[i] );
1170
void QgsGrassProvider::closeMap( int mapId )
1173
std::cerr << "Close map " << mapId << " nUsers = " << mMaps[mapId].nUsers << std::endl;
1176
// TODO: not tested because delete is never used for providers
1177
mMaps[mapId].nUsers--;
1179
if ( mMaps[mapId].nUsers == 0 ) { // No more users, free sources
1181
std::cerr << "No more users -> delete map" << std::endl;
1184
// TODO: do this better, probably maintain QgsGrassEdit as one user
1185
if ( mMaps[mapId].update ) {
1186
QMessageBox::warning( 0, "Warning", "The vector was currently edited, "
1187
"you can expect crash soon." );
1190
if ( mMaps[mapId].valid )
1192
Vect_close ( mMaps[mapId].map );
1194
mMaps[mapId].valid = false;
1198
bool QgsGrassProvider::mapOutdated( int mapId )
1201
std::cerr << "QgsGrassProvider::mapOutdated()" << std::endl;
1204
GMAP *map = &(mMaps[mapId]);
1206
QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName;
1207
QFileInfo di ( dp );
1209
if ( map->lastModified < di.lastModified() ) {
1211
std::cerr << "**** The map " << mapId << " was modified ****" << std::endl;
1220
bool QgsGrassProvider::attributesOutdated( int mapId )
1223
std::cerr << "QgsGrassProvider::attributesOutdated()" << std::endl;
1226
GMAP *map = &(mMaps[mapId]);
1228
QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln";
1229
QFileInfo di ( dp );
1231
if ( map->lastAttributesModified < di.lastModified() ) {
1233
std::cerr << "**** The attributes of the map " << mapId << " were modified ****" << std::endl;
1242
/** Set feature attributes */
1243
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature )
1246
std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
1248
if ( mLayers[layerId].nColumns > 0 ) {
1253
GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
1254
sizeof(GATT), cmpAtt);
1256
for (int i = 0; i < mLayers[layerId].nColumns; i++) {
1257
if ( att != NULL ) {
1258
Q3CString cstr( att->values[i] );
1259
feature->addAttribute ( mLayers[layerId].fields[i].name(), mEncoding->toUnicode(cstr) );
1260
} else { /* it may happen that attributes are missing -> set to empty string */
1261
feature->addAttribute ( mLayers[layerId].fields[i].name(), "");
1266
tmp.sprintf("%d", cat );
1267
feature->addAttribute ( "cat", tmp);
1271
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature, std::list<int> const& attlist)
1274
std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
1276
if ( mLayers[layerId].nColumns > 0 ) {
1280
GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
1281
sizeof(GATT), cmpAtt);
1283
for (std::list<int>::const_iterator iter=attlist.begin(); iter!=attlist.end();++iter) {
1284
if ( att != NULL ) {
1285
Q3CString cstr( att->values[*iter] );
1286
feature->addAttribute ( mLayers[layerId].fields[*iter].name(), mEncoding->toUnicode(cstr) );
1287
} else { /* it may happen that attributes are missing -> set to empty string */
1288
feature->addAttribute ( mLayers[layerId].fields[*iter].name(), "");
1293
tmp.sprintf("%d", cat );
1294
feature->addAttribute ( "cat", tmp);
1298
/** Get pointer to map */
1299
struct Map_info *QgsGrassProvider::layerMap ( int layerId )
1301
return ( mMaps[mLayers[layerId].mapId].map );
1304
QString QgsGrassProvider::getProjectionWKT(void)
1308
struct Cell_head cellhd;
1310
QgsGrass::setLocation ( mGisdbase, mLocation );
1311
G_get_default_window(&cellhd);
1312
if (cellhd.proj != PROJECTION_XY) {
1313
struct Key_Value *projinfo = G_get_projinfo();
1314
struct Key_Value *projunits = G_get_projunits();
1315
char *wkt = GPJ_grass_to_wkt ( projinfo, projunits, 0, 0 );
1323
int QgsGrassProvider::grassLayer()
1328
int QgsGrassProvider::grassLayer(QString name)
1331
int pos = name.find('_');
1337
return name.left(pos).toInt();
1340
int QgsGrassProvider::grassLayerType(QString name)
1342
int pos = name.find('_');
1348
QString ts = name.right( name.length() - pos - 1 );
1349
if ( ts.compare("point") == 0 ) {
1350
return GV_POINT; // ?! centroids may be points
1351
} else if ( ts.compare("line") == 0 ) {
1353
} else if ( ts.compare("polygon") == 0 ) {
1360
//----------------------------------------- Edit -------------------------------------------------------
1362
bool QgsGrassProvider::isGrassEditable ( void )
1365
std::cerr << "QgsGrassProvider::isGrassEditable" << std::endl;
1371
/* Check if current user is owner of mapset */
1372
if ( G__mapset_permissions2((char*)mGisdbase.ascii(),(char*)mLocation.ascii(),(char*)mMapset.ascii()) != 1 )
1375
// TODO: check format? (cannot edit OGR layers)
1380
bool QgsGrassProvider::isEdited ( void )
1383
std::cerr << "QgsGrassProvider::isEdited" << std::endl;
1386
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1387
return (map->update);
1390
bool QgsGrassProvider::isFrozen ( void )
1393
std::cerr << "QgsGrassProvider::isFrozen" << std::endl;
1396
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1397
return (map->frozen);
1400
void QgsGrassProvider::freeze()
1403
std::cerr << "QgsGrassProvider::freeze" << std::endl;
1406
if ( !isValid() ) return;
1408
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1410
if ( map->frozen ) return;
1413
Vect_close ( map->map );
1416
void QgsGrassProvider::thaw()
1419
std::cerr << "QgsGrassProvider::thaw" << std::endl;
1422
if ( !isValid() ) return;
1423
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1425
if ( !map->frozen ) return;
1429
map->frozen = false;
1433
bool QgsGrassProvider::startEdit ( void )
1436
std::cerr << "QgsGrassProvider::startEdit" << std::endl;
1437
std::cerr << " uri = " << getDataSourceUri().toLocal8Bit().data() << std::endl;
1438
std::cerr << " mMaps.size() = " << mMaps.size() << std::endl;
1441
if ( !isGrassEditable() )
1444
// Check number of maps (the problem may appear if static variables are not shared - runtime linker)
1445
if ( mMaps.size() == 0 ) {
1446
QMessageBox::warning( 0, "Warning", "No maps opened in mMaps, probably problem in runtime linking, "
1447
"static variables are not shared by provider and plugin." );
1452
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1455
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1457
// Set current mapset (mapset was previously checked by isGrassEditable() )
1458
// TODO: Should be done better / in other place ?
1459
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1461
Vect_close ( map->map );
1463
// TODO: Catch error
1465
QgsGrass::resetError();
1466
int level = Vect_open_update ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii() );
1468
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1469
std::cerr << "Cannot open GRASS vector for update: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1471
std::cerr << "Cannot open GRASS vector for update on level 2." << std::endl;
1474
// reopen vector for reading
1475
QgsGrass::resetError();
1476
Vect_set_open_level (2);
1477
level = Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii() );
1480
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1481
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1483
std::cerr << "Cannot reopen GRASS vector on level 2." << std::endl;
1491
Vect_set_category_index_update ( map->map );
1494
Vect_hist_command ( map->map );
1497
std::cerr << "Vector successfully reopened for update." << std::endl;
1506
bool QgsGrassProvider::closeEdit ( bool newMap )
1509
std::cerr << "QgsGrassProvider::closeEdit" << std::endl;
1516
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1518
if ( !(map->update) )
1524
QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() );
1526
// Set current mapset (mapset was previously checked by isGrassEditable() )
1527
// TODO: Should be done better / in other place ?
1528
// TODO: Is it necessary for build/close ?
1529
G__setenv( "MAPSET", (char *) map->mapset.ascii() );
1531
Vect_build_partial ( map->map, GV_BUILD_NONE, NULL);
1532
Vect_build ( map->map, stderr );
1534
// If a new map was created close the map and return
1537
std::cerr << "mLayers.size() = " << mLayers.size() << std::endl;
1538
map->update = false;
1539
// Map must be set as valid otherwise it is not closed and topo is not written
1541
closeLayer( mLayerId );
1545
Vect_close ( map->map );
1547
map->update = false;
1549
if ( !reopenMap() ) return false;
1556
bool QgsGrassProvider::reopenMap()
1558
GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
1560
QFileInfo di ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapName );
1561
map->lastModified = di.lastModified();
1563
di.setFile ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapset + "/dbln" );
1564
map->lastAttributesModified = di.lastModified();
1567
QgsGrass::resetError(); // to "catch" error after Vect_open_old()
1568
Vect_set_open_level (2);
1570
Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii());
1572
if ( QgsGrass::getError() == QgsGrass::FATAL ) {
1573
std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
1578
std::cerr << "GRASS map successfully reopened for reading." << std::endl;
1581
// Reload sources to layers
1582
for ( int i = 0; i < mLayers.size(); i++) {
1583
// if ( !(mLayers[i].valid) ) continue; // ?
1585
if ( mLayers[i].mapId == mLayers[mLayerId].mapId ) {
1586
loadLayerSourcesFromMap ( mLayers[i] );
1593
int QgsGrassProvider::numLines ( void )
1596
std::cerr << "QgsGrassProvider::numLines" << std::endl;
1599
return ( Vect_get_num_lines(mMap) );
1602
int QgsGrassProvider::numNodes ( void )
1605
std::cerr << "QgsGrassProvider::numNodes" << std::endl;
1608
return ( Vect_get_num_nodes(mMap) );
1611
int QgsGrassProvider::readLine ( struct line_pnts *Points, struct line_cats *Cats, int line )
1614
std::cerr << "QgsGrassProvider::readLine" << std::endl;
1618
Vect_reset_line ( Points );
1621
Vect_reset_cats ( Cats );
1623
if ( !Vect_line_alive(mMap, line) ) return -1;
1625
return ( Vect_read_line(mMap, Points, Cats, line) );
1628
bool QgsGrassProvider::nodeCoor ( int node, double *x, double *y )
1631
std::cerr << "QgsGrassProvider::nodeCoor" << std::endl;
1634
if ( !Vect_node_alive ( mMap, node) ) {
1640
Vect_get_node_coor ( mMap, node, x, y, NULL);
1644
bool QgsGrassProvider::lineNodes ( int line, int *node1, int *node2 )
1647
std::cerr << "QgsGrassProvider::lineNodes" << std::endl;
1650
if ( !Vect_line_alive(mMap, line) ) {
1656
Vect_get_line_nodes ( mMap, line, node1, node2 );
1660
int QgsGrassProvider::writeLine ( int type, struct line_pnts *Points, struct line_cats *Cats )
1663
std::cerr << "QgsGrassProvider::writeLine n_points = " << Points->n_points
1664
<< " n_cats = " << Cats->n_cats << std::endl;
1670
return ( (int) Vect_write_line(mMap,type,Points,Cats) );
1673
int QgsGrassProvider::rewriteLine ( int line, int type, struct line_pnts *Points, struct line_cats *Cats )
1676
std::cerr << "QgsGrassProvider::rewriteLine n_points = " << Points->n_points
1677
<< " n_cats = " << Cats->n_cats << std::endl;
1683
return ( Vect_rewrite_line(mMap,line,type,Points,Cats) );
1687
int QgsGrassProvider::deleteLine ( int line )
1690
std::cerr << "QgsGrassProvider::deleteLine" << std::endl;
1696
return ( Vect_delete_line(mMap,line) );
1699
int QgsGrassProvider::findLine ( double x, double y, int type, double threshold )
1702
std::cerr << "QgsGrassProvider::findLine" << std::endl;
1705
return ( Vect_find_line(mMap,x,y,0,type,threshold,0,0) );
1708
int QgsGrassProvider::findNode ( double x, double y, double threshold )
1710
return ( Vect_find_node ( mMap, x, y, 0, threshold, 0 ) );
1713
bool QgsGrassProvider::lineAreas ( int line, int *left, int *right )
1716
std::cerr << "QgsGrassProvider::lineAreas" << std::endl;
1719
if ( !Vect_line_alive(mMap, line) ) {
1725
Vect_get_line_areas ( mMap, line, left, right );
1729
int QgsGrassProvider::centroidArea ( int centroid )
1732
std::cerr << "QgsGrassProvider::centroidArea" << std::endl;
1735
if ( !Vect_line_alive(mMap, centroid) ) {
1739
return ( Vect_get_centroid_area(mMap,centroid) );
1742
int QgsGrassProvider::nodeNLines ( int node )
1745
std::cerr << "QgsGrassProvider::nodeNLines" << std::endl;
1748
if ( !Vect_node_alive(mMap, node) ) {
1752
return ( Vect_get_node_n_lines(mMap,node) );
1755
int QgsGrassProvider::nodeLine ( int node, int idx )
1758
std::cerr << "QgsGrassProvider::nodeLine" << std::endl;
1761
if ( !Vect_node_alive(mMap, node) ) {
1765
return ( Vect_get_node_line(mMap,node,idx) );
1768
int QgsGrassProvider::lineAlive ( int line )
1771
std::cerr << "QgsGrassProvider::lineAlive" << std::endl;
1774
return ( Vect_line_alive(mMap, line) ) ;
1777
int QgsGrassProvider::nodeAlive ( int node )
1780
std::cerr << "QgsGrassProvider::nodeAlive" << std::endl;
1783
return ( Vect_node_alive(mMap, node) ) ;
1786
int QgsGrassProvider::numUpdatedLines ( void )
1789
std::cerr << "QgsGrassProvider::numUpdatedLines" << std::endl;
1790
std::cerr << " numUpdatedLines = " << Vect_get_num_updated_lines(mMap) << std::endl;
1793
return ( Vect_get_num_updated_lines(mMap) ) ;
1796
int QgsGrassProvider::numUpdatedNodes ( void )
1799
std::cerr << "QgsGrassProvider::numUpdatedNodes" << std::endl;
1800
std::cerr << " numUpdatedNodes = " << Vect_get_num_updated_nodes(mMap) << std::endl;
1803
return ( Vect_get_num_updated_nodes(mMap) ) ;
1806
int QgsGrassProvider::updatedLine ( int idx )
1809
std::cerr << "QgsGrassProvider::updatedLine idx = " << idx << std::endl;
1810
std::cerr << " updatedLine = " << Vect_get_updated_line( mMap, idx ) << std::endl;
1813
return ( Vect_get_updated_line( mMap, idx ) ) ;
1816
int QgsGrassProvider::updatedNode ( int idx )
1819
std::cerr << "QgsGrassProvider::updatedNode idx = " << idx << std::endl;
1820
std::cerr << " updatedNode = " << Vect_get_updated_node( mMap, idx ) << std::endl;
1823
return ( Vect_get_updated_node( mMap, idx ) ) ;
1826
// ------------------ Attributes -------------------------------------------------
1828
QString *QgsGrassProvider::key ( int field )
1831
std::cerr << "QgsGrassProvider::key() field = " << field << std::endl;
1834
QString *key = new QString();
1836
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1840
std::cerr << "No field info -> no attributes" << std::endl;
1845
key->setAscii(fi->key);
1849
std::vector<QgsField> *QgsGrassProvider::columns ( int field )
1852
std::cerr << "QgsGrassProvider::columns() field = " << field << std::endl;
1855
std::vector<QgsField> *col = new std::vector<QgsField>;
1857
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1862
std::cerr << "No field info -> no attributes" << std::endl;
1868
std::cerr << "Field info found -> open database" << std::endl;
1870
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1871
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1873
if ( driver == NULL ) {
1874
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1879
std::cerr << "Database opened -> describe table" << std::endl;
1883
db_init_string ( &tableName );
1884
db_set_string ( &tableName, fi->table);
1887
if(db_describe_table (driver, &tableName, &table) != DB_OK) {
1888
std::cerr << "Cannot describe table" << std::endl;
1892
int nCols = db_get_table_number_of_columns(table);
1894
for (int c = 0; c < nCols; c++) {
1895
dbColumn *column = db_get_table_column (table, c);
1897
int ctype = db_sqltype_to_Ctype( db_get_column_sqltype (column) );
1903
case DB_C_TYPE_DOUBLE:
1906
case DB_C_TYPE_STRING:
1909
case DB_C_TYPE_DATETIME:
1913
col->push_back ( QgsField( db_get_column_name (column), type, db_get_column_length(column), 0) );
1916
db_close_database_shutdown_driver ( driver );
1921
std::vector<QgsFeatureAttribute> *QgsGrassProvider::attributes ( int field, int cat )
1924
std::cerr << "QgsGrassProvider::attributes() field = " << field << " cat = " << cat << std::endl;
1927
std::vector<QgsFeatureAttribute> *att = new std::vector<QgsFeatureAttribute>;
1929
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
1934
std::cerr << "No field info -> no attributes" << std::endl;
1940
std::cerr << "Field info found -> open database" << std::endl;
1942
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
1943
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
1945
if ( driver == NULL ) {
1946
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
1951
std::cerr << "Database opened -> read attributes" << std::endl;
1955
db_init_string (&dbstr);
1957
query.sprintf("select * from %s where %s = %d", fi->table, fi->key, cat );
1958
db_set_string (&dbstr, (char *)query.ascii());
1961
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
1964
dbCursor databaseCursor;
1965
if ( db_open_select_cursor(driver, &dbstr, &databaseCursor, DB_SCROLL) != DB_OK ){
1966
db_close_database_shutdown_driver ( driver );
1967
std::cerr << "Cannot select attributes from table" << std::endl;
1971
int nRecords = db_get_num_rows ( &databaseCursor );
1973
std::cerr << "Number of records: " << nRecords << std::endl;
1976
if ( nRecords < 1 ) {
1977
db_close_database_shutdown_driver ( driver );
1978
std::cerr << "No DB record" << std::endl;
1982
dbTable *databaseTable = db_get_cursor_table (&databaseCursor);
1983
int nColumns = db_get_table_number_of_columns(databaseTable);
1986
if ( db_fetch (&databaseCursor, DB_NEXT, &more) != DB_OK ) {
1987
db_close_database_shutdown_driver ( driver );
1988
std::cout << "Cannot fetch DB record" << std::endl;
1992
// Read columns' description
1993
for (int i = 0; i < nColumns; i++) {
1994
dbColumn *column = db_get_table_column (databaseTable, i);
1995
db_convert_column_value_to_string (column, &dbstr);
1997
QString v = mEncoding->toUnicode(db_get_string(&dbstr));
1998
std::cerr << "Value: " << v.toLocal8Bit().data() << std::endl;
1999
att->push_back ( QgsFeatureAttribute( db_get_column_name(column), v ) );
2002
db_close_cursor (&databaseCursor);
2003
db_close_database_shutdown_driver ( driver );
2004
db_free_string(&dbstr);
2009
QString *QgsGrassProvider::updateAttributes ( int field, int cat, const QString &values )
2012
std::cerr << "QgsGrassProvider::updateAttributes() field = " << field << " cat = " << cat << std::endl;
2015
QString *error = new QString();
2016
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2021
std::cerr << "No field info -> no attributes" << std::endl;
2023
error->setLatin1( "Cannot get field info" );
2028
std::cerr << "Field info found -> open database" << std::endl;
2030
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2031
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2033
if ( driver == NULL ) {
2034
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2035
error->setAscii("Cannot open database");
2040
std::cerr << "Database opened -> read attributes" << std::endl;
2044
db_init_string (&dbstr);
2047
query = "update " + QString(fi->table) + " set " + values + " where " + QString(fi->key)
2048
+ " = " + QString::number(cat);
2051
std::cerr << "query: " << query.toLocal8Bit().data() << std::endl;
2054
// For some strange reason, mEncoding->fromUnicode(query) does not work,
2055
// but probably it is not correct, because Qt widgets will use current locales for input
2056
// -> it is possible to edit only in current locales at present
2057
// QCString qcs = mEncoding->fromUnicode(query);
2059
Q3CString qcs = query.toLocal8Bit().data();
2061
std::cerr << "qcs: " << qcs.data() << std::endl;
2064
char *cs = new char[qcs.length() + 1];
2065
strcpy(cs, (const char *)qcs);
2066
db_set_string (&dbstr, cs );
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
int QgsGrassProvider::numDbLinks ( void )
2089
std::cerr << "QgsGrassProvider::numDbLinks()" << std::endl;
2092
return ( Vect_get_num_dblinks(mMap) );
2095
int QgsGrassProvider::dbLinkField ( int link )
2098
std::cerr << "QgsGrassProvider::dbLinkField()" << std::endl;
2101
struct field_info *fi = Vect_get_dblink ( mMap, link );
2103
if ( fi == NULL ) return 0;
2105
return ( fi->number );
2108
QString *QgsGrassProvider::executeSql ( int field, const QString &sql )
2111
std::cerr << "QgsGrassProvider::executeSql field = " << field << std::endl;
2114
QString *error = new QString();
2115
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2120
std::cerr << "No field info -> no attributes" << std::endl;
2122
error->setLatin1( "Cannot get field info" );
2127
std::cerr << "Field info found -> open database" << std::endl;
2130
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2131
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2133
if ( driver == NULL ) {
2134
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2135
error->setAscii("Cannot open database");
2140
std::cerr << "Database opened" << std::endl;
2144
db_init_string (&dbstr);
2145
db_set_string (&dbstr, (char *)sql.latin1());
2148
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2151
int ret = db_execute_immediate (driver, &dbstr);
2153
if ( ret != DB_OK) {
2154
std::cerr << "Error: " << db_get_error_msg() << std::endl;
2155
error->setLatin1( db_get_error_msg() );
2158
db_close_database_shutdown_driver ( driver );
2159
db_free_string(&dbstr);
2165
QString *QgsGrassProvider::createTable ( int field, const QString &key, const QString &columns )
2168
std::cerr << "QgsGrassProvider::createTable() field = " << field << std::endl;
2171
QString *error = new QString();
2172
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2177
std::cerr << "The table for this field already exists" << std::endl;
2179
error->setLatin1( "The table for this field already exists" );
2184
std::cerr << "Field info not found -> create new table" << std::endl;
2187
// We must set mapset before Vect_default_field_info
2188
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2190
int nLinks = Vect_get_num_dblinks( mMap );
2191
if ( nLinks == 0 ) {
2192
fi = Vect_default_field_info ( mMap, field, NULL, GV_1TABLE );
2194
fi = Vect_default_field_info ( mMap, field, NULL, GV_MTABLE );
2197
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2199
if ( driver == NULL ) {
2200
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2201
error->setAscii("Cannot open database");
2206
std::cerr << "Database opened -> create table" << std::endl;
2210
db_init_string (&dbstr);
2213
query.sprintf("create table %s ( %s )", fi->table, columns.latin1() );
2214
db_set_string (&dbstr, (char *)query.latin1());
2217
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2220
int ret = db_execute_immediate (driver, &dbstr);
2222
if ( ret != DB_OK) {
2223
std::cerr << "Error: " << db_get_error_msg() << std::endl;
2224
error->setLatin1( db_get_error_msg() );
2227
db_close_database_shutdown_driver ( driver );
2228
db_free_string(&dbstr);
2230
if ( !error->isEmpty() ) return error;
2232
ret = Vect_map_add_dblink ( mMap, field, NULL, fi->table, (char *)key.latin1(),
2233
fi->database, fi->driver);
2236
std::cerr << "Error: Cannot add dblink" << std::endl;
2237
error->setLatin1( "Cannot create link to the table. The table was created!" );
2243
QString *QgsGrassProvider::addColumn ( int field, const QString &column )
2246
std::cerr << "QgsGrassProvider::addColumn() field = " << field << std::endl;
2249
QString *error = new QString();
2250
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2255
std::cerr << "No field info" << std::endl;
2257
error->setLatin1( "Cannot get field info" );
2263
query.sprintf("alter table %s add column %s", fi->table, column.latin1() );
2266
return executeSql ( field, query );
2269
QString *QgsGrassProvider::insertAttributes ( int field, int cat )
2272
std::cerr << "QgsGrassProvider::insertAttributes() field = " << field << " cat = " << cat << std::endl;
2275
QString *error = new QString();
2276
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2281
std::cerr << "No field info -> no attributes" << std::endl;
2283
error->setLatin1( "Cannot get field info" );
2289
query.sprintf("insert into %s ( %s ) values ( %d )", fi->table, fi->key, cat );
2292
return executeSql ( field, query );
2295
QString *QgsGrassProvider::deleteAttributes ( int field, int cat )
2298
std::cerr << "QgsGrassProvider::deleteAttributes() field = " << field << " cat = " << cat << std::endl;
2301
QString *error = new QString();
2302
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2307
std::cerr << "No field info -> no attributes" << std::endl;
2309
error->setLatin1( "Cannot get field info" );
2315
query.sprintf("delete from %s where %s = %d", fi->table, fi->key, cat );
2318
return executeSql ( field, query );
2321
QString *QgsGrassProvider::isOrphan ( int field, int cat, int *orphan)
2324
std::cerr << "QgsGrassProvider::isOrphan() field = " << field << " cat = " << cat << std::endl;
2327
QString *error = new QString();
2329
// Check first if another line with such cat exists
2330
int fieldIndex = Vect_cidx_get_field_index ( mMap, field );
2331
if ( fieldIndex >= 0 )
2334
int ret = Vect_cidx_find_next ( mMap, fieldIndex, cat,
2335
GV_POINTS|GV_LINES, 0, &t, &id );
2344
// Check if attribute exists
2345
struct field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
2350
std::cerr << "No field info -> no attributes" << std::endl;
2357
std::cerr << "Field info found -> open database" << std::endl;
2359
QgsGrass::setMapset ( mGisdbase, mLocation, mMapset );
2360
dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
2362
if ( driver == NULL ) {
2363
std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
2364
error->setAscii("Cannot open database");
2369
std::cerr << "Database opened -> select record" << std::endl;
2373
db_init_string (&dbstr);
2376
query.sprintf("select %s from %s where %s = %d", fi->key, fi->table, fi->key, cat );
2377
db_set_string (&dbstr, (char *)query.latin1());
2380
std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
2384
if ( db_open_select_cursor(driver, &dbstr, &cursor, DB_SCROLL) != DB_OK )
2386
db_close_database_shutdown_driver ( driver );
2387
error->setAscii("Cannot query database: " + query );
2390
int nRecords = db_get_num_rows ( &cursor );
2392
std::cerr << "Number of records: " << nRecords << std::endl;
2395
if ( nRecords > 0 ) { *orphan = true; }
2397
db_close_database_shutdown_driver ( driver );
2398
db_free_string(&dbstr);
2404
// -------------------------------------------------------------------------------
2406
int QgsGrassProvider::cidxGetNumFields( )
2408
return ( Vect_cidx_get_num_fields(mMap) );
2411
int QgsGrassProvider::cidxGetFieldNumber( int idx )
2413
return ( Vect_cidx_get_field_number(mMap, idx) );
2416
int QgsGrassProvider::cidxGetMaxCat( int idx )
2418
int ncats = Vect_cidx_get_num_cats_by_index ( mMap, idx);
2421
Vect_cidx_get_cat_by_index ( mMap, idx, ncats-1, &cat, &type, &id );
2428
size_t QgsGrassProvider::layerCount() const
2430
return 1; // XXX how to find how many layers?
2431
} // QgsGrassProvider::layerCount()
2435
QString QgsGrassProvider::name() const
2438
} // QgsGrassProvider::name()
2442
QString QgsGrassProvider::description() const
2444
return GRASS_DESCRIPTION;
2445
} // QgsGrassProvider::description()