~ubuntu-branches/ubuntu/hardy/qgis/hardy

« back to all changes in this revision

Viewing changes to src/providers/grass/qgsgrassprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    qgsgrassprovider.cpp -  Data provider for GRASS format
 
3
                             -------------------
 
4
    begin                : March, 2004
 
5
    copyright            : (C) 2004 by Gary E.Sherman, Radim Blazek
 
6
    email                : sherman@mrcc.com, blazek@itc.it
 
7
 ***************************************************************************/
 
8
/***************************************************************************
 
9
 *                                                                         *
 
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.                                   *
 
14
 *                                                                         *
 
15
 ***************************************************************************/
 
16
/* $Id: qgsgrassprovider.cpp 6293 2006-12-21 18:00:15Z rblazek $ */
 
17
 
 
18
#include <string.h>
 
19
#include <iostream>
 
20
#include <vector>
 
21
#include <cfloat>
 
22
 
 
23
#include <qpixmap.h>
 
24
#include <qicon.h>
 
25
#include <qdir.h>
 
26
#include <qstring.h>
 
27
#include <qdatetime.h>
 
28
#include <qmessagebox.h>
 
29
//Added by qt3to4:
 
30
#include <Q3CString>
 
31
 
 
32
#include "qgis.h"
 
33
#include "qgsdataprovider.h"
 
34
#include "qgsfeature.h"
 
35
#include "qgsfield.h"
 
36
#include "qgsrect.h"
 
37
#include "qgsfeatureattribute.h"
 
38
 
 
39
extern "C" {
 
40
#include <grass/gprojects.h>
 
41
#include <grass/gis.h>
 
42
#include <grass/dbmi.h>
 
43
#include <grass/Vect.h>
 
44
}
 
45
 
 
46
#include "qgsgrass.h"
 
47
#include "qgsgrassprovider.h"
 
48
 
 
49
std::vector<GLAYER> QgsGrassProvider::mLayers;
 
50
std::vector<GMAP> QgsGrassProvider::mMaps;
 
51
 
 
52
 
 
53
static QString GRASS_KEY = "grass"; // XXX verify this
 
54
static QString GRASS_DESCRIPTION = "Grass provider"; // XXX verify this
 
55
 
 
56
 
 
57
 
 
58
QgsGrassProvider::QgsGrassProvider(QString const & uri)
 
59
    : QgsVectorDataProvider(uri)
 
60
{
 
61
#ifdef QGISDEBUG
 
62
    std::cerr << "QgsGrassProvider URI: " << uri.toLocal8Bit().data() << std::endl;
 
63
#endif
 
64
 
 
65
    QgsGrass::init();
 
66
 
 
67
    QTime time;
 
68
    time.start();
 
69
 
 
70
    mValid = false;
 
71
    
 
72
    // Parse URI 
 
73
    QDir dir ( uri );  // it is not a directory in fact
 
74
    QString myURI = dir.path();  // no dupl '/'
 
75
 
 
76
    mLayer = dir.dirName();
 
77
    myURI = myURI.left( dir.path().findRev('/') );
 
78
    dir = QDir(myURI);
 
79
    mMapName = dir.dirName();
 
80
    dir.cdUp(); 
 
81
    mMapset = dir.dirName();
 
82
    dir.cdUp(); 
 
83
    mLocation = dir.dirName();
 
84
    dir.cdUp(); 
 
85
    mGisdbase = dir.path();
 
86
    
 
87
    #ifdef QGISDEBUG
 
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;
 
93
    #endif
 
94
 
 
95
    /* Parse Layer, supported layers <field>_point, <field>_line, <field>_area
 
96
    *  Layer is opened even if it is empty (has no features) 
 
97
    */
 
98
    mLayerField = -1;       
 
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;
 
105
    } else {
 
106
        mLayerField = grassLayer ( mLayer );
 
107
        if ( mLayerField == -1 ) {
 
108
            std::cerr << "Invalid layer name, no underscore found: " << mLayer.toLocal8Bit().data() << std::endl;
 
109
            return;
 
110
        }
 
111
 
 
112
        mGrassType = grassLayerType ( mLayer );
 
113
        
 
114
        if ( mGrassType == GV_POINT ) {
 
115
            mLayerType = POINT;
 
116
        } else if ( mGrassType == GV_LINES ) {
 
117
            mLayerType = LINE;
 
118
        } else if ( mGrassType == GV_AREA ) {
 
119
            mLayerType = POLYGON;
 
120
        } else {
 
121
            std::cerr << "Invalid layer name, wrong type: " << mLayer.toLocal8Bit().data() << std::endl;
 
122
            return;
 
123
        }
 
124
        
 
125
    }
 
126
    #ifdef QGISDEBUG
 
127
    std::cerr << "mLayerField: " << mLayerField << std::endl;
 
128
    std::cerr << "mLayerType: " << mLayerType << std::endl;
 
129
    #endif
 
130
 
 
131
    if ( mLayerType == BOUNDARY || mLayerType == CENTROID ) {
 
132
        std::cerr << "Layer type not supported." << std::endl;
 
133
        return;
 
134
    }
 
135
 
 
136
    // Set QGIS type
 
137
    switch ( mLayerType ) {
 
138
        case POINT:
 
139
        case CENTROID:
 
140
            mQgisType = QGis::WKBPoint; 
 
141
            break;
 
142
        case LINE:
 
143
        case BOUNDARY:
 
144
            mQgisType = QGis::WKBLineString; 
 
145
            break;
 
146
        case POLYGON:
 
147
            mQgisType = QGis::WKBPolygon;
 
148
            break;
 
149
    }
 
150
 
 
151
    mLayerId = openLayer(mGisdbase, mLocation, mMapset, mMapName, mLayerField);
 
152
    if ( mLayerId < 0 ) {
 
153
        std::cerr << "Cannot open GRASS layer:" << myURI.toLocal8Bit().data() << std::endl;
 
154
        return;
 
155
    }
 
156
    #ifdef QGISDEBUG
 
157
    std::cerr << "mLayerId: " << mLayerId << std::endl;
 
158
    #endif
 
159
 
 
160
    mMap = layerMap(mLayerId);
 
161
 
 
162
    // Getting the total number of features in the layer
 
163
    mNumberFeatures = 0;
 
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 );
 
170
        }
 
171
    } else {
 
172
        // TODO nofield layers
 
173
        mNumberFeatures = 0;
 
174
        mCidxFieldNumCats = 0;
 
175
    }
 
176
    mNextCidx = 0;
 
177
 
 
178
    #ifdef QGISDEBUG
 
179
    std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
 
180
              << " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
 
181
    #endif
 
182
 
 
183
 
 
184
    // Create selection array
 
185
    mSelectionSize = allocateSelection ( mMap, &mSelection );
 
186
    resetSelection(1); // TODO ? - where what reset
 
187
 
 
188
    mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
 
189
 
 
190
    // Init structures
 
191
    mPoints = Vect_new_line_struct ();
 
192
    mCats = Vect_new_cats_struct ();
 
193
    mList = Vect_new_list ();
 
194
 
 
195
    mValid = true;
 
196
 
 
197
    #ifdef QGISDEBUG
 
198
    std::cerr << "New GRASS layer opened, time (ms): " << time.elapsed() << std::endl;
 
199
    #endif
 
200
}
 
201
 
 
202
void QgsGrassProvider::update ( void )
 
203
{
 
204
    #ifdef QGISDEBUG
 
205
    std::cerr << "*** QgsGrassProvider::update ***" << std::endl;
 
206
    #endif
 
207
 
 
208
    mValid = false;
 
209
 
 
210
    if ( ! mMaps[mLayers[mLayerId].mapId].valid ) return;
 
211
 
 
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)
 
214
    mNumberFeatures = 0;
 
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 );
 
221
        }
 
222
    } else {
 
223
        // TODO nofield layers
 
224
        mNumberFeatures = 0;
 
225
        mCidxFieldNumCats = 0;
 
226
    }
 
227
    mNextCidx = 0;
 
228
 
 
229
    #ifdef QGISDEBUG
 
230
    std::cerr << "mNumberFeatures = " << mNumberFeatures << " mCidxFieldIndex = " << mCidxFieldIndex
 
231
              << " mCidxFieldNumCats = " << mCidxFieldNumCats << std::endl;
 
232
    #endif
 
233
 
 
234
    // Create selection array
 
235
    if ( mSelection ) free ( mSelection );
 
236
    mSelectionSize = allocateSelection ( mMap, &mSelection );
 
237
    resetSelection(1); 
 
238
    
 
239
    mMapVersion = mMaps[mLayers[mLayerId].mapId].version;
 
240
 
 
241
    mValid = true;
 
242
}
 
243
 
 
244
int QgsGrassProvider::allocateSelection( struct Map_info *map, char **selection )
 
245
{
 
246
    int size;
 
247
    #ifdef QGISDEBUG
 
248
    std::cerr << "QgsGrassProvider::allocateSellection" << std::endl;
 
249
    #endif
 
250
    
 
251
    int nlines = Vect_get_num_lines ( map );
 
252
    int nareas = Vect_get_num_areas ( map );
 
253
    
 
254
    if ( nlines > nareas ) {
 
255
        size = nlines + 1;
 
256
    } else {
 
257
        size = nareas + 1;
 
258
    }
 
259
    #ifdef QGISDEBUG
 
260
    std::cerr << "nlines = " << nlines << " nareas = " << nareas << " size = " << size << std::endl;
 
261
    #endif
 
262
 
 
263
    *selection = (char *) malloc ( size );
 
264
 
 
265
    return size;
 
266
}
 
267
 
 
268
QgsGrassProvider::~QgsGrassProvider()
 
269
{
 
270
    #ifdef QGISDEBUG
 
271
    std::cerr << "QgsGrassProvider::~QgsGrassProvider()" << std::endl;
 
272
    #endif
 
273
    closeLayer ( mLayerId );
 
274
}
 
275
 
 
276
 
 
277
QString QgsGrassProvider::storageType()
 
278
{
 
279
  return "GRASS (Geographic Resources Analysis and Support System) file";
 
280
}
 
281
 
 
282
 
 
283
/**
 
284
* Get the first feature resutling from a select operation
 
285
* @return QgsFeature
 
286
*/
 
287
QgsFeature *QgsGrassProvider::getFirstFeature(bool fetchAttributes)
 
288
{
 
289
    #ifdef QGISDEBUG
 
290
    std::cout << "QgsGrassProvider::getFirstFeature()" << std::endl;
 
291
    #endif
 
292
 
 
293
    if ( isEdited() || isFrozen() || !mValid )
 
294
        return 0;
 
295
    
 
296
    if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
 
297
 
 
298
    mNextCidx = 0;
 
299
        
 
300
    return ( getNextFeature(fetchAttributes) );
 
301
}
 
302
 
 
303
/**
 
304
* Get the next feature resulting from a select operation
 
305
* @return false if there are no features in the selection set
 
306
*/
 
307
bool QgsGrassProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes)
 
