diff --git a/providers/delimitedtext/qgsdelimitedtextprovider.cpp b/providers/delimitedtext/qgsdelimitedtextprovider.cpp index 5d4bc6bce2f..2239bf5c308 100644 --- a/providers/delimitedtext/qgsdelimitedtextprovider.cpp +++ b/providers/delimitedtext/qgsdelimitedtextprovider.cpp @@ -448,7 +448,7 @@ QgsFeature *QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes) return f; } -QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list& attlist, bool getnotcommited) +QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list& attlist) { // We must manually check each point to see if it is within the // selection rectangle @@ -755,35 +755,6 @@ bool QgsDelimitedTextProvider::isValid(){ return mValid; } -bool QgsDelimitedTextProvider::startEditing() -{ - return false; -} - -void QgsDelimitedTextProvider::stopEditing() -{ -} - -bool QgsDelimitedTextProvider::commitChanges() -{ - return false; -} - -bool QgsDelimitedTextProvider::rollBack() -{ - return false; -} - -bool QgsDelimitedTextProvider::addFeature(QgsFeature* f) -{ - return false; -} - -bool QgsDelimitedTextProvider::deleteFeature(int id) -{ - return false; -} - /** * Check to see if the point is within the selection rectangle */ diff --git a/providers/delimitedtext/qgsdelimitedtextprovider.h b/providers/delimitedtext/qgsdelimitedtextprovider.h index bfa087200d3..9f960dea8eb 100644 --- a/providers/delimitedtext/qgsdelimitedtextprovider.h +++ b/providers/delimitedtext/qgsdelimitedtextprovider.h @@ -48,7 +48,8 @@ public: */ QgsFeature * getNextFeature(bool fetchAttributes=false); bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false); - QgsFeature * getNextFeature(std::list& attlist, bool getnotcommited=false); + + QgsFeature * getNextFeature(std::list& attlist); /** Get the feature type. This corresponds to WKBPoint, @@ -129,44 +130,6 @@ public: */ bool isValid(); - /** - Enables editing capabilities of the provider (if supported) - @return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); - - /** - Disables the editing capabilities of the provider - */ - virtual void stopEditing(); - - /** - Commits changes - @return false in case of problems - */ - virtual bool commitChanges(); - - /** - Discards changes - @return false in case of problems - */ - virtual bool rollBack(); - - /**Returns true if the provider is in editing mode*/ - virtual bool isEditable() const {return false;} - - /**Returns true if the provider has been modified since the last commit*/ - virtual bool isModified() const {return false;} - - /**Adds a feature - @return true in case of success and false in case of failure*/ - bool addFeature(QgsFeature* f); - - /**Deletes a feature - @param id the number of the feature - @return true in case of success and false in case of failure*/ - bool deleteFeature(int id); - /** * Check to see if the point is withn the selection * rectangle diff --git a/providers/gpx/qgsgpxprovider.cpp b/providers/gpx/qgsgpxprovider.cpp index 74410dc0ae3..7022e1276c8 100644 --- a/providers/gpx/qgsgpxprovider.cpp +++ b/providers/gpx/qgsgpxprovider.cpp @@ -143,10 +143,10 @@ QgsFeature *QgsGPXProvider::getNextFeature(bool fetchAttributes) { QgsFeature* feature = new QgsFeature(-1); bool success; if (fetchAttributes) - success = getNextFeature(feature, mAllAttributes, false); + success = getNextFeature(feature, mAllAttributes); else { std::list emptyList; - success = getNextFeature(feature, emptyList, false); + success = getNextFeature(feature, emptyList); } if (success) return feature; @@ -155,10 +155,9 @@ QgsFeature *QgsGPXProvider::getNextFeature(bool fetchAttributes) { } -QgsFeature * QgsGPXProvider::getNextFeature(std::list& attlist, - bool getnotcommited) { +QgsFeature * QgsGPXProvider::getNextFeature(std::list& attlist) { QgsFeature* feature = new QgsFeature(-1); - bool success = getNextFeature(feature, attlist, getnotcommited); + bool success = getNextFeature(feature, attlist); if (success) return feature; delete feature; @@ -167,11 +166,10 @@ QgsFeature * QgsGPXProvider::getNextFeature(std::list& attlist, bool QgsGPXProvider::getNextFeature(QgsFeature* feature, - std::list& attlist, - bool getnotcommitted) { - bool result = false; + std::list& attlist) { + bool result = false; - std::list::const_iterator iter; + /*std::list::const_iterator iter; if (mFeatureType == WaypointType) { // go through the list of waypoints and return the first one that is in @@ -371,7 +369,7 @@ bool QgsGPXProvider::getNextFeature(QgsFeature* feature, } } } - + */ return result; } @@ -551,214 +549,7 @@ bool QgsGPXProvider::isValid(){ return mValid; } -bool QgsGPXProvider::startEditing() { - mEditable = true; - return true; -} - - -void QgsGPXProvider::stopEditing() { - mEditable = false; -} - - -bool QgsGPXProvider::commitChanges() { - for (int i = 0; i < mAddedFeatures.size(); ++i) { - if (mFeatureType == WaypointType) - data->addWaypoint(*dynamic_cast(mAddedFeatures[i])); - else if (mFeatureType == RouteType) - data->addRoute(*dynamic_cast(mAddedFeatures[i])); - else if (mFeatureType == TrackType) - data->addTrack(*dynamic_cast(mAddedFeatures[i])); - - delete mAddedFeatures[i]; - } - mAddedFeatures.clear(); - - // write back to file - QDomDocument qdd; - data->fillDom(qdd); - QFile file(mFileName); - if (file.open(IO_WriteOnly)) { - QTextStream stream(&file); - stream<getGeometry(); - int id; - QGis::WKBTYPE ftype; - memcpy(&ftype, (geo + 1), sizeof(int)); - - /* Do different things for different geometry types: - WKBPoint -> add waypoint if this is a waypoint layer - WKBLineString -> add track if this is a track layer, route if this is a - route layer - WKBPolygon and the WKBMulti types are not supported because they don't - make sense for GPX files. */ - switch(ftype) { - - // the user is trying to add a point feature - case QGis::WKBPoint: { - if (mFeatureType != WaypointType) { - std::cerr<<"Tried to write point feature to non-point layer!"<(mAddedFeatures[mAddedFeatures.size() - 1])); - wpt->lat = *((double*)(geo + 5 + sizeof(double))); - wpt->lon = *((double*)(geo + 5)); - - // parse waypoint-specific attributes - std::vector::const_iterator iter; - for (iter = f->attributeMap().begin(); - iter != f->attributeMap().end(); ++iter) { - if (iter->fieldName() == "ele") { - bool b; - double d = iter->fieldValue().toDouble(&b); - if (b) - wpt->ele = d; - else - wpt->ele = -std::numeric_limits::max(); - } - else if (iter->fieldName() == "sym") - wpt->sym = iter->fieldValue(); - } - - obj = wpt; - - break; - } - - // the user is trying to add a line feature - case QGis::WKBLineString: { - if (mFeatureType == WaypointType) { - std::cerr<<"Tried to write line feature to point layer!"<getGeometry()+1+sizeof(int),sizeof(int)); -#ifdef QGISDEBUG - qWarning("length: "+QString::number(length)); -#endif - - GPSExtended* ext = NULL; - - // add route - if (mFeatureType == RouteType) { - mAddedFeatures.push_back(new Route); - Route* rte(dynamic_cast(mAddedFeatures[mAddedFeatures.size() - 1])); - for (int i = 0; i < length; ++i) { - Routepoint rpt; - std::memcpy(&rpt.lon, geo + 9 + 16 * i, sizeof(double)); - std::memcpy(&rpt.lat, geo + 9 + 16 * i + 8, sizeof(double)); - - // update the route bounds - rte->xMin = (rte->xMin < rpt.lon ? rte->xMin : rpt.lon); - rte->xMax = (rte->xMax > rpt.lon ? rte->xMax : rpt.lon); - rte->yMin = (rte->yMin < rpt.lat ? rte->yMin : rpt.lat); - rte->yMax = (rte->yMax > rpt.lat ? rte->yMax : rpt.lat); - - rte->points.push_back(rpt); - } - - ext = rte; - } - - // add track - else if (mFeatureType == TrackType) { - mAddedFeatures.push_back(new Track); - Track* trk(dynamic_cast(mAddedFeatures[mAddedFeatures.size() - 1])); - TrackSegment trkSeg; - for (int i = 0; i < length; ++i) { - Trackpoint tpt; - std::memcpy(&tpt.lon, geo + 9 + 16 * i, sizeof(double)); - std::memcpy(&tpt.lat, geo + 9 + 16 * i + 8, sizeof(double)); - - // update the track bounds - trk->xMin = (trk->xMin < tpt.lon ? trk->xMin : tpt.lon); - trk->xMax = (trk->xMax > tpt.lon ? trk->xMax : tpt.lon); - trk->yMin = (trk->yMin < tpt.lat ? trk->yMin : tpt.lat); - trk->yMax = (trk->yMax > tpt.lat ? trk->yMax : tpt.lat); - - trkSeg.points.push_back(tpt); - } - trk->segments.push_back(trkSeg); - - ext = trk; - } - - // parse GPSExtended-specific attributes - std::vector::const_iterator iter; - for (iter = f->attributeMap().begin(); - iter != f->attributeMap().end(); ++iter) { - if (iter->fieldName() == "number") { - bool b; - int n = iter->fieldValue().toInt(&b); - if (b) - ext->number = n; - else - ext->number = std::numeric_limits::max(); - } - } - - obj = ext; - - break; - } - - // unsupported geometry - something's wrong - default: - return false; - - } - - // parse common attributes - std::vector::const_iterator iter; - for (iter = f->attributeMap().begin(); - iter != f->attributeMap().end(); ++iter) { - if (iter->fieldName() == "name") - obj->name = iter->fieldValue(); - else if (iter->fieldName() == "cmt") - obj->cmt = iter->fieldValue(); - else if (iter->fieldName() == "desc") - obj->desc = iter->fieldValue(); - else if (iter->fieldName() == "src") - obj->src = iter->fieldValue(); - else if (iter->fieldName() == "url") - obj->url = iter->fieldValue(); - else if (iter->fieldName() == "urlname") - obj->urlname = iter->fieldValue(); - } - - return true; -} - - -bool QgsGPXProvider::deleteFeature(int id) { +bool QgsGPXProvider::addFeatures(std::list flist) { return false; } diff --git a/providers/gpx/qgsgpxprovider.h b/providers/gpx/qgsgpxprovider.h index bc5f126ca58..9fc07183007 100644 --- a/providers/gpx/qgsgpxprovider.h +++ b/providers/gpx/qgsgpxprovider.h @@ -51,7 +51,7 @@ public: */ QgsFeature * getNextFeature(bool fetchAttributes=false); bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false); - QgsFeature * getNextFeature(std::list& attlist, bool getnotcommited=false); + QgsFeature * getNextFeature(std::list& attlist); /** Get the feature type. This corresponds to WKBPoint, @@ -129,29 +129,6 @@ public: */ bool isValid(); - /** - Enables editing capabilities of the provider (if supported) - @return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); - - /** - Disables the editing capabilities of the provider - */ - virtual void stopEditing(); - - /** - Commits changes - @return false in case of problems - */ - virtual bool commitChanges(); - - /** - Discards changes - @return false in case of problems - */ - virtual bool rollBack(); - /**Returns true if the provider is in editing mode*/ virtual bool isEditable() const { return mEditable; } @@ -160,12 +137,7 @@ public: /**Adds a feature @return true in case of success and false in case of failure*/ - bool addFeature(QgsFeature* f); - -/**Deletes a feature - @param id the number of the feature - @return true in case of success and false in case of failure*/ - bool deleteFeature(int id); + bool addFeatures(std::list flist); /**Returns the default value for attribute @c attr for feature @c f. */ QString getDefaultValue(const QString& attr, QgsFeature* f); @@ -178,12 +150,13 @@ public: * @return True if point is within the rectangle */ bool boundsCheck(double x, double y); + + bool supportsFeatureAddition(){return true;} private: /** Internal function used by the other getNextFeature() functions. */ - bool getNextFeature(QgsFeature* feature, std::list& attlist, - bool getnotcommitted); + bool getNextFeature(QgsFeature* feature, std::list& attlist); bool mEditable; std::vector mAddedFeatures; diff --git a/providers/grass/qgsgrassprovider.cpp b/providers/grass/qgsgrassprovider.cpp index 4452e0b65d3..e32574fe3dd 100644 --- a/providers/grass/qgsgrassprovider.cpp +++ b/providers/grass/qgsgrassprovider.cpp @@ -326,7 +326,7 @@ QgsFeature *QgsGrassProvider::getNextFeature(bool fetchAttributes) return ( getNextFeature(attlist) ); } -QgsFeature* QgsGrassProvider::getNextFeature(std::list& attlist, bool getnotcommited) +QgsFeature* QgsGrassProvider::getNextFeature(std::list& attlist) { int cat, type, id, idx; unsigned char *wkb; @@ -649,41 +649,6 @@ bool QgsGrassProvider::isValid(){ return mValid; } -bool QgsGrassProvider::startEditing() -{ - return false; -} - -void QgsGrassProvider::stopEditing() -{ -} - -bool QgsGrassProvider::commitChanges() -{ - return false; -} - -bool QgsGrassProvider::rollBack() -{ - return false; -} - -bool QgsGrassProvider::addFeature(QgsFeature* f) -{ - #ifdef QGISDEBUG - std::cerr << "QgsGrassProvider::addFeature()" << std::endl; - #endif - return false; -} - -bool QgsGrassProvider::deleteFeature(int id) -{ - #ifdef QGISDEBUG - std::cerr << "QgsGrassProvider::deleteFeature()" << std::endl; - #endif - return false; -} - // ------------------------------------------------------------------------------------------------------ // Compare categories in GATT static int cmpAtt ( const void *a, const void *b ) { diff --git a/providers/grass/qgsgrassprovider.h b/providers/grass/qgsgrassprovider.h index 8f2bf2f8b07..68221146318 100644 --- a/providers/grass/qgsgrassprovider.h +++ b/providers/grass/qgsgrassprovider.h @@ -108,7 +108,7 @@ public: */ QgsFeature * getNextFeature(bool fetchAttributes=false); bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false); - QgsFeature* getNextFeature(std::list& attlist, bool getnotcommited=false); + QgsFeature* getNextFeature(std::list& attlist); /** * Get the feature type as defined in WKBTYPE (qgis.h). @@ -408,44 +408,6 @@ public: /** Get maximum category for field index */ int cidxGetMaxCat ( int idx ); - /** - Enables editing capabilities of the provider (if supported) - @return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); - - /** - Disables the editing capabilities of the provider - */ - virtual void stopEditing(); - - /** - Commits changes - @return false in case of problems - */ - virtual bool commitChanges(); - - /** - Discards changes - @return false in case of problems - */ - virtual bool rollBack(); - - /**Returns true if the provider is in editing mode*/ - virtual bool isEditable() const {return true;} - - /**Returns true if the provider has been modified since the last commit*/ - virtual bool isModified() const {return false;} - - /**Adds a feature - @return true in case of success and false in case of failure*/ - bool addFeature(QgsFeature* f); - - /**Deletes a feature - @param id the number of the feature - @return true in case of success and false in case of failure*/ - bool deleteFeature(int id); - private: enum ENDIAN { NDR = 1, diff --git a/providers/ogr/qgsshapefileprovider.cpp b/providers/ogr/qgsshapefileprovider.cpp index dcede07e9e9..7933f6f91e9 100644 --- a/providers/ogr/qgsshapefileprovider.cpp +++ b/providers/ogr/qgsshapefileprovider.cpp @@ -120,13 +120,6 @@ QgsShapeFileProvider::~QgsShapeFileProvider() } delete[] minmaxcache; - //delete not commited features - for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) - { - delete *it; - } - mAddedFeatures.clear(); - } /** @@ -360,7 +353,7 @@ QgsFeature *QgsShapeFileProvider::getNextFeature(bool fetchAttributes) return f; } -QgsFeature *QgsShapeFileProvider::getNextFeature(std::list& attlist, bool getnotcommited) +QgsFeature *QgsShapeFileProvider::getNextFeature(std::list& attlist) { QgsFeature *f = 0; if(valid) @@ -408,26 +401,11 @@ QgsFeature *QgsShapeFileProvider::getNextFeature(std::list& attlist, bool g } else { - if(getnotcommited&&mAddedFeatures.size()>0&&mAddedFeaturesIt!=mAddedFeatures.end()) - { -#ifdef QGISDEBUG - qWarning("accessing feature in the cache"); -#endif //QGISDEBUG - QgsFeature* addedfeature=*mAddedFeaturesIt; - ++mAddedFeaturesIt; - //copy the feature because it will be deleted in QgsVectorLayer::draw() - QgsFeature* returnf=new QgsFeature(*addedfeature); - return returnf; - } #ifdef QGISDEBUG std::cerr << "Feature is null\n"; #endif // probably should reset reading here ogrLayer->ResetReading(); - if(!mAddedFeatures.empty()) - { - mAddedFeaturesIt=mAddedFeatures.begin(); - } } } else @@ -616,10 +594,6 @@ void QgsShapeFileProvider::reset() { ogrLayer->SetSpatialFilter(0); ogrLayer->ResetReading(); - if(!mAddedFeatures.empty()) - { - mAddedFeaturesIt=mAddedFeatures.begin(); - } } QString QgsShapeFileProvider::minValue(int position) @@ -687,17 +661,11 @@ bool QgsShapeFileProvider::isValid() return valid; } -bool QgsShapeFileProvider::startEditing() -{ - mEditable=true; - return true; -} - -bool QgsShapeFileProvider::commitFeature(QgsFeature* f) +bool QgsShapeFileProvider::addFeature(QgsFeature* f) { qWarning("try to commit a feature"); - if(mEditable) - { + + bool returnValue = true; OGRFeatureDefn* fdef=ogrLayer->GetLayerDefn(); OGRFeature* feature=new OGRFeature(fdef); @@ -839,39 +807,20 @@ bool QgsShapeFileProvider::commitFeature(QgsFeature* f) ++numberFeatures; delete feature; return returnValue; - } - else//layer not editable - { - return false; - } } -/*bool QgsShapeFileProvider::deleteFeature(int id) +bool QgsShapeFileProvider::addFeatures(std::list flist) { -#ifdef QGISDEBUG - int test=ogrLayer->TestCapability("OLCDeleteFeature"); - if(!test) + bool returnvalue=true; + for(std::list::iterator it=flist.begin();it!=flist.end();++it) { - qWarning("no support for deletion of features"); + if(!addFeature(*it)) + { + returnvalue=false; + } } -#endif - OGRErr message=ogrLayer->DeleteFeature(id); - switch(message) - { - case OGRERR_UNSUPPORTED_OPERATION: -#ifdef QGISDEBUG - qWarning("driver does not support deletion"); -#endif - return false; - case OGRERR_NONE: -#ifdef QGISDEBUG - qWarning("deletion successfull"); -#endif - break; - } - return true; - return false; -}*/ + return returnvalue; +} /** * Class factory to return a pointer to a newly created diff --git a/providers/ogr/qgsshapefileprovider.h b/providers/ogr/qgsshapefileprovider.h index 08634edeee6..e794b278d26 100644 --- a/providers/ogr/qgsshapefileprovider.h +++ b/providers/ogr/qgsshapefileprovider.h @@ -49,7 +49,7 @@ class QgsShapeFileProvider:public QgsVectorDataProvider *@param attlist a list containing the indexes of the attribute fields to copy *@param getnotcommited flag indicating if not commited features should be returned */ - QgsFeature *getNextFeature(std::list& attlist, bool getnotcommited=false); + QgsFeature *getNextFeature(std::list& attlist); /** * Get the next feature resutling from a select operation * @return True if the feature was read. This does not indicate @@ -139,14 +139,10 @@ class QgsShapeFileProvider:public QgsVectorDataProvider */ bool isValid(); - /** - *Enables editing capabilities of the provider (if supported) - *@return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); + /**Writes a list of features to the file*/ + bool addFeatures(std::list flist); - protected: - bool commitFeature(QgsFeature* f); + bool supportsFeatureAddition(){return true;} private: unsigned char *getGeometryPointer(OGRFeature * fet); @@ -173,6 +169,6 @@ class QgsShapeFileProvider:public QgsVectorDataProvider void fillMinMaxCash(); //! Selection rectangle OGRPolygon * mSelectionRectangle; - - + /**Adds one feature*/ + bool addFeature(QgsFeature* f); }; diff --git a/providers/postgres/qgspostgresprovider.cpp b/providers/postgres/qgspostgresprovider.cpp index 4ffc8e831bf..c7eb3af25f3 100644 --- a/providers/postgres/qgspostgresprovider.cpp +++ b/providers/postgres/qgspostgresprovider.cpp @@ -456,7 +456,7 @@ QgsFeature *QgsPostgresProvider::getNextFeature(bool fetchAttributes) return f; } -QgsFeature* QgsPostgresProvider::getNextFeature(std::list& attlist, bool getnotcommited) +QgsFeature* QgsPostgresProvider::getNextFeature(std::list& attlist) { QgsFeature *f = 0; if (valid) @@ -465,36 +465,16 @@ QgsFeature* QgsPostgresProvider::getNextFeature(std::list& attlist, bool ge queryResult = PQexec(connection, (const char *)fetch); if(PQntuples(queryResult) == 0) { - - if(getnotcommited&&mAddedFeatures.size()>0&&mAddedFeaturesIt!=mAddedFeatures.end()) - { -#ifdef QGISDEBUG - qWarning("accessing feature in the cache"); -#endif //QGISDEBUG - QgsFeature* addedfeature=*mAddedFeaturesIt; - ++mAddedFeaturesIt; - //copy the feature because it will be deleted in QgsVectorLayer::draw() - QgsFeature* returnf=new QgsFeature(*addedfeature); - return returnf; - } #ifdef QGISDEBUG std::cerr << "Feature is null\n"; #endif - if(!mAddedFeatures.empty()) - { - mAddedFeaturesIt=mAddedFeatures.begin(); - } - PQexec(connection, "end work"); ready = false; return 0; } int *noid; - bool cont=false;//flag for repeating the loop in case of deleted features - while(cont==false) - { - int oid = *(int *)PQgetvalue(queryResult,0,PQfnumber(queryResult,primaryKey)); + int oid = *(int *)PQgetvalue(queryResult,0,PQfnumber(queryResult,primaryKey)); #ifdef QGISDEBUG std::cerr << "Primary key type is " << primaryKeyType << std::endl; #endif @@ -525,23 +505,8 @@ QgsFeature* QgsPostgresProvider::getNextFeature(std::list& attlist, bool ge noid = &oid; } } - //block feature if oid is contained in mDeletedFeatures - std::set::iterator iter=mDeletedFeatures.find(*noid); - if(iter==mDeletedFeatures.end()) - { - cont=true; - } - else - { - //we hit deleted feature, fetch the next - fetch = "fetch forward 1 from qgisf"; - queryResult = PQexec(connection, (const char *)fetch); - if(PQntuples(queryResult) == 0) - { - cont=true; - } - } - } + + int returnedLength = PQgetlength(queryResult,0, PQfnumber(queryResult,"qgs_feature_geometry")); if(returnedLength > 0) @@ -934,13 +899,7 @@ bool QgsPostgresProvider::isValid(){ return valid; } -bool QgsPostgresProvider::startEditing() -{ - mEditable=true; - return true; -} - -bool QgsPostgresProvider::commitFeature(QgsFeature* f) +bool QgsPostgresProvider::addFeature(QgsFeature* f) { if(f) { @@ -1044,13 +1003,6 @@ QString QgsPostgresProvider::getDefaultValue(const QString& attr, QgsFeature* f) } bool QgsPostgresProvider::deleteFeature(int id) -{ - mDeletedFeatures.insert(id); - mModified=true; - return true; -} - -bool QgsPostgresProvider::eraseFeature(int id) { QString sql("DELETE FROM "+tableName+" WHERE "+primaryKey+" = "+QString::number(id)); #ifdef QGISDEBUG @@ -1111,6 +1063,32 @@ QString QgsPostgresProvider::postgisVersion(PGconn *connection){ return postgisVersionInfo; } +bool QgsPostgresProvider::addFeatures(std::list flist) +{ + bool returnvalue=true; + for(std::list::iterator it=flist.begin();it!=flist.end();++it) + { + if(!addFeature(*it)) + { + returnvalue=false; + } + } + return returnvalue; +} + +bool QgsPostgresProvider::deleteFeatures(std::list id) +{ + bool returnvalue=true; + for(std::list::iterator it=id.begin();it!=id.end();++it) + { + if(!deleteFeature(*it)) + { + returnvalue=false; + } + } + return returnvalue; +} + /** * Class factory to return a pointer to a newly created * QgsPostgresProvider object diff --git a/providers/postgres/qgspostgresprovider.h b/providers/postgres/qgspostgresprovider.h index a8ce7beb3f7..3f3c4bd3e35 100644 --- a/providers/postgres/qgspostgresprovider.h +++ b/providers/postgres/qgspostgresprovider.h @@ -61,7 +61,7 @@ class QgsPostgresProvider:public QgsVectorDataProvider *@param attlist a list containing the indexes of the attribute fields to copy *@param getnotcommited flag indicating if not commited features should be returned */ - QgsFeature* getNextFeature(std::list& attlist, bool getnotcommited=false); + QgsFeature* getNextFeature(std::list& attlist); /** Get the feature type. This corresponds to * WKBPoint, * WKBLineString, @@ -162,28 +162,22 @@ class QgsPostgresProvider:public QgsVectorDataProvider //! get status of PROJ4 capability bool hasPROJ(PGconn *); - /** - *Enables editing capabilities of the provider (if supported) - *@return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); - /**Returns the default value for attribute @c attr for feature @c f. */ QString getDefaultValue(const QString& attr, QgsFeature* f); - /**Deletes a feature - @param id the number of the feature + /**Adds a list of features @return true in case of success and false in case of failure*/ - virtual bool deleteFeature(int id); + bool addFeatures(std::list flist); - protected: - /**Commits a feature - @return true in case of success and false in case of failure*/ - bool commitFeature(QgsFeature* f); - /**Commits the deletion of a feature - @return true in case of success and false in case of faiure*/ - bool eraseFeature(int id); + /**Deletes a list of features + @param id list of feature ids + @return true in case of success and false in case of failure*/ + bool deleteFeatures(std::list id); + bool supportsFeatureAddition(){return true;} + + bool supportsFeatureDeletion(){return true;} + private: std::vector < QgsFeature > features; std::vector < bool > *selected; @@ -282,4 +276,8 @@ private: bool gistAvailable; //! PROJ4 capability bool projAvailable; + /**Writes a single feature*/ + bool addFeature(QgsFeature* f); + /**Deletes a feature*/ + bool deleteFeature(int id); }; diff --git a/src/qgisapp.cpp b/src/qgisapp.cpp index 591136cded5..20a46c7f533 100644 --- a/src/qgisapp.cpp +++ b/src/qgisapp.cpp @@ -1870,11 +1870,6 @@ void QgisApp::deleteSelected() if (li) { QgsVectorLayer* vlayer = dynamic_cast(((QgsLegendItem *) li)->layer()); - if(!vlayer->getDataProvider()||!vlayer->getDataProvider()->isEditable()) - { - QMessageBox::information(0,"Layer not editable","Cannot edit the vector layer. Use 'Start editing' in the legend item menu",QMessageBox::Ok); - return; - } if(vlayer) { if(!vlayer->deleteSelectedFeatures()) diff --git a/src/qgsdataprovider.h b/src/qgsdataprovider.h index e8f06be4727..aa78ba8dfb4 100644 --- a/src/qgsdataprovider.h +++ b/src/qgsdataprovider.h @@ -85,35 +85,6 @@ public: */ virtual bool isValid()=0; - /** - Enables editing capabilities of the provider (if supported) - @return false in case of error or if the provider does not support editing - */ - virtual bool startEditing()=0; - - /** - Disables the editing capabilities of the provider - */ - virtual void stopEditing()=0; - - /** - Commits changes - @return false in case of problems - */ - virtual bool commitChanges()=0; - - /** - Discards changes - @return false in case of problems - */ - virtual bool rollBack()=0; - - /**Returns true if the provider is in editing mode*/ - virtual bool isEditable() const=0; - - /**Returns true if the provider has been modified since the last commit*/ - virtual bool isModified() const=0; - /* Reset the layer - for an OGRLayer, this means clearing the * spatial filter and calling ResetReading */ diff --git a/src/qgsmapcanvas.cpp b/src/qgsmapcanvas.cpp index 867c7d391ed..30d655a099a 100644 --- a/src/qgsmapcanvas.cpp +++ b/src/qgsmapcanvas.cpp @@ -1202,10 +1202,10 @@ void QgsMapCanvas::mouseReleaseEvent(QMouseEvent * e) if(vlayer) { - if(!vlayer->getDataProvider()||!vlayer->getDataProvider()->isEditable()) + if(!vlayer->isEditable()) { - QMessageBox::information(0,"Layer not editable","Cannot edit the vector layer. Use 'Start editing' in the legend item menu",QMessageBox::Ok); - break; + QMessageBox::information(0,"Layer not editable","Cannot edit the vector layer. Use 'Start editing' in the legend item menu",QMessageBox::Ok); + break; } QgsFeature* f = new QgsFeature(0,"WKBPoint"); @@ -1250,7 +1250,7 @@ void QgsMapCanvas::mouseReleaseEvent(QMouseEvent * e) QgsVectorLayer* vlayer=dynamic_cast(mCanvasProperties->mapLegend->currentLayer()); if(vlayer) { - if(!vlayer->getDataProvider()||!vlayer->getDataProvider()->isEditable()) + if(!vlayer->isEditable()) { QMessageBox::information(0,"Layer not editable","Cannot edit the vector layer. Use 'Start editing' in the legend item menu",QMessageBox::Ok); break; diff --git a/src/qgsmaplayer.h b/src/qgsmaplayer.h index add16f44c80..af8d3a13c5d 100644 --- a/src/qgsmaplayer.h +++ b/src/qgsmaplayer.h @@ -222,7 +222,7 @@ public: void setLegendItem(QgsLegendItem * li); /**True if the layer can be edited*/ - virtual bool isEditable()=0; + virtual bool isEditable() const =0; /** sets state from DOM document diff --git a/src/qgsrasterlayer.cpp b/src/qgsrasterlayer.cpp index cb8f7f53d96..63d6659161a 100644 --- a/src/qgsrasterlayer.cpp +++ b/src/qgsrasterlayer.cpp @@ -3142,7 +3142,7 @@ RasterPyramidList QgsRasterLayer::buildRasterPyramidList() } -bool QgsRasterLayer::isEditable() +bool QgsRasterLayer::isEditable() const { return false; } diff --git a/src/qgsrasterlayer.h b/src/qgsrasterlayer.h index 7edf50865e9..4195c43acfa 100644 --- a/src/qgsrasterlayer.h +++ b/src/qgsrasterlayer.h @@ -769,7 +769,7 @@ public: // RasterPyramid getRasterPyramid(int thePyramidNo); /**Currently returns always false*/ - bool isEditable(); + bool isEditable() const; public slots: diff --git a/src/qgsvectordataprovider.cpp b/src/qgsvectordataprovider.cpp index 2f47cc09993..a794a84bc02 100644 --- a/src/qgsvectordataprovider.cpp +++ b/src/qgsvectordataprovider.cpp @@ -18,91 +18,19 @@ #include "qgsfeature.h" -QgsVectorDataProvider::QgsVectorDataProvider(): mEditable(false), mModified(false) +QgsVectorDataProvider::QgsVectorDataProvider() { } -bool QgsVectorDataProvider::startEditing() + +bool QgsVectorDataProvider::addFeatures(std::list flist) { - //providers supporting editing need to overwrite this method return false; } -void QgsVectorDataProvider::stopEditing() +bool QgsVectorDataProvider::deleteFeatures(std::list id) { - mEditable=false; -} - -bool QgsVectorDataProvider::commitChanges() -{ - if(mEditable) - { - bool returnvalue=true; - for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) - { - if(!commitFeature(*it)) - { - returnvalue=false; - } - delete *it; - } - - for(std::set::iterator it=mDeletedFeatures.begin();it!=mDeletedFeatures.end();++it) - { - if(!eraseFeature(*it)) - { - returnvalue=false; - } - } - - mAddedFeatures.clear(); - mDeletedFeatures.clear(); - mModified=false; - return returnvalue; - } - else - { - return false; - } -} - -bool QgsVectorDataProvider::rollBack() -{ - if(mEditable) - { - for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) - { - delete *it; - } - mAddedFeatures.clear(); - mModified=false; - return true; - } - else - { - return false; - } -} - -bool QgsVectorDataProvider::addFeature(QgsFeature* f) -{ - if(mEditable) - { - mAddedFeatures.push_back(f); - mAddedFeaturesIt=mAddedFeatures.begin(); - mModified=true; - return true; - } - else - { - return false; - } -} - -bool QgsVectorDataProvider::deleteFeature(int id) -{ - //needs to be done by subclasses, because not all providers support it return false; } @@ -112,15 +40,14 @@ QString QgsVectorDataProvider::getDefaultValue(const QString& attr, return ""; } - -bool QgsVectorDataProvider::commitFeature(QgsFeature* f) +bool QgsVectorDataProvider::supportsFeatureAddition() { - //needs to be done by subclasses + //needs to be overwritten by providers if they provide feature editing return false; } -bool QgsVectorDataProvider::eraseFeature(int id) +bool QgsVectorDataProvider::supportsFeatureDeletion() { - //needs to be done by subclasses + //needs to be overwritten by providers which support this return false; } diff --git a/src/qgsvectordataprovider.h b/src/qgsvectordataprovider.h index 0dd8b026c8f..e5cd3f695d6 100644 --- a/src/qgsvectordataprovider.h +++ b/src/qgsvectordataprovider.h @@ -43,7 +43,7 @@ class QgsVectorDataProvider: public QgsDataProvider *@param attlist a list containing the indexes of the attribute fields to copy *@param getnotcommited flag indicating if not commited features should be returned */ - virtual QgsFeature * getNextFeature(std::list& attlist, bool getnotcommited=false)=0; + virtual QgsFeature * getNextFeature(std::list& attlist)=0; /** * Get the next feature using new method @@ -93,14 +93,14 @@ class QgsVectorDataProvider: public QgsDataProvider @param position the number of the attribute*/ virtual QString maxValue(int position)=0; - /**Adds a feature (but does not commit it) + /**Adds a list of features @return true in case of success and false in case of failure*/ - virtual bool addFeature(QgsFeature* f); + virtual bool addFeatures(std::list flist); /**Deletes a feature (but not not write it to disk yes) - @param id the number of the feature + @param id list containing feature ids to delete @return true in case of success and false in case of failure*/ - virtual bool deleteFeature(int id); + virtual bool deleteFeatures(std::list id); /**Returns the default value for attribute @c attr for feature @c f. */ virtual QString getDefaultValue(const QString& attr, QgsFeature* f); @@ -112,56 +112,11 @@ class QgsVectorDataProvider: public QgsDataProvider */ virtual std::vector& identify(QgsRect *rect)=0; - /** - *Enables editing capabilities of the provider (if supported) - *@return false in case of error or if the provider does not support editing - */ - virtual bool startEditing(); + /**Returns true if a provider supports feature editing*/ + virtual bool supportsFeatureAddition(); - /** - *Disables the editing capabilities of the provider - */ - virtual void stopEditing(); - - /** - Commits changes - @return false in case of problems - */ - virtual bool commitChanges(); - - /** - Discards changes - @return false in case of problems - */ - virtual bool rollBack(); - - /**Returns true if the provider is in editing mode*/ - virtual bool isEditable() const {return mEditable;} - - /**Returns true if the provider has been modified since the last commit*/ - virtual bool isModified() const {return mModified;} - - - protected: - - /**Flag indicating wheter the provider is in editing mode or not*/ - bool mEditable; - /**Flag indicating wheter the provider has been modified since the last commit*/ - bool mModified; - /**Features which are added but not yet commited*/ - std::list mAddedFeatures; - /**Ids of features to delete*/ - std::set mDeletedFeatures; - /**Commits the addition of a feature - @return true in case of success and false in case of failure*/ - virtual bool commitFeature(QgsFeature* f); - /**Commits the deletion of a feature - @return true in case of success and false in case of faiure*/ - virtual bool eraseFeature(int id); - - /**If getNextFeature needs to returns pointers to not commited features, - this member points to the latest feature*/ - std::list::iterator mAddedFeaturesIt; + /**Returns true if a provider supports deleting features*/ + virtual bool supportsFeatureDeletion(); }; #endif diff --git a/src/qgsvectorlayer.cpp b/src/qgsvectorlayer.cpp index da971062309..d72dff51c7c 100644 --- a/src/qgsvectorlayer.cpp +++ b/src/qgsvectorlayer.cpp @@ -89,7 +89,9 @@ QgsVectorLayer::QgsVectorLayer(QString vectorLayerPath, m_renderer(0), m_propertiesDialog(0), m_rendererDialog(0), - ir(0) // initialize the identify results pointer + ir(0), // initialize the identify results pointer + mEditable(false), + mModified(false) { #ifdef QGISDEBUG std::cerr << "VECTORLAYERPATH: " << vectorLayerPath.ascii() << std::endl; @@ -275,13 +277,25 @@ void QgsVectorLayer::drawLabels(QPainter * p, QgsRect * viewExtent, QgsCoordinat { // Render label if ( mLabelOn && (fet != 0)) { - bool sel=selected.find(fet->featureId()) != selected.end(); - mLabel->renderLabel ( p, viewExtent, cXf, dst, fet, sel); + if(mDeleted.find(fet->featureId())==mDeleted.end())//don't render labels of deleted features + { + bool sel=mSelected.find(fet->featureId()) != mSelected.end(); + mLabel->renderLabel ( p, viewExtent, cXf, dst, fet, sel); + } } delete fet; featureCount++; } + //render labels of not-commited features + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + bool sel=mSelected.find((*it)->featureId()) != mSelected.end(); + mLabel->renderLabel ( p, viewExtent, cXf, dst, *it, sel); + } + + + #ifdef QGISDEBUG std::cerr << "Total features processed is " << featureCount << std::endl; #endif @@ -340,7 +354,7 @@ void QgsVectorLayer::draw(QPainter * p, QgsRect * viewExtent, QgsCoordinateTrans std::list attributes=m_renderer->classificationAttributes(); - while((fet = dataProvider->getNextFeature(attributes,true))) + while((fet = dataProvider->getNextFeature(attributes))) { // If update threshold is greater than 0, check to see if // the threshold has been exceeded @@ -360,235 +374,25 @@ void QgsVectorLayer::draw(QPainter * p, QgsRect * viewExtent, QgsCoordinateTrans #endif } else { - bool sel=selected.find(fet->featureId()) != selected.end(); - m_renderer->renderFeature(p, fet, &marker, &markerScaleFactor, sel); + if(mDeleted.find(fet->featureId())==mDeleted.end()) + { + bool sel=mSelected.find(fet->featureId()) != mSelected.end(); + m_renderer->renderFeature(p, fet, &marker, &markerScaleFactor, sel); + + drawFeature(p,fet,cXf,&marker, markerScaleFactor); + ++featureCount; + delete fet; + } + } + } + //also draw the not yet commited features + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + bool sel=mSelected.find((*it)->featureId()) != mSelected.end(); + m_renderer->renderFeature(p, fet, &marker, &markerScaleFactor, sel); + drawFeature(p,*it,cXf,&marker,markerScaleFactor); + } - // std::cout << "Feature type: " << wkbType << std::endl; - // read each feature based on its type - - // get the wkb representation - feature = fet->getGeometry(); - // if (feature != 0) { - // std::cout << featureCount << "'the feature is null\n"; - //TODO - add this to the debug options -- if we decide to keep it - //wkbHeader header; - //memcpy((void *)&header,feature,sizeof(header)); - //std::cout << "Endian:" << header.endian << " WkbType:" << header.wkbType << std::endl; - - // FIX for the endian problem on osx (possibly sparc?) - // TODO Restructure this whole wkb reading code to use - // wkb structures as defined at (among other places): - // http://publib.boulder.ibm.com/infocenter/db2help/index.jsp?topic=/com.ibm.db2.udb.doc/opt/rsbp4121.htm - memcpy(&wkbType, (feature+1), sizeof(wkbType)); - - switch (wkbType) - { - case WKBPoint: - - // fldDef = fet->GetFieldDefnRef(1); - // fld = fldDef->GetNameRef(); - //NEEDTHIS? val = fet->GetFieldAsString(1); - //std::cout << val << "\n"; - - x = (double *) (feature + 5); - y = (double *) (feature + 5 + sizeof(double)); - // std::cout << "transforming point\n"; - pt.setX(*x); - pt.setY(*y); - cXf->transform(&pt); - //std::cout << "drawing marker for feature " << featureCount << "\n"; - p->drawRect(static_cast(pt.x()), static_cast(pt.y()), 5, 5); - p->scale(markerScaleFactor,markerScaleFactor); - p->drawPicture((int)(static_cast(pt.x()) / markerScaleFactor - marker.boundingRect().width() / 2), - (int)(static_cast(pt.y()) / markerScaleFactor - marker.boundingRect().height() / 2), - marker); - p->resetXForm(); - - break; - - case WKBLineString: - - // get number of points in the line - ptr = feature + 5; - nPoints = (int *) ptr; - ptr = feature + 1 + 2 * sizeof(int); - for (idx = 0; idx < *nPoints; idx++) - { - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - // transform the point - pt.setX(*x); - pt.setY(*y); - cXf->transform(&pt); - if (idx == 0) - p->moveTo(static_cast(pt.x()), static_cast(pt.y())); - else - p->lineTo(static_cast(pt.x()), static_cast(pt.y())); - } - break; - - case WKBMultiLineString: - - numLineStrings = (int) (feature[5]); - ptr = feature + 9; - for (jdx = 0; jdx < numLineStrings; jdx++) - { - // each of these is a wbklinestring so must handle as such - lsb = *ptr; - ptr += 5; // skip type since we know its 2 - nPoints = (int *) ptr; - ptr += sizeof(int); - for (idx = 0; idx < *nPoints; idx++) - { - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - // transform the point - pt.setX(*x); - pt.setY(*y); - cXf->transform(&pt); - if (idx == 0) - p->moveTo(static_cast(pt.x()), static_cast(pt.y())); - else - p->lineTo(static_cast(pt.x()), static_cast(pt.y())); - } - } - break; - - case WKBPolygon: - - { - // get number of rings in the polygon - numRings = (int *) (feature + 1 + sizeof(int)); - - if ( ! *numRings ) // sanity check for zero rings in polygon - { - break; - } - - int *ringStart; // index of first point for each ring - int *ringNumPoints; // number of points in each ring - ringStart = new int[*numRings]; - ringNumPoints = new int[*numRings]; - - int x0, y0, pdx; - pdx = 0; - ptr = feature + 1 + 2 * sizeof(int); // set pointer to the first ring - for (idx = 0; idx < *numRings; idx++) { - // get number of points in the ring - nPoints = (int *) ptr; - ringStart[idx] = pdx; - ringNumPoints[idx] = *nPoints; - ptr += 4; - if ( idx == 0 ) { - pa = new QPointArray(*nPoints); - } else { - pa->resize ( pa->size() + *nPoints + 1 ); // better to calc size for all rings before? - } - for (jdx = 0; jdx < *nPoints; jdx++) { - // add points to a point array for drawing the polygon - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; -#ifdef QGISX11DEBUG - std::cout << "Transforming " << *x << "," << *y << " to "; -#endif - ptr += sizeof(double); - pt.setX(*x); - pt.setY(*y); - cXf->transform(&pt); - pa->setPoint(pdx++, static_cast(pt.x()), static_cast(pt.y())); - } - if ( idx == 0 ) { // remember last outer ring point - x0 = static_cast(pt.x()); - y0 = static_cast(pt.y()); - } else { // return to x0,y0 (inner rings - islands) - pa->setPoint(pdx++, x0, y0); - } - } - // draw the polygon fill - pen = p->pen(); // store current pen - p->setPen ( Qt::NoPen ); // no boundary - p->drawPolygon(*pa); - - // draw outline - p->setPen ( pen ); - p->setBrush ( Qt::NoBrush ); - for (idx = 0; idx < *numRings; idx++) { - p->drawPolygon( *pa, FALSE, ringStart[idx], ringNumPoints[idx]); - } - - delete pa; - delete [] ringStart; - delete [] ringNumPoints; - - break; - - } - case WKBMultiPolygon: - - // get the number of polygons - ptr = feature + 5; - numPolygons = (int *) ptr; - ptr = feature + 9; - for (kdx = 0; kdx < *numPolygons; kdx++) - { - //skip the endian and feature type info and - // get number of rings in the polygon - ptr+=5; - numRings = (int *) ptr; - ptr += 4; - for (idx = 0; idx < *numRings; idx++) - { - // get number of points in the ring - nPoints = (int *) ptr; - ptr += 4; - pa = new QPointArray(*nPoints); - for (jdx = 0; jdx < *nPoints; jdx++) - { - // add points to a point array for drawing the polygon - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); -#ifdef QGISX11DEBUG - std::cout << "Transforming " << *x << "," << *y << " to "; -#endif - pt.setX(*x); - pt.setY(*y); - cXf->transform(&pt); - pa->setPoint(jdx, static_cast(pt.x()), static_cast(pt.y())); - } - // draw the ring - p->drawPolygon(*pa); - delete pa; - } - } - break; - - default: -#ifdef QGISDEBUG - std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n"; -#endif - break; - } - - - // XXX should be lower down? delete fet; - delete fet; - //std::cout << "deleting feature[]\n"; - // std::cout << geom->getGeometryName() << std::endl; - featureCount++; - - } - - //qApp->processEvents(); - - //delete fet; - } #ifdef QGISDEBUG std::cerr << "Total features processed is " << featureCount << std::endl; #endif @@ -598,6 +402,7 @@ void QgsVectorLayer::draw(QPainter * p, QgsRect * viewExtent, QgsCoordinateTrans #ifdef QGISDEBUG qWarning("Warning, QgsRenderer is null in QgsVectorLayer::draw()"); #endif + } } @@ -692,7 +497,7 @@ void QgsVectorLayer::table() int numFields = dataProvider->fieldCount(); tabledisplay = new QgsAttributeTableDisplay(); connect(tabledisplay, SIGNAL(deleted()), this, SLOT(invalidateTableDisplay())); - tabledisplay->table()->setNumRows(dataProvider->featureCount()); + tabledisplay->table()->setNumRows(dataProvider->featureCount()+mAddedFeatures.size()-mDeleted.size()); tabledisplay->table()->setNumCols(numFields + 1); //+1 for the id-column int row = 0; @@ -708,7 +513,11 @@ void QgsVectorLayer::table() QgsFeature *fet; while ((fet = dataProvider->getNextFeature(true))) { - + if(mDeleted.find(fet->featureId())!=mDeleted.end()) + { + //feature has been deleted + continue; + } //id-field tabledisplay->table()->setText(row, 0, QString::number(fet->featureId())); tabledisplay->table()->insertFeatureId(fet->featureId(), row); //insert the id into the search tree of qgsattributetable @@ -722,6 +531,21 @@ void QgsVectorLayer::table() delete fet; } + //also consider the not commited features + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + //id-field + tabledisplay->table()->setText(row, 0, QString::number((*it)->featureId())); + tabledisplay->table()->insertFeatureId((*it)->featureId(), row); //insert the id into the search tree of qgsattributetable + std::vector < QgsFeatureAttribute > attr = (*it)->attributeMap(); + for (int i = 0; i < attr.size(); i++) + { + // get the field values + tabledisplay->table()->setText(row, i + 1, attr[i].fieldValue()); + } + row++; + } + // reset the pointer to start of fetabledisplayures so // subsequent reads will not fail dataProvider->reset(); @@ -738,11 +562,11 @@ void QgsVectorLayer::table() QObject::disconnect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections())); - for (std::map < int, bool >::iterator it = selected.begin(); it != selected.end(); ++it) + for (std::set::iterator it = mSelected.begin(); it != mSelected.end(); ++it) { - tabledisplay->table()->selectRowWithId(it->first); + tabledisplay->table()->selectRowWithId(*it); #ifdef QGISDEBUG - qWarning("selecting row with id " + QString::number(it->first)); + qWarning("selecting row with id " + QString::number(*it)); #endif } @@ -761,7 +585,7 @@ void QgsVectorLayer::table() void QgsVectorLayer::select(int number) { - selected[number] = true; + mSelected.insert(number); } void QgsVectorLayer::select(QgsRect * rect, bool lock) @@ -790,10 +614,26 @@ void QgsVectorLayer::select(int number) while (fet = dataProvider->getNextFeature(true)) { - select(fet->featureId()); - if (tabledisplay) + if(mDeleted.find(fet->featureId())==mDeleted.end())//don't select deleted features { - tabledisplay->table()->selectRowWithId(fet->featureId()); + select(fet->featureId()); + if (tabledisplay) + { + tabledisplay->table()->selectRowWithId(fet->featureId()); + } + } + } + + //also test the not commited features + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + if((*it)->intersects(rect)) + { + select((*it)->featureId()); + if (tabledisplay) + { + tabledisplay->table()->selectRowWithId((*it)->featureId()); + } } } @@ -808,7 +648,7 @@ void QgsVectorLayer::select(int number) void QgsVectorLayer::removeSelection() { - selected.clear(); + mSelected.clear(); } void QgsVectorLayer::triggerRepaint() @@ -976,7 +816,7 @@ void QgsVectorLayer::select(int number) while ((fet = dataProvider->getNextFeature(false))) { - if (selected.find(fet->featureId()) != selected.end()) + if (mSelected.find(fet->featureId()) != mSelected.end()) { feature = fet->getGeometry(); wkbType = (int) feature[1]; @@ -1265,16 +1105,38 @@ void QgsVectorLayer::select(int number) { if(dataProvider) { - int end=endian(); - memcpy(f->getGeometry(),&end,1); + //set the endian properly + int end=endian(); + memcpy(f->getGeometry(),&end,1); - //using a feature id which (hopefully) does not conflict with already commited features - f->setFeatureId(-1); + //assign a temporary id to the feature + int tempid; + if(mAddedFeatures.size()==0) + { + tempid=findFreeId(); + } + else + { + std::list::iterator it=mAddedFeatures.end(); + --it; + tempid=(*it)->featureId()+1; + } +#ifdef QGISDEBUG + qWarning("assigned feature id "+QString::number(tempid)); +#endif + f->setFeatureId(tempid); + mAddedFeatures.push_back(f); + mModified=true; - if(dataProvider->addFeature(f)) - { - return true; - } + //hide and delete the table because it is not up to date any more + if (tabledisplay) + { + tabledisplay->close(); + delete tabledisplay; + tabledisplay=0; + } + + return true; } return false; } @@ -1287,25 +1149,55 @@ void QgsVectorLayer::select(int number) bool QgsVectorLayer::deleteSelectedFeatures() { -#ifdef QGISDEBUG - qWarning("entering QgsVectorLayer::deleteSelectedFeatures"); -#endif - bool resvalue=true; - for(std::map::iterator it=selected.begin();it!=selected.end();++it) - { - if(it->second==true) - { -#ifdef QGISDEBUG - qWarning("selected feature detected"); -#endif - if(!dataProvider->deleteFeature(it->first)) - { - resvalue=false; - } - } - } - triggerRepaint(); - return resvalue; + if(!dataProvider->supportsFeatureDeletion()) + { + QMessageBox::information(0, tr("Provider does not support deletion"), tr("Data provider does not support deleting features")); + return false; + } + + if(!isEditable()) + { + QMessageBox::information(0, tr("Layer not editable"), tr("The current layer is not editable. Choose 'start editing' in the legend item right click menu")); + return false; + } + + for(std::set::iterator it=mSelected.begin();it!=mSelected.end();++it) + { + bool notcommitedfeature=false; + //first test, if the feature with this id is a not-commited feature + for(std::list::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter) + { + if((*it)==(*iter)->featureId()) + { + mAddedFeatures.erase(iter); + notcommitedfeature=true; + break; + } + } + if(notcommitedfeature) + { + break; + } + mDeleted.insert(*it); + } + + if(mSelected.size()>0) + { + mModified=true; + mSelected.clear(); + triggerRepaint(); + + //hide and delete the table because it is not up to date any more + if (tabledisplay) + { + tabledisplay->close(); + delete tabledisplay; + tabledisplay=0; + } + + } + + return true; } QgsLabel * QgsVectorLayer::label() @@ -1327,14 +1219,15 @@ void QgsVectorLayer::select(int number) { if(dataProvider) { - if(!dataProvider->startEditing()) - { + if(!dataProvider->supportsFeatureAddition()) + { QMessageBox::information(0,"Start editing failed","Provider cannot be opened for editing",QMessageBox::Ok); - } - else - { - updateItemPixmap(); - } + } + else + { + mEditable=true; + updateItemPixmap(); + } } } @@ -1342,18 +1235,19 @@ void QgsVectorLayer::select(int number) { if(dataProvider) { - if(dataProvider->isModified()) + if(mModified) { //commit or roll back? int commit=QMessageBox::information(0,"Stop editing","Do you want to save the changes?",QMessageBox::Yes,QMessageBox::No); if(commit==QMessageBox::Yes) { - if(!dataProvider->commitChanges()) + if(!commitChanges()) { QMessageBox::information(0,"Error","Could not commit changes",QMessageBox::Ok); } else { + //hide and delete the table because it is not up to date any more if (tabledisplay) { tabledisplay->close(); @@ -1364,29 +1258,25 @@ void QgsVectorLayer::select(int number) } else if(commit==QMessageBox::No) { - if(!dataProvider->rollBack()) + if(!rollBack()) { QMessageBox::information(0,"Error","Problems during roll back",QMessageBox::Ok); } + //hide and delete the table because it is not up to date any more + if (tabledisplay) + { + tabledisplay->close(); + delete tabledisplay; + tabledisplay=0; + } } triggerRepaint(); } - dataProvider->stopEditing(); + mEditable=false; + mModified=false; updateItemPixmap(); } } - - bool QgsVectorLayer::isEditable() - { - if(dataProvider) - { - return dataProvider->isEditable(); - } - else - { - return false; - } - } // return state of scale dependent rendering. True if features should // only be rendered if between mMinimumScale and mMaximumScale @@ -1860,3 +1750,316 @@ void QgsVectorLayer::inOverview( bool b ) { QgsMapLayer::inOverview( b ); } + +int QgsVectorLayer::findFreeId() +{ + int freeid=-INT_MAX; + int fid; + if(dataProvider) + { + dataProvider->reset(); + QgsFeature *fet; + while ((fet = dataProvider->getNextFeature(true))) + { + fid=fet->featureId(); + if(fid>freeid) + { + freeid=fid; + } + delete fet; + } +#ifdef QGISDEBUG + qWarning("freeid is: "+QString::number(freeid+1)); +#endif + return freeid+1; + } + else + { +#ifdef QGISDEBUG + qWarning("Error, dataProvider is 0 in QgsVectorLayer::findFreeId"); +#endif + return -1; + } +} + +bool QgsVectorLayer::commitChanges() +{ + if(dataProvider) + { + bool returnvalue=true; + std::list addedlist; + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + addedlist.push_back(*it); + } + if(!dataProvider->addFeatures(addedlist)) + { + returnvalue=false; + } + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + delete *it; + } + mAddedFeatures.clear(); + + if(mDeleted.size()>0) + { + std::list deletelist; + for(std::set::iterator it=mDeleted.begin();it!=mDeleted.end();++it) + { + deletelist.push_back(*it); + mSelected.erase(*it);//just in case the feature is still selected + } + if(!dataProvider->deleteFeatures(deletelist)) + { + returnvalue=false; + } + } + return returnvalue; + } + else + { + return false; + } +} + +bool QgsVectorLayer::rollBack() +{ + for(std::list::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it) + { + delete *it; + mSelected.erase((*it)->featureId()); + } + mAddedFeatures.clear(); + for(std::set::iterator it=mDeleted.begin();it!=mDeleted.end();++it) + { + mSelected.erase(*it); + } + mDeleted.clear(); + return true; +} + +void QgsVectorLayer::drawFeature(QPainter* p, QgsFeature* fet, QgsCoordinateTransform * cXf, QPicture* marker, double markerScaleFactor) +{ + unsigned char *feature; + bool attributesneeded = m_renderer->needsAttributes(); + + double *x; + double *y; + int wkbType; + QgsPoint pt; + + QPen pen; + feature = fet->getGeometry(); + + memcpy(&wkbType, (feature+1), sizeof(wkbType)); + + switch (wkbType) + { + case WKBPoint: + { + x = (double *) (feature + 5); + y = (double *) (feature + 5 + sizeof(double)); + // std::cout << "transforming point\n"; + pt.setX(*x); + pt.setY(*y); + cXf->transform(&pt); + //std::cout << "drawing marker for feature " << featureCount << "\n"; + p->drawRect(static_cast(pt.x()), static_cast(pt.y()), 5, 5); + p->scale(markerScaleFactor,markerScaleFactor); + p->drawPicture((int)(static_cast(pt.x()) / markerScaleFactor - marker->boundingRect().width() / 2), + (int)(static_cast(pt.y()) / markerScaleFactor - marker->boundingRect().height() / 2), + *marker); + p->resetXForm(); + + break; + } + case WKBLineString: + { + unsigned char *ptr; + int *nPoints; + int idx; + + // get number of points in the line + ptr = feature + 5; + nPoints = (int *) ptr; + ptr = feature + 1 + 2 * sizeof(int); + for (idx = 0; idx < *nPoints; idx++) + { + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + // transform the point + pt.setX(*x); + pt.setY(*y); + cXf->transform(&pt); + if (idx == 0) + p->moveTo(static_cast(pt.x()), static_cast(pt.y())); + else + p->lineTo(static_cast(pt.x()), static_cast(pt.y())); + } + break; + } + case WKBMultiLineString: + { + unsigned char *ptr; + int idx, jdx, numLineStrings; + int *nPoints; + char lsb; + + numLineStrings = (int) (feature[5]); + ptr = feature + 9; + for (jdx = 0; jdx < numLineStrings; jdx++) + { + // each of these is a wbklinestring so must handle as such + lsb = *ptr; + ptr += 5; // skip type since we know its 2 + nPoints = (int *) ptr; + ptr += sizeof(int); + for (idx = 0; idx < *nPoints; idx++) + { + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + // transform the point + pt.setX(*x); + pt.setY(*y); + cXf->transform(&pt); + if (idx == 0) + p->moveTo(static_cast(pt.x()), static_cast(pt.y())); + else + p->lineTo(static_cast(pt.x()), static_cast(pt.y())); + } + } + break; + } + case WKBPolygon: + + { + unsigned char *ptr; + int idx, jdx; + int *numRings, *nPoints; + QPointArray *pa; + + // get number of rings in the polygon + numRings = (int *) (feature + 1 + sizeof(int)); + + if ( ! *numRings ) // sanity check for zero rings in polygon + { + break; + } + + int *ringStart; // index of first point for each ring + int *ringNumPoints; // number of points in each ring + ringStart = new int[*numRings]; + ringNumPoints = new int[*numRings]; + + int x0, y0, pdx; + pdx = 0; + ptr = feature + 1 + 2 * sizeof(int); // set pointer to the first ring + for (idx = 0; idx < *numRings; idx++) { + // get number of points in the ring + nPoints = (int *) ptr; + ringStart[idx] = pdx; + ringNumPoints[idx] = *nPoints; + ptr += 4; + if ( idx == 0 ) { + pa = new QPointArray(*nPoints); + } else { + pa->resize ( pa->size() + *nPoints + 1 ); // better to calc size for all rings before? + } + for (jdx = 0; jdx < *nPoints; jdx++) { + // add points to a point array for drawing the polygon + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; +#ifdef QGISX11DEBUG + std::cout << "Transforming " << *x << "," << *y << " to "; +#endif + ptr += sizeof(double); + pt.setX(*x); + pt.setY(*y); + cXf->transform(&pt); + pa->setPoint(pdx++, static_cast(pt.x()), static_cast(pt.y())); + } + if ( idx == 0 ) { // remember last outer ring point + x0 = static_cast(pt.x()); + y0 = static_cast(pt.y()); + } else { // return to x0,y0 (inner rings - islands) + pa->setPoint(pdx++, x0, y0); + } + } + // draw the polygon fill + pen = p->pen(); // store current pen + p->setPen ( Qt::NoPen ); // no boundary + p->drawPolygon(*pa); + + // draw outline + p->setPen ( pen ); + p->setBrush ( Qt::NoBrush ); + for (idx = 0; idx < *numRings; idx++) { + p->drawPolygon( *pa, FALSE, ringStart[idx], ringNumPoints[idx]); + } + + delete pa; + delete [] ringStart; + delete [] ringNumPoints; + + break; + + } + case WKBMultiPolygon: + { + unsigned char *ptr; + int idx, jdx, kdx; + int *numPolygons, *numRings, *nPoints; + QPointArray *pa; + + // get the number of polygons + ptr = feature + 5; + numPolygons = (int *) ptr; + ptr = feature + 9; + for (kdx = 0; kdx < *numPolygons; kdx++) + { + //skip the endian and feature type info and + // get number of rings in the polygon + ptr+=5; + numRings = (int *) ptr; + ptr += 4; + for (idx = 0; idx < *numRings; idx++) + { + // get number of points in the ring + nPoints = (int *) ptr; + ptr += 4; + pa = new QPointArray(*nPoints); + for (jdx = 0; jdx < *nPoints; jdx++) + { + // add points to a point array for drawing the polygon + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); +#ifdef QGISX11DEBUG + std::cout << "Transforming " << *x << "," << *y << " to "; +#endif + pt.setX(*x); + pt.setY(*y); + cXf->transform(&pt); + pa->setPoint(jdx, static_cast(pt.x()), static_cast(pt.y())); + } + // draw the ring + p->drawPolygon(*pa); + delete pa; + } + } + break; + } + default: +#ifdef QGISDEBUG + std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n"; +#endif + break; + } +} diff --git a/src/qgsvectorlayer.h b/src/qgsvectorlayer.h index f41f932f11d..a8973abcdae 100644 --- a/src/qgsvectorlayer.h +++ b/src/qgsvectorlayer.h @@ -210,9 +210,6 @@ class QgsVectorLayer : public QgsMapLayer /**Label is on */ bool labelOn( void ); - /**True if the layer can be edited*/ - bool isEditable(); - /** * Minimum scale at which the layer is rendered * @return Scale as integer @@ -228,11 +225,20 @@ class QgsVectorLayer : public QgsMapLayer * @return true if so */ bool scaleDependentRender(); + + /**Returns true if the provider is in editing mode*/ + virtual bool isEditable() const {return (mEditable&&dataProvider);} + + /**Returns true if the provider has been modified since the last commit*/ + virtual bool isModified() const {return mModified;} + protected: /**Pointer to the table display object if there is one, else a pointer to 0*/ QgsAttributeTableDisplay * tabledisplay; /**Vector holding the information which features are activated*/ - std::map < int, bool > selected; + std::set mSelected; + std::set mDeleted; + std::list mAddedFeatures; /**Color to and fill the selected features*/ QColor selectionColor; /**Renderer object which holds the information about how to display the features*/ @@ -245,11 +251,19 @@ protected: QgsDlgVectorLayerProperties *m_propertiesDialog; /**Widget to set the symbology properties*/ QDialog *m_rendererDialog; + /**Goes through all features and finds a free id (e.g. to give it temporarily to a not-commited feature)*/ + int findFreeId(); + /**Writes the changes to disk*/ + bool commitChanges(); + /**Discards the edits*/ + bool rollBack(); protected slots: void startEditing(); void stopEditing(); + void drawFeature(QPainter* p, QgsFeature* fet, QgsCoordinateTransform * cXf, QPicture* marker, double markerScaleFactor); + private: // Private attributes //! Draws the layer labels using coordinate transformation @@ -313,6 +327,11 @@ private: // Private methods // Identify Results dialog box QgsAttributeAction mActions; + /**Flag indicating wheter the layer is in editing mode or not*/ + bool mEditable; + /**Flag indicating wheter the layer has been modified since the last commit*/ + bool mModified; + }; #endif