moved the responsability for not-commited features to qgsvectorlayer. Because of this, it is now possible to treat not-commited features like commited ones. Vectordataproviders now only need to implement 'addFeatures','deleteFeatures', 'supportsFeatureAddition' and 'supportsFeatureDeletion' if they support feature addition or deletion

git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@2258 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
mhugent 2004-11-15 21:52:57 +00:00
parent c4c5d60b1c
commit 48bca3c901
20 changed files with 627 additions and 1011 deletions

View File

@ -448,7 +448,7 @@ QgsFeature *QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
return f;
}
QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list<int>& attlist, bool getnotcommited)
QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list<int>& 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
*/

View File

@ -48,7 +48,8 @@ public:
*/
QgsFeature * getNextFeature(bool fetchAttributes=false);
bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false);
QgsFeature * getNextFeature(std::list<int>& attlist, bool getnotcommited=false);
QgsFeature * getNextFeature(std::list<int>& 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

View File

@ -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<int> 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<int>& attlist,
bool getnotcommited) {
QgsFeature * QgsGPXProvider::getNextFeature(std::list<int>& 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<int>& attlist,
bool QgsGPXProvider::getNextFeature(QgsFeature* feature,
std::list<int>& attlist,
bool getnotcommitted) {
bool result = false;
std::list<int>& attlist) {
bool result = false;
std::list<int>::const_iterator iter;
/*std::list<int>::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<Waypoint*>(mAddedFeatures[i]));
else if (mFeatureType == RouteType)
data->addRoute(*dynamic_cast<Route*>(mAddedFeatures[i]));
else if (mFeatureType == TrackType)
data->addTrack(*dynamic_cast<Track*>(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<<qdd.toString();
}
else {
std::cerr<<"Could not write \""<<mFileName<<"\""<<std::endl;
return false;
}
return true;
}
bool QgsGPXProvider::rollBack() {
for (int i = 0; i < mAddedFeatures.size(); ++i)
delete mAddedFeatures[i];
mAddedFeatures.clear();
return true;
}
bool QgsGPXProvider::addFeature(QgsFeature* f) {
if (!mEditable)
return false;
GPSObject* obj = NULL;
unsigned char* geo = f->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!"<<std::endl;
return false;
}
mAddedFeatures.push_back(new Waypoint);
Waypoint* wpt(dynamic_cast<Waypoint*>(mAddedFeatures[mAddedFeatures.size() - 1]));
wpt->lat = *((double*)(geo + 5 + sizeof(double)));
wpt->lon = *((double*)(geo + 5));
// parse waypoint-specific attributes
std::vector<QgsFeatureAttribute>::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<double>::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!"<<std::endl;
return false;
}
// get the number of points
int length;
memcpy(&length,f->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<Route*>(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<Track*>(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<QgsFeatureAttribute>::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<int>::max();
}
}
obj = ext;
break;
}
// unsupported geometry - something's wrong
default:
return false;
}
// parse common attributes
std::vector<QgsFeatureAttribute>::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<QgsFeature*> flist) {
return false;
}

View File

@ -51,7 +51,7 @@ public:
*/
QgsFeature * getNextFeature(bool fetchAttributes=false);
bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false);
QgsFeature * getNextFeature(std::list<int>& attlist, bool getnotcommited=false);
QgsFeature * getNextFeature(std::list<int>& 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<QgsFeature*> 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<int>& attlist,
bool getnotcommitted);
bool getNextFeature(QgsFeature* feature, std::list<int>& attlist);
bool mEditable;
std::vector<GPSObject*> mAddedFeatures;

View File

@ -326,7 +326,7 @@ QgsFeature *QgsGrassProvider::getNextFeature(bool fetchAttributes)
return ( getNextFeature(attlist) );
}
QgsFeature* QgsGrassProvider::getNextFeature(std::list<int>& attlist, bool getnotcommited)
QgsFeature* QgsGrassProvider::getNextFeature(std::list<int>& 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 ) {

View File

@ -108,7 +108,7 @@ public:
*/
QgsFeature * getNextFeature(bool fetchAttributes=false);
bool getNextFeature(QgsFeature &feature, bool fetchAttributes=false);
QgsFeature* getNextFeature(std::list<int>& attlist, bool getnotcommited=false);
QgsFeature* getNextFeature(std::list<int>& 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,

View File

@ -120,13 +120,6 @@ QgsShapeFileProvider::~QgsShapeFileProvider()
}
delete[] minmaxcache;
//delete not commited features
for(std::list<QgsFeature*>::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<int>& attlist, bool getnotcommited)
QgsFeature *QgsShapeFileProvider::getNextFeature(std::list<int>& attlist)
{
QgsFeature *f = 0;
if(valid)
@ -408,26 +401,11 @@ QgsFeature *QgsShapeFileProvider::getNextFeature(std::list<int>& 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<QgsFeature*> flist)
{
#ifdef QGISDEBUG
int test=ogrLayer->TestCapability("OLCDeleteFeature");
if(!test)
bool returnvalue=true;
for(std::list<QgsFeature*>::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

View File

@ -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<int>& attlist, bool getnotcommited=false);
QgsFeature *getNextFeature(std::list<int>& 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<QgsFeature*> 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);
};

View File

@ -456,7 +456,7 @@ QgsFeature *QgsPostgresProvider::getNextFeature(bool fetchAttributes)
return f;
}
QgsFeature* QgsPostgresProvider::getNextFeature(std::list<int>& attlist, bool getnotcommited)
QgsFeature* QgsPostgresProvider::getNextFeature(std::list<int>& attlist)
{
QgsFeature *f = 0;
if (valid)
@ -465,36 +465,16 @@ QgsFeature* QgsPostgresProvider::getNextFeature(std::list<int>& 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<int>& attlist, bool ge
noid = &oid;
}
}
//block feature if oid is contained in mDeletedFeatures
std::set<int>::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<QgsFeature*> flist)
{
bool returnvalue=true;
for(std::list<QgsFeature*>::iterator it=flist.begin();it!=flist.end();++it)
{
if(!addFeature(*it))
{
returnvalue=false;
}
}
return returnvalue;
}
bool QgsPostgresProvider::deleteFeatures(std::list<int> id)
{
bool returnvalue=true;
for(std::list<int>::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

View File

@ -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<int>& attlist, bool getnotcommited=false);
QgsFeature* getNextFeature(std::list<int>& 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<QgsFeature*> 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<int> 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);
};

View File

@ -1870,11 +1870,6 @@ void QgisApp::deleteSelected()
if (li)
{
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(((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())

View File

@ -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
*/

View File

@ -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<QgsVectorLayer*>(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;

View File

@ -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

View File

@ -3142,7 +3142,7 @@ RasterPyramidList QgsRasterLayer::buildRasterPyramidList()
}
bool QgsRasterLayer::isEditable()
bool QgsRasterLayer::isEditable() const
{
return false;
}

View File

@ -769,7 +769,7 @@ public:
// RasterPyramid getRasterPyramid(int thePyramidNo);
/**Currently returns always false*/
bool isEditable();
bool isEditable() const;
public slots:

View File

@ -18,91 +18,19 @@
#include "qgsfeature.h"
QgsVectorDataProvider::QgsVectorDataProvider(): mEditable(false), mModified(false)
QgsVectorDataProvider::QgsVectorDataProvider()
{
}
bool QgsVectorDataProvider::startEditing()
bool QgsVectorDataProvider::addFeatures(std::list<QgsFeature*> flist)
{
//providers supporting editing need to overwrite this method
return false;
}
void QgsVectorDataProvider::stopEditing()
bool QgsVectorDataProvider::deleteFeatures(std::list<int> id)
{
mEditable=false;
}
bool QgsVectorDataProvider::commitChanges()
{
if(mEditable)
{
bool returnvalue=true;
for(std::list<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
{
if(!commitFeature(*it))
{
returnvalue=false;
}
delete *it;
}
for(std::set<int>::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<QgsFeature*>::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;
}

View File

@ -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<int>& attlist, bool getnotcommited=false)=0;
virtual QgsFeature * getNextFeature(std::list<int>& 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<QgsFeature*> 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<int> 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<QgsFeature>& 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<QgsFeature*> mAddedFeatures;
/**Ids of features to delete*/
std::set<int> 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<QgsFeature*>::iterator mAddedFeaturesIt;
/**Returns true if a provider supports deleting features*/
virtual bool supportsFeatureDeletion();
};
#endif

View File

@ -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<QgsFeature*>::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<int> 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<QgsFeature*>::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<int>(pt.x()), static_cast<int>(pt.y()), 5, 5);
p->scale(markerScaleFactor,markerScaleFactor);
p->drawPicture((int)(static_cast<int>(pt.x()) / markerScaleFactor - marker.boundingRect().width() / 2),
(int)(static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
else
p->lineTo(static_cast<int>(pt.x()), static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
else
p->lineTo(static_cast<int>(pt.x()), static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
}
if ( idx == 0 ) { // remember last outer ring point
x0 = static_cast<int>(pt.x());
y0 = static_cast<int>(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<int>(pt.x()), static_cast<int>(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<QgsFeature*>::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<int>::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<QgsFeature*>::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<QgsFeature*>::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<int,bool>::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<int>::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<QgsFeature*>::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<QgsFeature*> addedlist;
for(std::list<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
{
addedlist.push_back(*it);
}
if(!dataProvider->addFeatures(addedlist))
{
returnvalue=false;
}
for(std::list<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
{
delete *it;
}
mAddedFeatures.clear();
if(mDeleted.size()>0)
{
std::list<int> deletelist;
for(std::set<int>::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<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
{
delete *it;
mSelected.erase((*it)->featureId());
}
mAddedFeatures.clear();
for(std::set<int>::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<int>(pt.x()), static_cast<int>(pt.y()), 5, 5);
p->scale(markerScaleFactor,markerScaleFactor);
p->drawPicture((int)(static_cast<int>(pt.x()) / markerScaleFactor - marker->boundingRect().width() / 2),
(int)(static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
else
p->lineTo(static_cast<int>(pt.x()), static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
else
p->lineTo(static_cast<int>(pt.x()), static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
}
if ( idx == 0 ) { // remember last outer ring point
x0 = static_cast<int>(pt.x());
y0 = static_cast<int>(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<int>(pt.x()), static_cast<int>(pt.y()));
}
// draw the ring
p->drawPolygon(*pa);
delete pa;
}
}
break;
}
default:
#ifdef QGISDEBUG
std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n";
#endif
break;
}
}

View File

@ -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<int> mSelected;
std::set<int> mDeleted;
std::list<QgsFeature*> 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