308
{
 
309
    #if QGISDEBUG > 3
 
310
    std::cout << "QgsGrassProvider::getNextFeature()" << std::endl;
 
311
    #endif
 
312
 
 
313
    if ( isEdited() || isFrozen() || !mValid )
 
314
        return 0;
 
315
    
 
316
    if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
 
317
 
 
318
    // TODO once clear how to do that 
 
319
    return false;
 
320
}
 
321
 
 
322
/**
 
323
* Get the next feature resulting from a select operation
 
324
* Return 0 if there are no features in the selection set
 
325
* @return QgsFeature
 
326
*/
 
327
QgsFeature *QgsGrassProvider::getNextFeature(bool fetchAttributes)
 
328
{
 
329
    #if QGISDEBUG > 3
 
330
    std::cout << "QgsGrassProvider::getNextFeature() mNextCidx = " << mNextCidx 
 
331
              << " fetchAttributes = " << fetchAttributes << std::endl;
 
332
    #endif
 
333
    
 
334
    if ( isEdited() || isFrozen() || !mValid )
 
335
        return 0;
 
336
 
 
337
    if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
 
338
 
 
339
    std::list<int> attlist;
 
340
 
 
341
    if ( fetchAttributes ) {
 
342
        int fc = fieldCount();
 
343
        for ( int i = 0; i < fc; i++ ) {
 
344
            attlist.push_back(i);
 
345
        }
 
346
    }
 
347
 
 
348
    return ( getNextFeature(attlist) );
 
349
}
 
350
 
 
351
QgsFeature* QgsGrassProvider::getNextFeature(std::list<int> const& attlist, int featureQueueSize)
 
352
{
 
353
    int cat, type, id, idx;
 
354
    unsigned char *wkb;
 
355
    int wkbsize;
 
356
 
 
357
    #if QGISDEBUG > 3
 
358
    std::cout << "QgsGrassProvider::getNextFeature( attlist )" << std::endl;
 
359
    #endif
 
360
 
 
361
    if ( isEdited() || isFrozen() || !mValid )
 
362
        return 0;
 
363
    
 
364
    if ( mCidxFieldIndex < 0 ) return 0; // No features, no features in this layer
 
365
    
 
366
    // Get next line/area id
 
367
    int found = 0;
 
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
 
371
 
 
372
        if ( !(type & mGrassType) ) continue;
 
373
        if ( !mSelection[id] ) continue;
 
374
        found = 1;
 
375
        break;
 
376
    }
 
377
    if ( !found ) return 0; // No more features
 
378
    #if QGISDEBUG > 3
 
379
    std::cout << "cat = " << cat << " type = " << type << " id = " << id << std::endl;
 
380
    #endif
 
381
 
 
382
    QgsFeature *f = new QgsFeature(id);
 
383
 
 
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;
 
388
        
 
389
        if ( type & GV_POINTS ) {
 
390
            wkbsize = 1 + 4 + 2*8;
 
391
        } else { // GV_LINES
 
392
            wkbsize = 1+4+4+npoints*2*8;
 
393
        }           
 
394
        wkb = new unsigned char[wkbsize];
 
395
        unsigned char *wkbp = wkb;
 
396
        wkbp[0] = (unsigned char) endian();
 
397
        wkbp += 1;
 
398
 
 
399
        /* WKB type */
 
400
        memcpy (wkbp, &mQgisType, 4);
 
401
        wkbp += 4;
 
402
        
 
403
        /* number of points */
 
404
        if ( type & GV_LINES ) {
 
405
            memcpy (wkbp, &npoints, 4);
 
406
            wkbp += 4;
 
407
        }
 
408
        
 
409
        for ( int i = 0; i < npoints; i++ ) {
 
410
            memcpy (wkbp, &(mPoints->x[i]), 8);
 
411
            memcpy (wkbp+8, &(mPoints->y[i]), 8);
 
412
            wkbp += 16;
 
413
        }
 
414
    } else { // GV_AREA
 
415
        Vect_get_area_points ( mMap, id, mPoints );
 
416
        int npoints = mPoints->n_points;
 
417
 
 
418
        wkbsize = 1+4+4+4+npoints*2*8; // size without islands
 
419
        wkb = new unsigned char[wkbsize];
 
420
        wkb[0] = (unsigned char) endian();
 
421
        int offset = 1;
 
422
 
 
423
        /* WKB type */
 
424
        memcpy ( wkb+offset, &mQgisType, 4);
 
425
        offset += 4;
 
426
 
 
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);
 
431
        offset += 4;
 
432
 
 
433
        /* Outer ring */
 
434
        memcpy (wkb+offset, &npoints, 4);
 
435
        offset += 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);
 
439
            offset += 16;
 
440
        }
 
441
        
 
442
        /* Isles */
 
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;
 
446
            
 
447
            // add space
 
448
            wkbsize += 4+npoints*2*8;
 
449
            wkb = (unsigned char *) realloc (wkb, wkbsize);
 
450
 
 
451
            memcpy (wkb+offset, &npoints, 4);
 
452
            offset += 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);
 
456
                offset += 16;
 
457
            }
 
458
        }
 
459
    }
 
460
 
 
461
    f->setGeometryAndOwnership(wkb, wkbsize);
 
462
 
 
463
    setFeatureAttributes( mLayerId, cat, f, attlist );  
 
464
    
 
465
    return f;
 
466
 
 
467
    return 0;//soon
 
468
}
 
469
 
 
470
void QgsGrassProvider::resetSelection( bool sel)
 
471
{
 
472
    #ifdef QGISDEBUG
 
473
    std::cout << "QgsGrassProvider::resetSelection()" << std::endl;
 
474
    #endif
 
475
    if ( !mValid ) return;
 
476
    memset ( mSelection, (int) sel, mSelectionSize );
 
477
    mNextCidx = 0;
 
478
}
 
479
 
 
480
/**
 
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
 
484
*/
 
485
void QgsGrassProvider::select(QgsRect *rect, bool useIntersect)
 
486
{
 
487
    #ifdef QGISDEBUG
 
488
    std::cout << "QgsGrassProvider::select() useIntersect = " << useIntersect << std::endl;
 
489
    #endif
 
490
 
 
491
    if ( isEdited() || isFrozen() || !mValid )
 
492
        return;
 
493
 
 
494
    // check if outdated and update if necessary
 
495
    int mapId = mLayers[mLayerId].mapId;
 
496
    if ( mapOutdated(mapId) ) {
 
497
        updateMap ( mapId );
 
498
    }
 
499
    if ( mMapVersion < mMaps[mapId].version ) {
 
500
        update();
 
501
    }
 
502
    if ( attributesOutdated(mapId) ) {
 
503
        loadAttributes (mLayers[mLayerId]);
 
504
    }
 
505
 
 
506
    resetSelection(0);
 
507
    
 
508
    if ( !useIntersect ) { // select by bounding boxes only
 
509
        BOUND_BOX box;
 
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);
 
517
        }
 
518
 
 
519
    } else { // check intersection
 
520
        struct line_pnts *Polygon;
 
521
        
 
522
        Polygon = Vect_new_line_struct();
 
523
 
 
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);
 
529
 
 
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);
 
534
        }
 
535
 
 
536
        Vect_destroy_line_struct (Polygon);
 
537
    }
 
538
    for ( int i = 0; i < mList->n_values; i++ ) {
 
539
        if ( mList->value[i] <= mSelectionSize ) {
 
540
            mSelection[mList->value[i]] = 1;
 
541
        } else {
 
542
            std::cerr << "Selected element out of range" << std::endl;
 
543
        }
 
544
    }
 
545
        
 
546
    #ifdef QGISDEBUG
 
547
    std::cout << mList->n_values << " features selected" << std::endl;
 
548
    #endif
 
549
}
 
550
 
 
551
 
 
552
/**
 
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
 
556
*/
 
557
std::vector<QgsFeature>& QgsGrassProvider::identify(QgsRect * rect)
 
558
{
 
559
    #ifdef QGISDEBUG
 
560
    std::cout << "QgsGrassProvider::identify()" << std::endl;
 
561
    #endif
 
562
 
 
563
    // TODO: does not return vector of features! Should it?
 
564
 
 
565
    if ( !isEdited() && !isFrozen() && mValid ) {
 
566
        select(rect, true);
 
567
    }
 
568
}
 
569
 
 
570
QgsRect *QgsGrassProvider::extent()
 
571
{
 
572
    BOUND_BOX box;
 
573
    Vect_get_map_box ( mMap, &box );
 
574
 
 
575
    return new QgsRect( box.W, box.S, box.E, box.N);
 
576
}
 
577
 
 
578
/** 
 
579
* Return the feature type
 
580
*/
 
581
int QgsGrassProvider::geometryType() const
 
582
{
 
583
    return mQgisType;
 
584
}
 
585
/** 
 
586
* Return the feature type
 
587
*/
 
588
long QgsGrassProvider::featureCount() const 
 
589
{
 
590
    return mNumberFeatures;
 
591
}
 
592
 
 
593
/**
 
594
* Return the number of fields
 
595
*/
 
596
int QgsGrassProvider::fieldCount() const
 
597
{
 
598
    #ifdef QGISDEBUG
 
599
    std::cerr << "QgsGrassProvider::fieldCount() return:" << mLayers[mLayerId].fields.size() << std::endl;
 
600
    #endif
 
601
    return mLayers[mLayerId].fields.size();
 
602
}
 
603
 
 
604
/**
 
605
* Return fields
 
606
*/
 
607
std::vector<QgsField> const & QgsGrassProvider::fields() const
 
608
{
 
609
      return mLayers[mLayerId].fields;
 
610
}
 
611
 
 
612
int QgsGrassProvider::keyField()
 
613
{
 
614
      return mLayers[mLayerId].keyColumn;
 
615
}
 
616
 
 
617
void QgsGrassProvider::reset()
 
618
{
 
619
    if ( isEdited() || isFrozen() || !mValid )
 
620
        return;
 
621
 
 
622
    int mapId = mLayers[mLayerId].mapId;
 
623
    if ( mapOutdated(mapId) ) {
 
624
        updateMap ( mapId );
 
625
    }
 
626
    if ( mMapVersion < mMaps[mapId].version ) {
 
627
        update();
 
628
    }
 
629
    if ( attributesOutdated(mapId) ) {
 
630
        loadAttributes (mLayers[mLayerId]);
 
631
    }
 
632
    
 
633
    resetSelection(1);
 
634
    mNextCidx = 0;
 
635
}
 
636
 
 
637
QString QgsGrassProvider::minValue(int position)
 
638
{
 
639
    if ( position >= fieldCount() ) {
 
640
        std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::minValue()" 
 
641
                  << std::endl;
 
642
    }
 
643
    return QString::number( mLayers[mLayerId].minmax[position][0], 'f', 2 );
 
644
}
 
645
 
 
646
 
 
647
QString QgsGrassProvider::maxValue(int position)
 
648
{
 
649
    if ( position >= fieldCount() ) {
 
650
        std::cerr << "Warning: access requested to invalid position in QgsGrassProvider::maxValue()" 
 
651
                  << std::endl;
 
652
    }
 
653
    return QString::number( mLayers[mLayerId].minmax[position][1], 'f', 2 );
 
654
}
 
655
 
 
656
bool QgsGrassProvider::isValid(){
 
657
    #ifdef QGISDEBUG
 
658
    QString validString = mValid?"true":"false";
 
659
    std::cerr << "QgsGrassProvider::isValid() returned: " << validString.toLocal8Bit().data() << std::endl;
 
660
    #endif
 
661
    return mValid;
 
662
}
 
663
 
 
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);
 
670
}
 
671
 
 
672
/* returns layerId or -1 on error */
 
673
int QgsGrassProvider::openLayer(QString gisdbase, QString location, QString mapset, QString mapName, int field)
 
674
{
 
675
    #ifdef QGISDEBUG
 
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;
 
682
    #endif
 
683
 
 
684
    // Check if this layer is already opened
 
685
 
 
686
    for ( int i = 0; i <  mLayers.size(); i++) {
 
687
        if ( !(mLayers[i].valid) ) continue;
 
688
 
 
689
        GMAP *mp = &(mMaps[mLayers[i].mapId]);
 
690
 
 
691
        if ( mp->gisdbase == gisdbase && mp->location == location && 
 
692
             mp->mapset == mapset && mp->mapName == mapName && mLayers[i].field == field )
 
693
        {
 
694
            // the layer already exists, return layer id
 
695
            #ifdef QGISDEBUG
 
696
            std::cerr << "The layer is already opened with ID = " << i << std::endl;
 
697
            #endif
 
698
            mLayers[i].nUsers++;
 
699
            return i;
 
700
        }
 
701
    }
 
702
 
 
703
    // Create a new layer
 
704
    GLAYER layer;
 
705
    layer.valid = false;
 
706
    layer.field = field; 
 
707
    layer.nUsers = 1; 
 
708
 
 
709
    // Open map
 
710
    layer.mapId = openMap ( gisdbase, location, mapset, mapName );
 
711
    if ( layer.mapId < 0 ) {
 
712
        std::cerr << "Cannot open vector map" << std::endl;
 
713
        return -1;
 
714
    }
 
715
    #ifdef QGISDEBUG
 
716
    std::cerr << "layer.mapId = " << layer.mapId << std::endl;
 
717
    #endif
 
718
    layer.map = mMaps[layer.mapId].map;
 
719
 
 
720
    layer.attributes = 0; // because loadLayerSourcesFromMap will release old
 
721
    loadLayerSourcesFromMap ( layer );
 
722
 
 
723
    layer.valid = true;
 
724
 
 
725
    // Add new layer to layers
 
726
    mLayers.push_back(layer);
 
727
        
 
728
    #ifdef QGISDEBUG
 
729
    std::cerr << "New layer successfully opened" << layer.nAttributes << std::endl;
 
730
    #endif
 
731
        
 
732
    return mLayers.size() - 1; 
 
733
}
 
734
 
 
735
void QgsGrassProvider::loadLayerSourcesFromMap ( GLAYER &layer )
 
736
{
 
737
    #ifdef QGISDEBUG
 
738
    std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
 
739
    #endif
 
740
 
 
741
    // Reset and free 
 
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] );
 
748
            }
 
749
            free ( layer.attributes[i].values );
 
750
        }
 
751
        free ( layer.attributes );
 
752
    }
 
753
    loadAttributes ( layer );
 
754
}
 
755
    
 
756
void QgsGrassProvider::loadAttributes ( GLAYER &layer )
 
757
{
 
758
    #ifdef QGISDEBUG
 
759
    std::cerr << "QgsGrassProvider::loadLayerSourcesFromMap" << std::endl;
 
760
    #endif
 
761
 
 
762
    // TODO: free old attributes
 
763
    
 
764
    if ( !layer.map ) return;
 
765
 
 
766
    // Get field info
 
767
    layer.fieldInfo = Vect_get_field( layer.map, layer.field); // should work also with field = 0
 
768
 
 
769
    // Read attributes
 
770
    layer.nColumns = 0;
 
771
    layer.nAttributes = 0;
 
772
    layer.attributes = 0;
 
773
    layer.fields.clear();
 
774
    layer.keyColumn = -1;
 
775
    if ( layer.fieldInfo == NULL ) {
 
776
        #ifdef QGISDEBUG
 
777
        std::cerr << "No field info -> no attribute table" << std::endl;
 
778
        #endif
 
779
    } else { 
 
780
        #ifdef QGISDEBUG
 
781
        std::cerr << "Field info found -> open database" << std::endl;
 
782
        #endif
 
783
        dbDriver *databaseDriver = db_start_driver_open_database ( layer.fieldInfo->driver, 
 
784
                                                                   layer.fieldInfo->database );
 
785
 
 
786
        if ( databaseDriver == NULL ) {
 
787
            std::cerr << "Cannot open database " << layer.fieldInfo->database << " by driver " 
 
788
                      << layer.fieldInfo->driver << std::endl;
 
789
        } else {
 
790
            #ifdef QGISDEBUG
 
791
            std::cerr << "Database opened -> open select cursor" << std::endl;
 
792
            #endif
 
793
            dbString dbstr; 
 
794
            db_init_string (&dbstr);
 
795
            db_set_string (&dbstr, "select * from ");
 
796
            db_append_string (&dbstr, layer.fieldInfo->table);
 
797
            
 
798
            #ifdef QGISDEBUG
 
799
            std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
800
            #endif
 
801
            dbCursor databaseCursor;
 
802
            if ( db_open_select_cursor(databaseDriver, &dbstr, &databaseCursor, DB_SCROLL) != DB_OK ){
 
803
                layer.nColumns = 0;
 
804
                db_close_database_shutdown_driver ( databaseDriver );
 
805
                QMessageBox::warning( 0, "Warning", "Cannot select attributes from table '" + 
 
806
                                 QString(layer.fieldInfo->table) + "'" );
 
807
            } else {
 
808
                int nRecords = db_get_num_rows ( &databaseCursor );
 
809
                #ifdef QGISDEBUG
 
810
                std::cerr << "Number of records: " << nRecords << std::endl;
 
811
                #endif
 
812
                
 
813
                dbTable  *databaseTable = db_get_cursor_table (&databaseCursor);
 
814
                layer.nColumns = db_get_table_number_of_columns(databaseTable);
 
815
 
 
816
                layer.minmax = new double[layer.nColumns][2];
 
817
 
 
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;
 
822
 
 
823
                    dbColumn *column = db_get_table_column (databaseTable, i);
 
824
 
 
825
                    int ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) );
 
826
                    #ifdef QGISDEBUG
 
827
                    std::cerr << "column = " << db_get_column_name(column) 
 
828
                              << " ctype = " << ctype << std::endl;
 
829
                    #endif
 
830
                    
 
831
                    QString ctypeStr;
 
832
                    switch ( ctype ) {
 
833
                        case DB_C_TYPE_INT:
 
834
                            ctypeStr = "integer";
 
835
                            break; 
 
836
                        case DB_C_TYPE_DOUBLE:
 
837
                            ctypeStr = "double";
 
838
                            break; 
 
839
                        case DB_C_TYPE_STRING:
 
840
                            ctypeStr = "string";
 
841
                            break; 
 
842
                        case DB_C_TYPE_DATETIME:
 
843
                            ctypeStr = "datetime";
 
844
                            break; 
 
845
                    }
 
846
                    layer.fields.push_back ( QgsField( db_get_column_name(column), ctypeStr, 
 
847
                                     db_get_column_length(column), db_get_column_precision(column) ) );
 
848
                    
 
849
                    if ( G_strcasecmp ( db_get_column_name(column), layer.fieldInfo->key) == 0 ) {
 
850
                        layer.keyColumn = i;
 
851
                    }
 
852
                }
 
853
    
 
854
                if ( layer.keyColumn < 0 ) {
 
855
                    layer.fields.clear();
 
856
                    layer.nColumns = 0;
 
857
 
 
858
                    QMessageBox::warning( 0, "Warning", "Key column '" + QString(layer.fieldInfo->key) + 
 
859
                                 "' not found in the table '" + QString(layer.fieldInfo->table) + "'" );
 
860
                } else {
 
861
                    // Read attributes to the memory
 
862
                    layer.attributes = (GATT *) malloc ( nRecords * sizeof(GATT) );
 
863
                    while ( 1 ) {
 
864
                        int more;
 
865
                                
 
866
                        if ( db_fetch (&databaseCursor, DB_NEXT, &more) != DB_OK ) {
 
867
                            std::cout << "Cannot fetch DB record" << std::endl;
 
868
                            break;
 
869
                        }
 
870
                        if ( !more ) break; // no more records
 
871
 
 
872
                        // Check cat value
 
873
                        dbColumn *column = db_get_table_column (databaseTable, layer.keyColumn);
 
874
                        dbValue *value = db_get_column_value(column);
 
875
                        
 
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; 
 
879
 
 
880
                        layer.attributes[layer.nAttributes].values = (char **) malloc ( layer.nColumns * sizeof(char*) );
 
881
 
 
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);
 
888
 
 
889
                            #if QGISDEBUG > 3
 
890
                            std::cout << "column: " << db_get_column_name(column) << std::endl;
 
891
                            std::cout << "value: " << db_get_string(&dbstr) << std::endl;
 
892
                            #endif
 
893
 
 
894
                            layer.attributes[layer.nAttributes].values[i] = strdup ( db_get_string(&dbstr) );
 
895
                            if ( !db_test_value_isnull(value) )
 
896
                            {
 
897
                                double dbl;
 
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 );
 
902
                                } else {
 
903
                                    dbl = 0;
 
904
                                }
 
905
                                
 
906
                                if ( dbl < layer.minmax[i][0] ) {
 
907
                                    layer.minmax[i][0] = dbl;
 
908
                                }
 
909
                                if ( dbl > layer.minmax[i][1] ) {
 
910
                                    layer.minmax[i][1] = dbl;
 
911
                                }
 
912
                            }
 
913
                        }
 
914
                        layer.nAttributes++;
 
915
                    }
 
916
                    // Sort attributes by category
 
917
                    qsort ( layer.attributes, layer.nAttributes, sizeof(GATT), cmpAtt );
 
918
                }
 
919
                db_close_cursor (&databaseCursor);
 
920
                db_close_database_shutdown_driver ( databaseDriver );
 
921
                db_free_string(&dbstr);
 
922
 
 
923
                #ifdef QGISDEBUG
 
924
                std::cerr << "fields.size = " << layer.fields.size() << std::endl;
 
925
                std::cerr << "number of attributes = " << layer.nAttributes << std::endl;
 
926
                #endif
 
927
 
 
928
            }
 
929
        }
 
930
    }
 
931
 
 
932
    // Add cat if no attribute fields exist (otherwise qgis crashes)
 
933
    if ( layer.nColumns == 0 ) {
 
934
        layer.keyColumn = 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; 
 
939
 
 
940
        int cidx = Vect_cidx_get_field_index ( layer.map, layer.field );
 
941
        if ( cidx >= 0 ) {
 
942
            int ncats, cat, type, id;
 
943
            
 
944
            ncats = Vect_cidx_get_num_cats_by_index ( layer.map, cidx );
 
945
 
 
946
            if ( ncats > 0 ) {
 
947
                Vect_cidx_get_cat_by_index ( layer.map, cidx, 0, &cat, &type, &id );
 
948
                layer.minmax[0][0] = cat; 
 
949
 
 
950
                Vect_cidx_get_cat_by_index ( layer.map, cidx, ncats-1, &cat, &type, &id );
 
951
                layer.minmax[0][1] = cat; 
 
952
            }
 
953
        }
 
954
    }
 
955
 
 
956
    GMAP *map = &(mMaps[layer.mapId]);
 
957
    
 
958
    QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
 
959
    map->lastAttributesModified = di.lastModified();
 
960
}
 
961
 
 
962
void QgsGrassProvider::closeLayer( int layerId )
 
963
{
 
964
    #ifdef QGISDEBUG
 
965
    std::cerr << "Close layer " << layerId << " nUsers = " << mLayers[layerId].nUsers << std::endl;
 
966
    #endif
 
967
 
 
968
    // TODO: not tested because delete is never used for providers
 
969
    mLayers[layerId].nUsers--;
 
970
 
 
971
    if ( mLayers[layerId].nUsers == 0 ) { // No more users, free sources
 
972
        #ifdef QGISDEBUG
 
973
        std::cerr << "No more users -> delete layer" << std::endl;
 
974
        #endif
 
975
 
 
976
        mLayers[layerId].valid = false;
 
977
 
 
978
        // Column names/types
 
979
        mLayers[layerId].fields.resize(0);
 
980
        
 
981
        // Attributes
 
982
        #ifdef QGISDEBUG
 
983
        std::cerr << "Delete attribute values" << std::endl;
 
984
        #endif
 
985
        for ( int i = 0; i < mLayers[layerId].nAttributes; i++ ) {
 
986
            free ( mLayers[layerId].attributes[i].values );
 
987
        }
 
988
        free ( mLayers[layerId].attributes );
 
989
                
 
990
        delete[] mLayers[layerId].minmax;
 
991
 
 
992
        // Field info
 
993
        free ( mLayers[layerId].fieldInfo );
 
994
 
 
995
        closeMap ( mLayers[layerId].mapId );
 
996
    }
 
997
}
 
998
 
 
999
/* returns mapId or -1 on error */
 
1000
int QgsGrassProvider::openMap(QString gisdbase, QString location, QString mapset, QString mapName)
 
1001
{
 
1002
    #ifdef QGISDEBUG
 
1003
    std::cerr << "QgsGrassProvider::openMap()" << std::endl;
 
1004
    #endif
 
1005
 
 
1006
    QString tmpPath = gisdbase + "/" + location + "/" + mapset + "/" + mapName;
 
1007
 
 
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 ) 
 
1011
        {
 
1012
            // the map is already opened, return map id
 
1013
            #ifdef QGISDEBUG
 
1014
            std::cerr << "The map is already opened with ID = " << i << std::endl;
 
1015
            #endif
 
1016
            mMaps[i].nUsers++;
 
1017
            return i;
 
1018
        }
 
1019
    }
 
1020
 
 
1021
    GMAP map;
 
1022
    map.valid = false;
 
1023
    map.frozen = false;
 
1024
    map.gisdbase = gisdbase;
 
1025
    map.location = location;
 
1026
    map.mapset = mapset;
 
1027
    map.mapName = mapName;
 
1028
    map.path = tmpPath;
 
1029
    map.nUsers = 1;
 
1030
    map.version = 1;
 
1031
    map.update = 0;
 
1032
    map.map = (struct Map_info *) malloc ( sizeof(struct Map_info) );
 
1033
 
 
1034
    // Set GRASS location
 
1035
    QgsGrass::setLocation ( gisdbase, location ); 
 
1036
#ifdef QGISDEBUG
 
1037
        std::cerr << "Setting  gisdbase, location: " << gisdbase.toLocal8Bit().data() << ", " << location.toLocal8Bit().data() << std::endl;
 
1038
#endif
 
1039
 
 
1040
    // Find the vector
 
1041
    char *ms = G_find_vector2 ( (char *) mapName.ascii(), (char *) mapset.ascii()) ;
 
1042
 
 
1043
    if ( ms == NULL) {
 
1044
        std::cerr << "Cannot find GRASS vector" << std::endl;
 
1045
        return -1;
 
1046
    }
 
1047
 
 
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();
 
1052
    
 
1053
    di.setFile ( gisdbase + "/" + location + "/" + mapset + "/vector/" + mapName + "/dbln" );
 
1054
    map.lastAttributesModified = di.lastModified();
 
1055
 
 
1056
    // Do we have topology and cidx (level2)
 
1057
    int level = 2;
 
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;
 
1064
        level = 1;
 
1065
    }
 
1066
    else
 
1067
    {
 
1068
        Vect_close ( map.map );
 
1069
    }
 
1070
 
 
1071
    if ( level == 1 )
 
1072
    {
 
1073
        int ret = QMessageBox::question ( 0, "Warning",
 
1074
                      "GRASS vector map " + mapName + 
 
1075
                      + " does not have topology. Build topology?",
 
1076
                      QMessageBox::Yes,  QMessageBox::No );
 
1077
 
 
1078
        if ( ret == QMessageBox::No ) return -1;
 
1079
    }
 
1080
 
 
1081
    // Open vector
 
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());
 
1085
 
 
1086
    if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1087
        std::cerr << "Cannot open GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
 
1088
        return -1;
 
1089
    }
 
1090
 
 
1091
    if ( level == 1 )
 
1092
    {
 
1093
        QgsGrass::resetError();
 
1094
        Vect_build ( map.map, stderr );
 
1095
 
 
1096
        if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1097
            std::cerr << "Cannot build topology: " 
 
1098
                      << QgsGrass::getErrorMessage().toLocal8Bit().data() 
 
1099
                      << std::endl;
 
1100
            return -1;
 
1101
        }
 
1102
    }
 
1103
 
 
1104
    #ifdef QGISDEBUG
 
1105
    std::cerr << "GRASS map successfully opened" << std::endl;
 
1106
    #endif
 
1107
    
 
1108
    map.valid = true;
 
1109
 
 
1110
    // Add new map to maps
 
1111
    mMaps.push_back(map);
 
1112
 
 
1113
    return mMaps.size() - 1; // map id 
 
1114
}
 
1115
 
 
1116
void QgsGrassProvider::updateMap ( int mapId )
 
1117
{
 
1118
    #ifdef QGISDEBUG
 
1119
    std::cerr << "QgsGrassProvider::updateMap() mapId = " << mapId << std::endl;
 
1120
    #endif
 
1121
 
 
1122
    /* Close map */
 
1123
    GMAP *map = &(mMaps[mapId]);
 
1124
 
 
1125
    bool closeMap = map->valid;
 
1126
    map->valid = false;
 
1127
    map->version++;
 
1128
 
 
1129
    QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() ); 
 
1130
 
 
1131
    // TODO: Should be done better / in other place ?
 
1132
    // TODO: Is it necessary for close ?
 
1133
    G__setenv( "MAPSET", (char *) map->mapset.ascii() );
 
1134
    
 
1135
    if ( closeMap ) Vect_close ( map->map );
 
1136
 
 
1137
    QFileInfo di ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName );
 
1138
    map->lastModified = di.lastModified();
 
1139
 
 
1140
    di.setFile ( map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln" );
 
1141
    map->lastAttributesModified = di.lastModified();
 
1142
 
 
1143
    // Reopen vector
 
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());
 
1147
 
 
1148
    if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1149
        std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
 
1150
 
 
1151
        // TODO if reopen fails, mLayers should be also updated
 
1152
        return;
 
1153
    }
 
1154
 
 
1155
    #ifdef QGISDEBUG
 
1156
    std::cerr << "GRASS map successfully reopened for reading." << std::endl;
 
1157
    #endif
 
1158
 
 
1159
    for ( int i = 0; i <  mLayers.size(); i++) {
 
1160
        // if ( !(mLayers[i].valid) ) continue; // ?
 
1161
 
 
1162
        if  ( mLayers[i].mapId == mapId ) {
 
1163
            loadLayerSourcesFromMap ( mLayers[i] );
 
1164
        }
 
1165
    }
 
1166
 
 
1167
    map->valid = true;
 
1168
}
 
1169
 
 
1170
void QgsGrassProvider::closeMap( int mapId )
 
1171
{
 
1172
    #ifdef QGISDEBUG
 
1173
    std::cerr << "Close map " << mapId << " nUsers = " << mMaps[mapId].nUsers << std::endl;
 
1174
    #endif
 
1175
 
 
1176
    // TODO: not tested because delete is never used for providers
 
1177
    mMaps[mapId].nUsers--;
 
1178
 
 
1179
    if ( mMaps[mapId].nUsers == 0 ) { // No more users, free sources
 
1180
        #ifdef QGISDEBUG
 
1181
        std::cerr << "No more users -> delete map" << std::endl;
 
1182
        #endif
 
1183
 
 
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." );
 
1188
        }
 
1189
 
 
1190
        if ( mMaps[mapId].valid )
 
1191
        {
 
1192
            Vect_close ( mMaps[mapId].map );
 
1193
        }
 
1194
        mMaps[mapId].valid = false;
 
1195
    }
 
1196
}
 
1197
 
 
1198
bool QgsGrassProvider::mapOutdated( int mapId )
 
1199
{
 
1200
    #ifdef QGISDEBUG
 
1201
    std::cerr << "QgsGrassProvider::mapOutdated()" << std::endl;
 
1202
    #endif
 
1203
 
 
1204
    GMAP *map = &(mMaps[mapId]);
 
1205
    
 
1206
    QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName;
 
1207
    QFileInfo di ( dp );
 
1208
 
 
1209
    if ( map->lastModified < di.lastModified() ) {
 
1210
        #ifdef QGISDEBUG
 
1211
        std::cerr << "**** The map " << mapId << " was modified ****" << std::endl;
 
1212
        #endif
 
1213
        
 
1214
        return true;
 
1215
    }
 
1216
 
 
1217
    return false;
 
1218
}
 
1219
 
 
1220
bool QgsGrassProvider::attributesOutdated( int mapId )
 
1221
{
 
1222
    #ifdef QGISDEBUG
 
1223
    std::cerr << "QgsGrassProvider::attributesOutdated()" << std::endl;
 
1224
    #endif
 
1225
 
 
1226
    GMAP *map = &(mMaps[mapId]);
 
1227
    
 
1228
    QString dp = map->gisdbase + "/" + map->location + "/" + map->mapset + "/vector/" + map->mapName + "/dbln";
 
1229
    QFileInfo di ( dp );
 
1230
 
 
1231
    if ( map->lastAttributesModified < di.lastModified() ) {
 
1232
        #ifdef QGISDEBUG
 
1233
        std::cerr << "**** The attributes of the map " << mapId << " were modified ****" << std::endl;
 
1234
        #endif
 
1235
        
 
1236
        return true;
 
1237
    }
 
1238
 
 
1239
    return false;
 
1240
}
 
1241
 
 
1242
/** Set feature attributes */
 
1243
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature )
 
1244
{
 
1245
    #if QGISDEBUG > 3
 
1246
    std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
 
1247
    #endif
 
1248
    if ( mLayers[layerId].nColumns > 0 ) {
 
1249
        // find cat
 
1250
        GATT key;
 
1251
        key.cat = cat;
 
1252
    
 
1253
        GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
 
1254
                                       sizeof(GATT), cmpAtt);
 
1255
 
 
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(), "");
 
1262
            }
 
1263
        }
 
1264
    } else { 
 
1265
        QString tmp;
 
1266
        tmp.sprintf("%d", cat );
 
1267
        feature->addAttribute ( "cat", tmp);
 
1268
    }
 
1269
}
 
1270
 
 
1271
void QgsGrassProvider::setFeatureAttributes ( int layerId, int cat, QgsFeature *feature, std::list<int> const& attlist)
 
1272
{
 
1273
    #if QGISDEBUG > 3
 
1274
    std::cerr << "setFeatureAttributes cat = " << cat << std::endl;
 
1275
    #endif
 
1276
    if ( mLayers[layerId].nColumns > 0 ) {
 
1277
        // find cat
 
1278
        GATT key;
 
1279
        key.cat = cat;
 
1280
        GATT *att = (GATT *) bsearch ( &key, mLayers[layerId].attributes, mLayers[layerId].nAttributes,
 
1281
                                       sizeof(GATT), cmpAtt);
 
1282
 
 
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(), "");     
 
1289
            } 
 
1290
        }
 
1291
    } else { 
 
1292
        QString tmp;
 
1293
        tmp.sprintf("%d", cat );
 
1294
        feature->addAttribute ( "cat", tmp);
 
1295
    }
 
1296
}
 
1297
 
 
1298
/** Get pointer to map */
 
1299
struct Map_info *QgsGrassProvider::layerMap ( int layerId )
 
1300
{
 
1301
    return ( mMaps[mLayers[layerId].mapId].map );
 
1302
}
 
1303
 
 
1304
QString QgsGrassProvider::getProjectionWKT(void)
 
1305
{
 
1306
    QString WKT;
 
1307
 
 
1308
    struct Cell_head cellhd;
 
1309
 
 
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 );
 
1316
        WKT = QString(wkt);
 
1317
        free ( wkt);
 
1318
    }
 
1319
    
 
1320
    return WKT;
 
1321
}
 
1322
 
 
1323
int QgsGrassProvider::grassLayer()
 
1324
{
 
1325
        return mLayerField;
 
1326
}
 
1327
 
 
1328
int QgsGrassProvider::grassLayer(QString name)
 
1329
{
 
1330
    // Get field number
 
1331
    int pos = name.find('_');
 
1332
 
 
1333
    if ( pos == -1 ) {
 
1334
        return -1;
 
1335
    }
 
1336
 
 
1337
    return name.left(pos).toInt();
 
1338
}
 
1339
 
 
1340
int QgsGrassProvider::grassLayerType(QString name)
 
1341
{
 
1342
    int pos = name.find('_');
 
1343
 
 
1344
    if ( pos == -1 ) {
 
1345
        return -1;
 
1346
    }
 
1347
 
 
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 ) {
 
1352
        return GV_LINES; 
 
1353
    } else if ( ts.compare("polygon") == 0 ) {
 
1354
        return GV_AREA; 
 
1355
    }
 
1356
 
 
1357
    return -1;
 
1358
}
 
1359
 
 
1360
//-----------------------------------------  Edit -------------------------------------------------------
 
1361
 
 
1362
bool QgsGrassProvider::isGrassEditable ( void )
 
1363
{
 
1364
    #ifdef QGISDEBUG
 
1365
    std::cerr << "QgsGrassProvider::isGrassEditable" << std::endl;
 
1366
    #endif
 
1367
 
 
1368
    if ( !isValid() ) 
 
1369
        return false;
 
1370
 
 
1371
    /* Check if current user is owner of mapset */
 
1372
    if ( G__mapset_permissions2((char*)mGisdbase.ascii(),(char*)mLocation.ascii(),(char*)mMapset.ascii()) != 1 )
 
1373
        return false;
 
1374
 
 
1375
    // TODO: check format? (cannot edit OGR layers)
 
1376
 
 
1377
    return true;
 
1378
}
 
1379
 
 
1380
bool QgsGrassProvider::isEdited ( void )
 
1381
{
 
1382
    #if QGISDEBUG > 3
 
1383
    std::cerr << "QgsGrassProvider::isEdited" << std::endl;
 
1384
    #endif
 
1385
 
 
1386
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1387
    return (map->update);
 
1388
}
 
1389
 
 
1390
bool QgsGrassProvider::isFrozen ( void )
 
1391
{
 
1392
    #if QGISDEBUG > 3
 
1393
    std::cerr << "QgsGrassProvider::isFrozen" << std::endl;
 
1394
    #endif
 
1395
 
 
1396
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1397
    return (map->frozen);
 
1398
}
 
1399
 
 
1400
void QgsGrassProvider::freeze()
 
1401
{
 
1402
#ifdef QGISDEBUG
 
1403
    std::cerr << "QgsGrassProvider::freeze" << std::endl;
 
1404
#endif
 
1405
 
 
1406
    if ( !isValid() ) return;
 
1407
 
 
1408
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1409
 
 
1410
    if ( map->frozen ) return;
 
1411
    
 
1412
    map->frozen = true;
 
1413
    Vect_close ( map->map );
 
1414
}
 
1415
 
 
1416
void QgsGrassProvider::thaw()
 
1417
{
 
1418
#ifdef QGISDEBUG
 
1419
    std::cerr << "QgsGrassProvider::thaw" << std::endl;
 
1420
#endif
 
1421
 
 
1422
    if ( !isValid() ) return;
 
1423
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1424
 
 
1425
    if ( !map->frozen ) return;
 
1426
 
 
1427
    if ( reopenMap() ) 
 
1428
    {
 
1429
        map->frozen = false;
 
1430
    }
 
1431
}
 
1432
 
 
1433
bool QgsGrassProvider::startEdit ( void )
 
1434
{
 
1435
#ifdef QGISDEBUG
 
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;
 
1439
#endif
 
1440
 
 
1441
    if ( !isGrassEditable() )
 
1442
        return false;
 
1443
 
 
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." );
 
1448
        return false;
 
1449
    }
 
1450
 
 
1451
    /* Close map */
 
1452
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1453
    map->valid = false;
 
1454
 
 
1455
    QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() ); 
 
1456
 
 
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() );
 
1460
 
 
1461
    Vect_close ( map->map );
 
1462
 
 
1463
    // TODO: Catch error 
 
1464
     
 
1465
    QgsGrass::resetError();
 
1466
    int level = Vect_open_update ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii() );
 
1467
    if (  level < 2 ) { 
 
1468
        if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1469
            std::cerr << "Cannot open GRASS vector for update: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
 
1470
        } else {
 
1471
            std::cerr << "Cannot open GRASS vector for update on level 2." << std::endl;
 
1472
        }
 
1473
        
 
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() );
 
1478
    
 
1479
        if ( level < 2 ) {
 
1480
            if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1481
                std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
 
1482
            } else {
 
1483
                std::cerr << "Cannot reopen GRASS vector on level 2." << std::endl;
 
1484
            }
 
1485
        } else {
 
1486
            map->valid = true;
 
1487
        }
 
1488
        
 
1489
        return false;
 
1490
    }
 
1491
    Vect_set_category_index_update ( map->map );
 
1492
 
 
1493
    // Write history
 
1494
    Vect_hist_command ( map->map );
 
1495
 
 
1496
    #ifdef QGISDEBUG
 
1497
    std::cerr << "Vector successfully reopened for update." << std::endl;
 
1498
    #endif
 
1499
 
 
1500
    map->update = true;
 
1501
    map->valid = true;
 
1502
 
 
1503
    return true;
 
1504
}
 
1505
 
 
1506
bool QgsGrassProvider::closeEdit ( bool newMap )
 
1507
{
 
1508
    #ifdef QGISDEBUG
 
1509
    std::cerr << "QgsGrassProvider::closeEdit" << std::endl;
 
1510
    #endif
 
1511
 
 
1512
    if ( !isValid() )
 
1513
        return false;
 
1514
 
 
1515
    /* Close map */
 
1516
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1517
    
 
1518
    if ( !(map->update) )
 
1519
        return false;
 
1520
 
 
1521
    map->valid = false;
 
1522
    map->version++;
 
1523
 
 
1524
    QgsGrass::setLocation ( (char *) map->gisdbase.ascii(), (char *) map->location.ascii() ); 
 
1525
 
 
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() );
 
1530
    
 
1531
    Vect_build_partial ( map->map, GV_BUILD_NONE, NULL);
 
1532
    Vect_build ( map->map, stderr );
 
1533
 
 
1534
    // If a new map was created close the map and return
 
1535
    if ( newMap )
 
1536
    {
 
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
 
1540
        map->valid = true;
 
1541
        closeLayer( mLayerId );
 
1542
        return true;
 
1543
    }
 
1544
 
 
1545
    Vect_close ( map->map );
 
1546
 
 
1547
    map->update = false;
 
1548
 
 
1549
    if ( !reopenMap() ) return false;
 
1550
 
 
1551
    map->valid = true;
 
1552
 
 
1553
    return true;
 
1554
}
 
1555
 
 
1556
bool QgsGrassProvider::reopenMap()
 
1557
{
 
1558
    GMAP *map = &(mMaps[mLayers[mLayerId].mapId]);
 
1559
 
 
1560
    QFileInfo di ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapName );
 
1561
    map->lastModified = di.lastModified();
 
1562
 
 
1563
    di.setFile ( mGisdbase + "/" + mLocation + "/" + mMapset + "/vector/" + mMapset + "/dbln" );
 
1564
    map->lastAttributesModified = di.lastModified();
 
1565
 
 
1566
    // Reopen vector
 
1567
    QgsGrass::resetError(); // to "catch" error after Vect_open_old()
 
1568
    Vect_set_open_level (2);
 
1569
 
 
1570
    Vect_open_old ( map->map, (char *) map->mapName.ascii(), (char *) map->mapset.ascii());
 
1571
 
 
1572
    if ( QgsGrass::getError() == QgsGrass::FATAL ) {
 
1573
        std::cerr << "Cannot reopen GRASS vector: " << QgsGrass::getErrorMessage().toLocal8Bit().data() << std::endl;
 
1574
        return false;
 
1575
    }
 
1576
 
 
1577
    #ifdef QGISDEBUG
 
1578
    std::cerr << "GRASS map successfully reopened for reading." << std::endl;
 
1579
    #endif
 
1580
 
 
1581
    // Reload sources to layers
 
1582
    for ( int i = 0; i <  mLayers.size(); i++) {
 
1583
        // if ( !(mLayers[i].valid) ) continue; // ?
 
1584
 
 
1585
        if  ( mLayers[i].mapId == mLayers[mLayerId].mapId ) {
 
1586
            loadLayerSourcesFromMap ( mLayers[i] );
 
1587
        }
 
1588
    }
 
1589
 
 
1590
    return true;
 
1591
}
 
1592
 
 
1593
int QgsGrassProvider::numLines ( void )
 
1594
{
 
1595
    #ifdef QGISDEBUG
 
1596
    std::cerr << "QgsGrassProvider::numLines" << std::endl;
 
1597
    #endif
 
1598
 
 
1599
    return ( Vect_get_num_lines(mMap) );
 
1600
}
 
1601
 
 
1602
int QgsGrassProvider::numNodes ( void )
 
1603
{
 
1604
    #ifdef QGISDEBUG
 
1605
    std::cerr << "QgsGrassProvider::numNodes" << std::endl;
 
1606
    #endif
 
1607
 
 
1608
    return ( Vect_get_num_nodes(mMap) );
 
1609
}
 
1610
 
 
1611
int QgsGrassProvider::readLine ( struct line_pnts *Points, struct line_cats *Cats, int line )
 
1612
{
 
1613
    #if QGISDEBUG > 3
 
1614
    std::cerr << "QgsGrassProvider::readLine" << std::endl;
 
1615
    #endif
 
1616
 
 
1617
    if ( Points )
 
1618
        Vect_reset_line ( Points );
 
1619
 
 
1620
    if ( Cats )
 
1621
        Vect_reset_cats ( Cats );
 
1622
 
 
1623
    if ( !Vect_line_alive(mMap, line) ) return -1;
 
1624
 
 
1625
    return ( Vect_read_line(mMap, Points, Cats, line) );
 
1626
}
 
1627
 
 
1628
bool QgsGrassProvider::nodeCoor ( int node, double *x, double *y )
 
1629
{
 
1630
    #if QGISDEBUG > 3
 
1631
    std::cerr << "QgsGrassProvider::nodeCoor" << std::endl;
 
1632
    #endif
 
1633
 
 
1634
    if ( !Vect_node_alive ( mMap, node) ) {
 
1635
        *x = 0.0;
 
1636
        *y = 0.0;
 
1637
        return false;
 
1638
    }
 
1639
    
 
1640
    Vect_get_node_coor ( mMap, node, x, y, NULL);
 
1641
    return true;
 
1642
}
 
1643
 
 
1644
bool QgsGrassProvider::lineNodes ( int line, int *node1, int *node2 )
 
1645
{
 
1646
    #if QGISDEBUG > 3
 
1647
    std::cerr << "QgsGrassProvider::lineNodes" << std::endl;
 
1648
    #endif
 
1649
    
 
1650
    if ( !Vect_line_alive(mMap, line) ) {
 
1651
        *node1 = 0;
 
1652
        *node2 = 0;
 
1653
        return false;
 
1654
    }
 
1655
    
 
1656
    Vect_get_line_nodes ( mMap, line, node1, node2 );
 
1657
    return true;
 
1658
}
 
1659
 
 
1660
int QgsGrassProvider::writeLine ( int type, struct line_pnts *Points, struct line_cats *Cats )
 
1661
{
 
1662
    #ifdef QGISDEBUG
 
1663
    std::cerr << "QgsGrassProvider::writeLine n_points = " << Points->n_points 
 
1664
              << " n_cats = " << Cats->n_cats << std::endl;
 
1665
    #endif
 
1666
 
 
1667
    if ( !isEdited() )
 
1668
        return -1;
 
1669
 
 
1670
    return ( (int) Vect_write_line(mMap,type,Points,Cats) );
 
1671
}
 
1672
 
 
1673
int QgsGrassProvider::rewriteLine ( int line, int type, struct line_pnts *Points, struct line_cats *Cats )
 
1674
{
 
1675
    #ifdef QGISDEBUG
 
1676
    std::cerr << "QgsGrassProvider::rewriteLine n_points = " << Points->n_points 
 
1677
              << " n_cats = " << Cats->n_cats << std::endl;
 
1678
    #endif
 
1679
 
 
1680
    if ( !isEdited() )
 
1681
        return -1;
 
1682
 
 
1683
    return ( Vect_rewrite_line(mMap,line,type,Points,Cats) );
 
1684
}
 
1685
 
 
1686
 
 
1687
int QgsGrassProvider::deleteLine ( int line )
 
1688
{
 
1689
    #ifdef QGISDEBUG
 
1690
    std::cerr << "QgsGrassProvider::deleteLine" << std::endl;
 
1691
    #endif
 
1692
 
 
1693
    if ( !isEdited() )
 
1694
        return -1;
 
1695
 
 
1696
    return ( Vect_delete_line(mMap,line) );
 
1697
}
 
1698
 
 
1699
int QgsGrassProvider::findLine ( double x, double y, int type, double threshold )
 
1700
{
 
1701
    #if QGISDEBUG > 3
 
1702
    std::cerr << "QgsGrassProvider::findLine" << std::endl;
 
1703
    #endif
 
1704
 
 
1705
    return ( Vect_find_line(mMap,x,y,0,type,threshold,0,0) );
 
1706
}
 
1707
 
 
1708
int QgsGrassProvider::findNode ( double x, double y, double threshold )
 
1709
{
 
1710
    return ( Vect_find_node ( mMap, x, y, 0, threshold, 0 ) );
 
1711
}
 
1712
 
 
1713
bool QgsGrassProvider::lineAreas ( int line, int *left, int *right )
 
1714
{
 
1715
    #if QGISDEBUG > 3
 
1716
    std::cerr << "QgsGrassProvider::lineAreas" << std::endl;
 
1717
    #endif
 
1718
    
 
1719
    if ( !Vect_line_alive(mMap, line) ) {
 
1720
        *left = 0;
 
1721
        *right = 0;
 
1722
        return false;
 
1723
    }
 
1724
    
 
1725
    Vect_get_line_areas ( mMap, line, left, right );
 
1726
    return true;
 
1727
}
 
1728
 
 
1729
int QgsGrassProvider::centroidArea ( int centroid )
 
1730
{
 
1731
    #if QGISDEBUG > 3
 
1732
    std::cerr << "QgsGrassProvider::centroidArea" << std::endl;
 
1733
    #endif
 
1734
    
 
1735
    if ( !Vect_line_alive(mMap, centroid) ) {
 
1736
        return 0;
 
1737
    }
 
1738
    
 
1739
    return ( Vect_get_centroid_area(mMap,centroid) );
 
1740
}
 
1741
 
 
1742
int QgsGrassProvider::nodeNLines ( int node )
 
1743
{
 
1744
    #if QGISDEBUG > 3
 
1745
    std::cerr << "QgsGrassProvider::nodeNLines" << std::endl;
 
1746
    #endif
 
1747
    
 
1748
    if ( !Vect_node_alive(mMap, node) ) {
 
1749
        return 0;
 
1750
    }
 
1751
    
 
1752
    return ( Vect_get_node_n_lines(mMap,node) );
 
1753
}
 
1754
 
 
1755
int QgsGrassProvider::nodeLine ( int node, int idx )
 
1756
{
 
1757
    #if QGISDEBUG > 3
 
1758
    std::cerr << "QgsGrassProvider::nodeLine" << std::endl;
 
1759
    #endif
 
1760
    
 
1761
    if ( !Vect_node_alive(mMap, node) ) {
 
1762
        return 0;
 
1763
    }
 
1764
 
 
1765
    return ( Vect_get_node_line(mMap,node,idx) );
 
1766
}
 
1767
 
 
1768
int QgsGrassProvider::lineAlive ( int line )
 
1769
{
 
1770
    #if QGISDEBUG > 3
 
1771
    std::cerr << "QgsGrassProvider::lineAlive" << std::endl;
 
1772
    #endif
 
1773
    
 
1774
    return ( Vect_line_alive(mMap, line) ) ;
 
1775
}
 
1776
 
 
1777
int QgsGrassProvider::nodeAlive ( int node )
 
1778
{
 
1779
    #if QGISDEBUG > 3
 
1780
    std::cerr << "QgsGrassProvider::nodeAlive" << std::endl;
 
1781
    #endif
 
1782
    
 
1783
    return ( Vect_node_alive(mMap, node) ) ;
 
1784
}
 
1785
 
 
1786
int QgsGrassProvider::numUpdatedLines ( void )
 
1787
{
 
1788
    #ifdef QGISDEBUG
 
1789
    std::cerr << "QgsGrassProvider::numUpdatedLines" << std::endl;
 
1790
    std::cerr << "  numUpdatedLines = " << Vect_get_num_updated_lines(mMap) << std::endl;
 
1791
    #endif
 
1792
    
 
1793
    return ( Vect_get_num_updated_lines(mMap) ) ;
 
1794
}
 
1795
 
 
1796
int QgsGrassProvider::numUpdatedNodes ( void )
 
1797
{
 
1798
    #ifdef QGISDEBUG
 
1799
    std::cerr << "QgsGrassProvider::numUpdatedNodes" << std::endl;
 
1800
    std::cerr << "  numUpdatedNodes = " << Vect_get_num_updated_nodes(mMap) << std::endl;
 
1801
    #endif
 
1802
    
 
1803
    return ( Vect_get_num_updated_nodes(mMap) ) ;
 
1804
}
 
1805
 
 
1806
int QgsGrassProvider::updatedLine ( int idx )
 
1807
{
 
1808
    #ifdef QGISDEBUG
 
1809
    std::cerr << "QgsGrassProvider::updatedLine idx = " << idx << std::endl;
 
1810
    std::cerr << "  updatedLine = " << Vect_get_updated_line( mMap, idx ) << std::endl;
 
1811
    #endif
 
1812
    
 
1813
    return ( Vect_get_updated_line( mMap, idx ) ) ;
 
1814
}
 
1815
 
 
1816
int QgsGrassProvider::updatedNode ( int idx )
 
1817
{
 
1818
    #ifdef QGISDEBUG
 
1819
    std::cerr << "QgsGrassProvider::updatedNode idx = " << idx << std::endl;
 
1820
    std::cerr << "  updatedNode = " << Vect_get_updated_node( mMap, idx ) << std::endl;
 
1821
    #endif
 
1822
    
 
1823
    return ( Vect_get_updated_node( mMap, idx ) ) ;
 
1824
}
 
1825
 
 
1826
// ------------------ Attributes -------------------------------------------------
 
1827
 
 
1828
QString *QgsGrassProvider::key ( int field )
 
1829
{
 
1830
    #ifdef QGISDEBUG
 
1831
    std::cerr << "QgsGrassProvider::key() field = " << field << std::endl;
 
1832
    #endif
 
1833
 
 
1834
    QString *key = new QString();
 
1835
 
 
1836
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
1837
 
 
1838
    if ( fi == NULL ) {
 
1839
        #ifdef QGISDEBUG
 
1840
        std::cerr << "No field info -> no attributes" << std::endl;
 
1841
        #endif
 
1842
        return key;
 
1843
    }
 
1844
 
 
1845
    key->setAscii(fi->key);
 
1846
    return key;
 
1847
}
 
1848
 
 
1849
std::vector<QgsField> *QgsGrassProvider::columns ( int field )
 
1850
{
 
1851
    #ifdef QGISDEBUG
 
1852
    std::cerr << "QgsGrassProvider::columns() field = " << field << std::endl;
 
1853
    #endif
 
1854
 
 
1855
    std::vector<QgsField> *col = new std::vector<QgsField>;
 
1856
    
 
1857
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
1858
 
 
1859
    // Read attributes
 
1860
    if ( fi == NULL ) {
 
1861
        #ifdef QGISDEBUG
 
1862
        std::cerr << "No field info -> no attributes" << std::endl;
 
1863
        #endif
 
1864
        return ( col );
 
1865
    }
 
1866
 
 
1867
    #ifdef QGISDEBUG
 
1868
    std::cerr << "Field info found -> open database" << std::endl;
 
1869
    #endif
 
1870
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
1871
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
1872
 
 
1873
    if ( driver == NULL ) {
 
1874
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
1875
        return ( col );
 
1876
    }
 
1877
 
 
1878
    #ifdef QGISDEBUG
 
1879
    std::cerr << "Database opened -> describe table" << std::endl;
 
1880
    #endif
 
1881
 
 
1882
    dbString tableName;
 
1883
    db_init_string ( &tableName );
 
1884
    db_set_string ( &tableName, fi->table);
 
1885
    
 
1886
    dbTable *table;
 
1887
    if(db_describe_table (driver, &tableName, &table) != DB_OK) {
 
1888
        std::cerr << "Cannot describe table" << std::endl;
 
1889
        return ( col );
 
1890
    }
 
1891
 
 
1892
    int nCols = db_get_table_number_of_columns(table);
 
1893
 
 
1894
    for (int c = 0; c < nCols; c++) {
 
1895
        dbColumn *column = db_get_table_column (table, c);
 
1896
 
 
1897
        int ctype = db_sqltype_to_Ctype( db_get_column_sqltype (column) );
 
1898
        QString type;
 
1899
        switch ( ctype ) {
 
1900
            case DB_C_TYPE_INT:
 
1901
                type = "int";
 
1902
                break;
 
1903
            case DB_C_TYPE_DOUBLE:
 
1904
                type = "double";
 
1905
                break;
 
1906
            case DB_C_TYPE_STRING:
 
1907
                type = "string";
 
1908
                break;
 
1909
            case DB_C_TYPE_DATETIME:
 
1910
                type = "datetime";
 
1911
                break;
 
1912
        }
 
1913
        col->push_back ( QgsField( db_get_column_name (column), type, db_get_column_length(column), 0) );
 
1914
    }
 
1915
        
 
1916
    db_close_database_shutdown_driver ( driver );
 
1917
 
 
1918
    return col;
 
1919
}
 
1920
 
 
1921
std::vector<QgsFeatureAttribute> *QgsGrassProvider::attributes ( int field, int cat )
 
1922
{
 
1923
    #ifdef QGISDEBUG
 
1924
    std::cerr << "QgsGrassProvider::attributes() field = " << field << " cat = " << cat << std::endl;
 
1925
    #endif
 
1926
 
 
1927
    std::vector<QgsFeatureAttribute> *att = new std::vector<QgsFeatureAttribute>;
 
1928
 
 
1929
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
1930
 
 
1931
    // Read attributes
 
1932
    if ( fi == NULL ) {
 
1933
        #ifdef QGISDEBUG
 
1934
        std::cerr << "No field info -> no attributes" << std::endl;
 
1935
        #endif
 
1936
        return att;
 
1937
    }
 
1938
 
 
1939
    #ifdef QGISDEBUG
 
1940
    std::cerr << "Field info found -> open database" << std::endl;
 
1941
    #endif
 
1942
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
1943
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
1944
 
 
1945
    if ( driver == NULL ) {
 
1946
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
1947
        return att;
 
1948
    }
 
1949
 
 
1950
    #ifdef QGISDEBUG
 
1951
    std::cerr << "Database opened -> read attributes" << std::endl;
 
1952
    #endif
 
1953
 
 
1954
    dbString dbstr; 
 
1955
    db_init_string (&dbstr);
 
1956
    QString query;
 
1957
    query.sprintf("select * from %s where %s = %d", fi->table, fi->key, cat );
 
1958
    db_set_string (&dbstr, (char *)query.ascii());
 
1959
    
 
1960
    #ifdef QGISDEBUG
 
1961
    std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
1962
    #endif
 
1963
 
 
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;
 
1968
        return att;
 
1969
    } 
 
1970
 
 
1971
    int nRecords = db_get_num_rows ( &databaseCursor );
 
1972
    #ifdef QGISDEBUG
 
1973
    std::cerr << "Number of records: " << nRecords << std::endl;
 
1974
    #endif
 
1975
 
 
1976
    if ( nRecords < 1 ) {
 
1977
        db_close_database_shutdown_driver ( driver );
 
1978
        std::cerr << "No DB record" << std::endl;
 
1979
        return att;
 
1980
    }
 
1981
    
 
1982
    dbTable  *databaseTable = db_get_cursor_table (&databaseCursor);
 
1983
    int nColumns = db_get_table_number_of_columns(databaseTable);
 
1984
 
 
1985
    int more;
 
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;
 
1989
        return att;
 
1990
    }
 
1991
 
 
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);
 
1996
 
 
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 ) );
 
2000
    }
 
2001
 
 
2002
    db_close_cursor (&databaseCursor);
 
2003
    db_close_database_shutdown_driver ( driver );
 
2004
    db_free_string(&dbstr);
 
2005
 
 
2006
    return att;
 
2007
}
 
2008
 
 
2009
QString *QgsGrassProvider::updateAttributes ( int field, int cat, const QString &values )
 
2010
{
 
2011
    #ifdef QGISDEBUG
 
2012
    std::cerr << "QgsGrassProvider::updateAttributes() field = " << field << " cat = " << cat << std::endl;
 
2013
    #endif
 
2014
 
 
2015
    QString *error = new QString();
 
2016
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2017
 
 
2018
    // Read attributes
 
2019
    if ( fi == NULL ) {
 
2020
        #ifdef QGISDEBUG
 
2021
        std::cerr << "No field info -> no attributes" << std::endl;
 
2022
        #endif
 
2023
        error->setLatin1( "Cannot get field info" );
 
2024
        return error;
 
2025
    }
 
2026
 
 
2027
    #ifdef QGISDEBUG
 
2028
    std::cerr << "Field info found -> open database" << std::endl;
 
2029
    #endif
 
2030
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
2031
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
2032
 
 
2033
    if ( driver == NULL ) {
 
2034
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
2035
        error->setAscii("Cannot open database");
 
2036
        return error;
 
2037
    }
 
2038
 
 
2039
    #ifdef QGISDEBUG
 
2040
    std::cerr << "Database opened -> read attributes" << std::endl;
 
2041
    #endif
 
2042
 
 
2043
    dbString dbstr; 
 
2044
    db_init_string (&dbstr);
 
2045
    QString query;
 
2046
    
 
2047
    query = "update " + QString(fi->table) + " set " + values + " where " + QString(fi->key) 
 
2048
            + " = " + QString::number(cat);
 
2049
 
 
2050
    #ifdef QGISDEBUG
 
2051
    std::cerr << "query: " << query.toLocal8Bit().data() << std::endl;
 
2052
    #endif
 
2053
 
 
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);
 
2058
 
 
2059
    Q3CString qcs = query.toLocal8Bit().data();
 
2060
    #ifdef QGISDEBUG
 
2061
    std::cerr << "qcs: " << qcs.data() << std::endl;
 
2062
    #endif
 
2063
    
 
2064
    char *cs = new char[qcs.length() + 1];
 
2065
    strcpy(cs, (const char *)qcs);
 
2066
    db_set_string (&dbstr, cs );
 
2067
    delete[] cs;
 
2068
    
 
2069
    #ifdef QGISDEBUG
 
2070
    std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
2071
    #endif
 
2072
 
 
2073
    int ret = db_execute_immediate (driver, &dbstr);
 
2074
 
 
2075
    if ( ret != DB_OK) { 
 
2076
        std::cerr << "Error: " <<  db_get_error_msg() << std::endl;
 
2077
        error->setLatin1( db_get_error_msg() );
 
2078
    }
 
2079
 
 
2080
    db_close_database_shutdown_driver ( driver );
 
2081
    db_free_string(&dbstr);
 
2082
 
 
2083
    return error;
 
2084
}
 
2085
 
 
2086
int QgsGrassProvider::numDbLinks ( void )
 
2087
{
 
2088
    #ifdef QGISDEBUG
 
2089
    std::cerr << "QgsGrassProvider::numDbLinks()" << std::endl;
 
2090
    #endif
 
2091
 
 
2092
    return ( Vect_get_num_dblinks(mMap) );
 
2093
}
 
2094
 
 
2095
int QgsGrassProvider::dbLinkField ( int link )
 
2096
{
 
2097
    #ifdef QGISDEBUG
 
2098
    std::cerr << "QgsGrassProvider::dbLinkField()" << std::endl;
 
2099
    #endif
 
2100
 
 
2101
    struct  field_info *fi = Vect_get_dblink ( mMap, link );
 
2102
 
 
2103
    if ( fi == NULL ) return 0;
 
2104
 
 
2105
    return ( fi->number );
 
2106
}
 
2107
 
 
2108
QString *QgsGrassProvider::executeSql ( int field, const QString &sql )
 
2109
{
 
2110
    #ifdef QGISDEBUG
 
2111
    std::cerr << "QgsGrassProvider::executeSql field = " << field << std::endl;
 
2112
    #endif
 
2113
 
 
2114
    QString *error = new QString();
 
2115
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2116
 
 
2117
    // Read attributes
 
2118
    if ( fi == NULL ) {
 
2119
        #ifdef QGISDEBUG
 
2120
        std::cerr << "No field info -> no attributes" << std::endl;
 
2121
        #endif
 
2122
        error->setLatin1( "Cannot get field info" );
 
2123
        return error;
 
2124
    }
 
2125
 
 
2126
    #ifdef QGISDEBUG
 
2127
    std::cerr << "Field info found -> open database" << std::endl;
 
2128
    #endif
 
2129
 
 
2130
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
2131
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
2132
 
 
2133
    if ( driver == NULL ) {
 
2134
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
2135
        error->setAscii("Cannot open database");
 
2136
        return error;
 
2137
    }
 
2138
 
 
2139
    #ifdef QGISDEBUG
 
2140
    std::cerr << "Database opened" << std::endl;
 
2141
    #endif
 
2142
 
 
2143
    dbString dbstr; 
 
2144
    db_init_string (&dbstr);
 
2145
    db_set_string (&dbstr, (char *)sql.latin1());
 
2146
    
 
2147
    #ifdef QGISDEBUG
 
2148
    std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
2149
    #endif
 
2150
 
 
2151
    int ret = db_execute_immediate (driver, &dbstr);
 
2152
 
 
2153
    if ( ret != DB_OK) { 
 
2154
        std::cerr << "Error: " <<  db_get_error_msg() << std::endl;
 
2155
        error->setLatin1( db_get_error_msg() );
 
2156
    }
 
2157
 
 
2158
    db_close_database_shutdown_driver ( driver );
 
2159
    db_free_string(&dbstr);
 
2160
 
 
2161
    return error;
 
2162
 
 
2163
}
 
2164
 
 
2165
QString *QgsGrassProvider::createTable ( int field, const QString &key, const QString &columns )
 
2166
{
 
2167
    #ifdef QGISDEBUG
 
2168
    std::cerr << "QgsGrassProvider::createTable() field = " << field << std::endl;
 
2169
    #endif
 
2170
 
 
2171
    QString *error = new QString();
 
2172
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2173
 
 
2174
    // Read attributes
 
2175
    if ( fi != NULL ) {
 
2176
        #ifdef QGISDEBUG
 
2177
        std::cerr << "The table for this field already exists" << std::endl;
 
2178
        #endif
 
2179
        error->setLatin1( "The table for this field already exists" );
 
2180
        return error;
 
2181
    }
 
2182
 
 
2183
    #ifdef QGISDEBUG
 
2184
    std::cerr << "Field info not found -> create new table" << std::endl;
 
2185
    #endif
 
2186
 
 
2187
    // We must set mapset before Vect_default_field_info
 
2188
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
2189
 
 
2190
    int nLinks = Vect_get_num_dblinks( mMap );
 
2191
    if ( nLinks == 0 ) {
 
2192
        fi = Vect_default_field_info ( mMap, field, NULL, GV_1TABLE );
 
2193
    } else {
 
2194
        fi = Vect_default_field_info ( mMap, field, NULL, GV_MTABLE );
 
2195
    }
 
2196
    
 
2197
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
2198
 
 
2199
    if ( driver == NULL ) {
 
2200
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
2201
        error->setAscii("Cannot open database");
 
2202
        return error;
 
2203
    }
 
2204
 
 
2205
    #ifdef QGISDEBUG
 
2206
    std::cerr << "Database opened -> create table" << std::endl;
 
2207
    #endif
 
2208
 
 
2209
    dbString dbstr; 
 
2210
    db_init_string (&dbstr);
 
2211
    QString query;
 
2212
    
 
2213
    query.sprintf("create table %s ( %s )", fi->table, columns.latin1() );
 
2214
    db_set_string (&dbstr, (char *)query.latin1());
 
2215
    
 
2216
    #ifdef QGISDEBUG
 
2217
    std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
2218
    #endif
 
2219
 
 
2220
    int ret = db_execute_immediate (driver, &dbstr);
 
2221
 
 
2222
    if ( ret != DB_OK) { 
 
2223
        std::cerr << "Error: " <<  db_get_error_msg() << std::endl;
 
2224
        error->setLatin1( db_get_error_msg() );
 
2225
    }
 
2226
 
 
2227
    db_close_database_shutdown_driver ( driver );
 
2228
    db_free_string(&dbstr);
 
2229
 
 
2230
    if ( !error->isEmpty() ) return error;
 
2231
 
 
2232
    ret = Vect_map_add_dblink ( mMap, field, NULL, fi->table, (char *)key.latin1(), 
 
2233
                                    fi->database, fi->driver);
 
2234
 
 
2235
    if ( ret == -1 ) { 
 
2236
        std::cerr << "Error: Cannot add dblink" << std::endl;
 
2237
        error->setLatin1( "Cannot create link to the table. The table was created!" );
 
2238
    }
 
2239
 
 
2240
    return error;
 
2241
}
 
2242
 
 
2243
QString *QgsGrassProvider::addColumn ( int field, const QString &column )
 
2244
{
 
2245
    #ifdef QGISDEBUG
 
2246
    std::cerr << "QgsGrassProvider::addColumn() field = " << field << std::endl;
 
2247
    #endif
 
2248
 
 
2249
    QString *error = new QString();
 
2250
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2251
 
 
2252
    // Read attributes
 
2253
    if ( fi == NULL ) {
 
2254
        #ifdef QGISDEBUG
 
2255
        std::cerr << "No field info" << std::endl;
 
2256
        #endif
 
2257
        error->setLatin1( "Cannot get field info" );
 
2258
        return error;
 
2259
    }
 
2260
 
 
2261
    QString query;
 
2262
    
 
2263
    query.sprintf("alter table %s add column %s", fi->table, column.latin1() );
 
2264
 
 
2265
    delete error;
 
2266
    return executeSql ( field, query );
 
2267
}
 
2268
 
 
2269
QString *QgsGrassProvider::insertAttributes ( int field, int cat )
 
2270
{
 
2271
    #ifdef QGISDEBUG
 
2272
    std::cerr << "QgsGrassProvider::insertAttributes() field = " << field << " cat = " << cat << std::endl;
 
2273
    #endif
 
2274
 
 
2275
    QString *error = new QString();
 
2276
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2277
 
 
2278
    // Read attributes
 
2279
    if ( fi == NULL ) {
 
2280
        #ifdef QGISDEBUG
 
2281
        std::cerr << "No field info -> no attributes" << std::endl;
 
2282
        #endif
 
2283
        error->setLatin1( "Cannot get field info" );
 
2284
        return error;
 
2285
    }
 
2286
 
 
2287
    QString query;
 
2288
    
 
2289
    query.sprintf("insert into %s ( %s ) values ( %d )", fi->table, fi->key, cat );
 
2290
 
 
2291
    delete error;
 
2292
    return executeSql ( field, query );
 
2293
}
 
2294
 
 
2295
QString *QgsGrassProvider::deleteAttributes ( int field, int cat )
 
2296
{
 
2297
    #ifdef QGISDEBUG
 
2298
    std::cerr << "QgsGrassProvider::deleteAttributes() field = " << field << " cat = " << cat << std::endl;
 
2299
    #endif
 
2300
 
 
2301
    QString *error = new QString();
 
2302
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2303
 
 
2304
    // Read attributes
 
2305
    if ( fi == NULL ) {
 
2306
        #ifdef QGISDEBUG
 
2307
        std::cerr << "No field info -> no attributes" << std::endl;
 
2308
        #endif
 
2309
        error->setLatin1( "Cannot get field info" );
 
2310
        return error;
 
2311
    }
 
2312
 
 
2313
    QString query;
 
2314
    
 
2315
    query.sprintf("delete from %s where %s = %d", fi->table, fi->key, cat );
 
2316
 
 
2317
    delete error;
 
2318
    return executeSql ( field, query );
 
2319
}
 
2320
 
 
2321
QString *QgsGrassProvider::isOrphan ( int field, int cat, int *orphan)
 
2322
{
 
2323
    #ifdef QGISDEBUG
 
2324
    std::cerr << "QgsGrassProvider::isOrphan() field = " << field << " cat = " << cat << std::endl;
 
2325
    #endif
 
2326
 
 
2327
    QString *error = new QString();
 
2328
 
 
2329
    // Check first if another line with such cat exists
 
2330
    int fieldIndex = Vect_cidx_get_field_index ( mMap, field );
 
2331
    if ( fieldIndex >= 0 ) 
 
2332
    {
 
2333
        int t, id;
 
2334
        int ret = Vect_cidx_find_next ( mMap, fieldIndex, cat, 
 
2335
                        GV_POINTS|GV_LINES, 0, &t, &id );
 
2336
      
 
2337
        if ( ret >= 0 ) {
 
2338
           // Category exists
 
2339
           *orphan = false;
 
2340
           return error; 
 
2341
        }
 
2342
    }
 
2343
 
 
2344
    // Check if attribute exists
 
2345
    struct  field_info *fi = Vect_get_field( mMap, field); // should work also with field = 0
 
2346
 
 
2347
    // Read attributes
 
2348
    if ( fi == NULL ) {
 
2349
        #ifdef QGISDEBUG
 
2350
        std::cerr << "No field info -> no attributes" << std::endl;
 
2351
        #endif
 
2352
        *orphan = false;
 
2353
        return error; 
 
2354
    }
 
2355
 
 
2356
    #ifdef QGISDEBUG
 
2357
    std::cerr << "Field info found -> open database" << std::endl;
 
2358
    #endif
 
2359
    QgsGrass::setMapset ( mGisdbase, mLocation, mMapset ); 
 
2360
    dbDriver *driver = db_start_driver_open_database ( fi->driver, fi->database );
 
2361
 
 
2362
    if ( driver == NULL ) {
 
2363
        std::cerr << "Cannot open database " << fi->database << " by driver " << fi->driver << std::endl;
 
2364
        error->setAscii("Cannot open database");
 
2365
        return error;
 
2366
    }
 
2367
 
 
2368
    #ifdef QGISDEBUG
 
2369
    std::cerr << "Database opened -> select record" << std::endl;
 
2370
    #endif
 
2371
 
 
2372
    dbString dbstr; 
 
2373
    db_init_string (&dbstr);
 
2374
    QString query;
 
2375
    
 
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());
 
2378
    
 
2379
    #ifdef QGISDEBUG
 
2380
    std::cerr << "SQL: " << db_get_string(&dbstr) << std::endl;
 
2381
    #endif
 
2382
 
 
2383
    dbCursor cursor;
 
2384
    if ( db_open_select_cursor(driver, &dbstr, &cursor, DB_SCROLL) != DB_OK )
 
2385
    {
 
2386
        db_close_database_shutdown_driver ( driver );
 
2387
        error->setAscii("Cannot query database: " + query );
 
2388
        return error;
 
2389
    }
 
2390
    int nRecords = db_get_num_rows ( &cursor );
 
2391
    #ifdef QGISDEBUG
 
2392
    std::cerr << "Number of records: " << nRecords << std::endl;
 
2393
    #endif
 
2394
 
 
2395
    if ( nRecords > 0 ) { *orphan = true; }
 
2396
 
 
2397
    db_close_database_shutdown_driver ( driver );
 
2398
    db_free_string(&dbstr);
 
2399
 
 
2400
    return error;
 
2401
}
 
2402
 
 
2403
 
 
2404
// -------------------------------------------------------------------------------
 
2405
 
 
2406
int QgsGrassProvider::cidxGetNumFields( ) 
 
2407
{
 
2408
    return ( Vect_cidx_get_num_fields(mMap) );
 
2409
}
 
2410
 
 
2411
int QgsGrassProvider::cidxGetFieldNumber( int idx ) 
 
2412
{
 
2413
    return ( Vect_cidx_get_field_number(mMap, idx) );
 
2414
}
 
2415
 
 
2416
int QgsGrassProvider::cidxGetMaxCat( int idx ) 
 
2417
{
 
2418
    int ncats = Vect_cidx_get_num_cats_by_index ( mMap, idx);
 
2419
 
 
2420
    int cat, type, id;
 
2421
    Vect_cidx_get_cat_by_index ( mMap, idx, ncats-1, &cat, &type, &id );
 
2422
    
 
2423
    return ( cat );
 
2424
}
 
2425
    
 
2426
 
 
2427
 
 
2428
size_t QgsGrassProvider::layerCount() const
 
2429
{
 
2430
    return 1;                   // XXX how to find how many layers?
 
2431
} // QgsGrassProvider::layerCount()
 
2432
 
 
2433
 
 
2434
 
 
2435
QString QgsGrassProvider::name() const
 
2436
{
 
2437
    return GRASS_KEY;
 
2438
} // QgsGrassProvider::name()
 
2439
 
 
2440
 
 
2441
 
 
2442
QString QgsGrassProvider::description() const
 
2443
{
 
2444
    return GRASS_DESCRIPTION;
 
2445
} // QgsGrassProvider::description()
 
2446
 
 
2447