Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsvectorlayer.cpp 00003 -------------------- 00004 begin : Oct 29, 2003 00005 copyright : (C) 2003 by Gary E.Sherman 00006 email : sherman at mrcc.com 00007 00008 This class implements a generic means to display vector layers. The features 00009 and attributes are read from the data store using a "data provider" plugin. 00010 QgsVectorLayer can be used with any data store for which an appropriate 00011 plugin is available. 00012 00013 ***************************************************************************/ 00014 00015 /*************************************************************************** 00016 * * 00017 * This program is free software; you can redistribute it and/or modify * 00018 * it under the terms of the GNU General Public License as published by * 00019 * the Free Software Foundation; either version 2 of the License, or * 00020 * (at your option) any later version. * 00021 * * 00022 ***************************************************************************/ 00023 00024 #include <limits> 00025 00026 #include <QImage> 00027 #include <QPainter> 00028 #include <QPainterPath> 00029 #include <QPolygonF> 00030 #include <QSettings> 00031 #include <QString> 00032 #include <QDomNode> 00033 00034 #include "qgsvectorlayer.h" 00035 00036 // renderers 00037 #include "qgscontinuouscolorrenderer.h" 00038 #include "qgsgraduatedsymbolrenderer.h" 00039 #include "qgsrenderer.h" 00040 #include "qgssinglesymbolrenderer.h" 00041 #include "qgsuniquevaluerenderer.h" 00042 00043 #include "qgsattributeaction.h" 00044 00045 #include "qgis.h" //for globals 00046 #include "qgsapplication.h" 00047 #include "qgscoordinatetransform.h" 00048 #include "qgsfeature.h" 00049 #include "qgsfield.h" 00050 #include "qgsgeometry.h" 00051 #include "qgslabel.h" 00052 #include "qgslogger.h" 00053 #include "qgsmessagelog.h" 00054 #include "qgsmaptopixel.h" 00055 #include "qgspoint.h" 00056 #include "qgsproviderregistry.h" 00057 #include "qgsrectangle.h" 00058 #include "qgsrendercontext.h" 00059 #include "qgscoordinatereferencesystem.h" 00060 #include "qgsvectordataprovider.h" 00061 #include "qgsvectorlayerjoinbuffer.h" 00062 #include "qgsvectorlayerundocommand.h" 00063 #include "qgsvectoroverlay.h" 00064 #include "qgsmaplayerregistry.h" 00065 #include "qgsclipper.h" 00066 #include "qgsproject.h" 00067 00068 #include "qgsrendererv2.h" 00069 #include "qgssymbolv2.h" 00070 #include "qgssymbollayerv2.h" 00071 #include "qgssinglesymbolrendererv2.h" 00072 #include "qgsdiagramrendererv2.h" 00073 00074 #ifdef TESTPROVIDERLIB 00075 #include <dlfcn.h> 00076 #endif 00077 00078 00079 // typedef for the QgsDataProvider class factory 00080 typedef QgsDataProvider * create_it( const QString* uri ); 00081 00082 00083 00084 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath, 00085 QString baseName, 00086 QString providerKey, 00087 bool loadDefaultStyleFlag ) 00088 : QgsMapLayer( VectorLayer, baseName, vectorLayerPath ) 00089 , mUpdateThreshold( 0 ) // XXX better default value? 00090 , mDataProvider( NULL ) 00091 , mProviderKey( providerKey ) 00092 , mEditable( false ) 00093 , mReadOnly( false ) 00094 , mModified( false ) 00095 , mMaxUpdatedIndex( -1 ) 00096 , mActiveCommand( NULL ) 00097 , mRenderer( 0 ) 00098 , mRendererV2( NULL ) 00099 , mUsingRendererV2( false ) 00100 , mLabel( 0 ) 00101 , mLabelOn( false ) 00102 , mVertexMarkerOnlyForSelection( false ) 00103 , mFetching( false ) 00104 , mJoinBuffer( 0 ) 00105 , mDiagramRenderer( 0 ) 00106 , mDiagramLayerSettings( 0 ) 00107 { 00108 mActions = new QgsAttributeAction( this ); 00109 00110 // if we're given a provider type, try to create and bind one to this layer 00111 if ( ! mProviderKey.isEmpty() ) 00112 { 00113 setDataProvider( mProviderKey ); 00114 } 00115 if ( mValid ) 00116 { 00117 // Always set crs 00118 setCoordinateSystem(); 00119 00120 QSettings settings; 00121 //Changed to default to true as of QGIS 1.7 00122 //TODO: remove hack when http://hub.qgis.org/issues/5170 is fixed 00123 #ifdef ANDROID 00124 bool use_symbology_ng_default = false; 00125 #else 00126 bool use_symbology_ng_default = true; 00127 #endif 00128 if ( settings.value( "/qgis/use_symbology_ng", use_symbology_ng_default ).toBool() && hasGeometryType() ) 00129 { 00130 // using symbology-ng! 00131 setUsingRendererV2( true ); 00132 } 00133 00134 // check if there is a default style / propertysheet defined 00135 // for this layer and if so apply it 00136 bool defaultLoadedFlag = false; 00137 if ( loadDefaultStyleFlag ) 00138 { 00139 loadDefaultStyle( defaultLoadedFlag ); 00140 } 00141 00142 // if the default style failed to load or was disabled use some very basic defaults 00143 if ( !defaultLoadedFlag && hasGeometryType() ) 00144 { 00145 // add single symbol renderer 00146 if ( mUsingRendererV2 ) 00147 { 00148 setRendererV2( QgsFeatureRendererV2::defaultRenderer( geometryType() ) ); 00149 } 00150 else 00151 { 00152 QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( geometryType() ); 00153 setRenderer( renderer ); 00154 } 00155 } 00156 00157 mJoinBuffer = new QgsVectorLayerJoinBuffer(); 00158 00159 connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) ); 00160 updateFieldMap(); 00161 00162 // Get the update threshold from user settings. We 00163 // do this only on construction to avoid the penality of 00164 // fetching this each time the layer is drawn. If the user 00165 // changes the threshold from the preferences dialog, it will 00166 // have no effect on existing layers 00167 // TODO: load this setting somewhere else [MD] 00168 //QSettings settings; 00169 //mUpdateThreshold = settings.readNumEntry("Map/updateThreshold", 1000); 00170 } 00171 } // QgsVectorLayer ctor 00172 00173 00174 00175 QgsVectorLayer::~QgsVectorLayer() 00176 { 00177 QgsDebugMsg( "entered." ); 00178 00179 emit layerDeleted(); 00180 00181 mValid = false; 00182 00183 delete mRenderer; 00184 delete mDataProvider; 00185 delete mJoinBuffer; 00186 delete mLabel; 00187 delete mDiagramLayerSettings; 00188 00189 // Destroy any cached geometries and clear the references to them 00190 deleteCachedGeometries(); 00191 00192 delete mActions; 00193 00194 //delete remaining overlays 00195 00196 QList<QgsVectorOverlay*>::iterator overlayIt = mOverlays.begin(); 00197 for ( ; overlayIt != mOverlays.end(); ++overlayIt ) 00198 { 00199 delete *overlayIt; 00200 } 00201 } 00202 00203 QString QgsVectorLayer::storageType() const 00204 { 00205 if ( mDataProvider ) 00206 { 00207 return mDataProvider->storageType(); 00208 } 00209 return 0; 00210 } 00211 00212 00213 QString QgsVectorLayer::capabilitiesString() const 00214 { 00215 if ( mDataProvider ) 00216 { 00217 return mDataProvider->capabilitiesString(); 00218 } 00219 return 0; 00220 } 00221 00222 QString QgsVectorLayer::dataComment() const 00223 { 00224 if ( mDataProvider ) 00225 { 00226 return mDataProvider->dataComment(); 00227 } 00228 return QString(); 00229 } 00230 00231 00232 QString QgsVectorLayer::providerType() const 00233 { 00234 return mProviderKey; 00235 } 00236 00240 void QgsVectorLayer::setDisplayField( QString fldName ) 00241 { 00242 if ( !hasGeometryType() ) 00243 return; 00244 00245 // If fldName is provided, use it as the display field, otherwise 00246 // determine the field index for the feature column of the identify 00247 // dialog. We look for fields containing "name" first and second for 00248 // fields containing "id". If neither are found, the first field 00249 // is used as the node. 00250 QString idxName = ""; 00251 QString idxId = ""; 00252 00253 if ( !fldName.isEmpty() ) 00254 { 00255 mDisplayField = fldName; 00256 } 00257 else 00258 { 00259 const QgsFieldMap &fields = pendingFields(); 00260 int fieldsSize = fields.size(); 00261 00262 for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it ) 00263 { 00264 QString fldName = it.value().name(); 00265 QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" ); 00266 00267 // Check the fields and keep the first one that matches. 00268 // We assume that the user has organized the data with the 00269 // more "interesting" field names first. As such, name should 00270 // be selected before oldname, othername, etc. 00271 if ( fldName.indexOf( "name", false ) > -1 ) 00272 { 00273 if ( idxName.isEmpty() ) 00274 { 00275 idxName = fldName; 00276 } 00277 } 00278 if ( fldName.indexOf( "descrip", false ) > -1 ) 00279 { 00280 if ( idxName.isEmpty() ) 00281 { 00282 idxName = fldName; 00283 } 00284 } 00285 if ( fldName.indexOf( "id", false ) > -1 ) 00286 { 00287 if ( idxId.isEmpty() ) 00288 { 00289 idxId = fldName; 00290 } 00291 } 00292 } 00293 00294 //if there were no fields in the dbf just return - otherwise qgis segfaults! 00295 if ( fieldsSize == 0 ) 00296 return; 00297 00298 if ( idxName.length() > 0 ) 00299 { 00300 mDisplayField = idxName; 00301 } 00302 else 00303 { 00304 if ( idxId.length() > 0 ) 00305 { 00306 mDisplayField = idxId; 00307 } 00308 else 00309 { 00310 mDisplayField = fields[0].name(); 00311 } 00312 } 00313 00314 } 00315 } 00316 00317 // NOTE this is a temporary method added by Tim to prevent label clipping 00318 // which was occurring when labeller was called in the main draw loop 00319 // This method will probably be removed again in the near future! 00320 void QgsVectorLayer::drawLabels( QgsRenderContext& rendererContext ) 00321 { 00322 if ( !hasGeometryType() ) 00323 return; 00324 00325 QgsDebugMsg( "Starting draw of labels: " + id() ); 00326 00327 if (( mRenderer || mRendererV2 ) && mLabelOn && 00328 ( !mLabel->scaleBasedVisibility() || 00329 ( mLabel->minScale() <= rendererContext.rendererScale() && 00330 rendererContext.rendererScale() <= mLabel->maxScale() ) ) ) 00331 { 00332 QgsAttributeList attributes; 00333 if ( mRenderer ) 00334 { 00335 attributes = mRenderer->classificationAttributes(); 00336 } 00337 else if ( mRendererV2 ) 00338 { 00339 foreach( QString attrName, mRendererV2->usedAttributes() ) 00340 { 00341 int attrNum = fieldNameIndex( attrName ); 00342 attributes.append( attrNum ); 00343 } 00344 // make sure the renderer is ready for classification ("symbolForFeature") 00345 mRendererV2->startRender( rendererContext, this ); 00346 } 00347 00348 // Add fields required for labels 00349 mLabel->addRequiredFields( attributes ); 00350 00351 QgsDebugMsg( "Selecting features based on view extent" ); 00352 00353 int featureCount = 0; 00354 00355 try 00356 { 00357 // select the records in the extent. The provider sets a spatial filter 00358 // and sets up the selection set for retrieval 00359 select( attributes, rendererContext.extent() ); 00360 00361 QgsFeature fet; 00362 while ( nextFeature( fet ) ) 00363 { 00364 if (( mRenderer && mRenderer->willRenderFeature( &fet ) ) 00365 || ( mRendererV2 && mRendererV2->willRenderFeature( fet ) ) ) 00366 { 00367 bool sel = mSelectedFeatureIds.contains( fet.id() ); 00368 mLabel->renderLabel( rendererContext, fet, sel, 0 ); 00369 } 00370 featureCount++; 00371 } 00372 } 00373 catch ( QgsCsException &e ) 00374 { 00375 Q_UNUSED( e ); 00376 QgsDebugMsg( "Error projecting label locations" ); 00377 } 00378 00379 if ( mRendererV2 ) 00380 { 00381 mRendererV2->stopRender( rendererContext ); 00382 } 00383 00384 QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) ); 00385 00386 // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06] 00387 // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes. 00388 //qApp->processEvents(); 00389 00390 } 00391 } 00392 00393 00394 unsigned char *QgsVectorLayer::drawLineString( unsigned char *feature, QgsRenderContext &renderContext ) 00395 { 00396 QPainter *p = renderContext.painter(); 00397 unsigned char *ptr = feature + 5; 00398 unsigned int wkbType = *(( int* )( feature + 1 ) ); 00399 unsigned int nPoints = *(( int* )ptr ); 00400 ptr = feature + 9; 00401 00402 bool hasZValue = ( wkbType == QGis::WKBLineString25D ); 00403 00404 std::vector<double> x( nPoints ); 00405 std::vector<double> y( nPoints ); 00406 std::vector<double> z( nPoints, 0.0 ); 00407 00408 // Extract the points from the WKB format into the x and y vectors. 00409 for ( register unsigned int i = 0; i < nPoints; ++i ) 00410 { 00411 x[i] = *(( double * ) ptr ); 00412 ptr += sizeof( double ); 00413 y[i] = *(( double * ) ptr ); 00414 ptr += sizeof( double ); 00415 00416 if ( hasZValue ) // ignore Z value 00417 ptr += sizeof( double ); 00418 } 00419 00420 // Transform the points into map coordinates (and reproject if 00421 // necessary) 00422 00423 transformPoints( x, y, z, renderContext ); 00424 00425 // Work around a +/- 32768 limitation on coordinates 00426 // Look through the x and y coordinates and see if there are any 00427 // that need trimming. If one is found, there's no need to look at 00428 // the rest of them so end the loop at that point. 00429 for ( register unsigned int i = 0; i < nPoints; ++i ) 00430 { 00431 if ( qAbs( x[i] ) > QgsClipper::MAX_X || 00432 qAbs( y[i] ) > QgsClipper::MAX_Y ) 00433 { 00434 QgsClipper::trimFeature( x, y, true ); // true = polyline 00435 nPoints = x.size(); // trimming may change nPoints. 00436 break; 00437 } 00438 } 00439 00440 // set up QPolygonF class with transformed points 00441 QPolygonF pa( nPoints ); 00442 for ( register unsigned int i = 0; i < nPoints; ++i ) 00443 { 00444 pa[i].setX( x[i] ); 00445 pa[i].setY( y[i] ); 00446 } 00447 00448 // The default pen gives bevelled joins between segements of the 00449 // polyline, which is good enough for the moment. 00450 //preserve a copy of the pen before we start fiddling with it 00451 QPen pen = p->pen(); // to be kept original 00452 00453 // 00454 // experimental alpha transparency 00455 // 255 = opaque 00456 // 00457 QPen myTransparentPen = p->pen(); // store current pen 00458 QColor myColor = myTransparentPen.color(); 00459 //only set transparency from layer level if renderer does not provide 00460 //transparency on class level 00461 if ( !mRenderer->usesTransparency() ) 00462 { 00463 myColor.setAlpha( mTransparencyLevel ); 00464 } 00465 myTransparentPen.setColor( myColor ); 00466 p->setPen( myTransparentPen ); 00467 p->drawPolyline( pa ); 00468 00469 // draw vertex markers if in editing mode, but only to the main canvas 00470 if ( mEditable && renderContext.drawEditingInformation() ) 00471 { 00472 00473 std::vector<double>::const_iterator xIt; 00474 std::vector<double>::const_iterator yIt; 00475 for ( xIt = x.begin(), yIt = y.begin(); xIt != x.end(); ++xIt, ++yIt ) 00476 { 00477 drawVertexMarker( *xIt, *yIt, *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize ); 00478 } 00479 } 00480 00481 //restore the pen 00482 p->setPen( pen ); 00483 00484 return ptr; 00485 } 00486 00487 unsigned char *QgsVectorLayer::drawPolygon( unsigned char *feature, QgsRenderContext &renderContext ) 00488 { 00489 QPainter *p = renderContext.painter(); 00490 typedef std::pair<std::vector<double>, std::vector<double> > ringType; 00491 typedef ringType* ringTypePtr; 00492 typedef std::vector<ringTypePtr> ringsType; 00493 00494 // get number of rings in the polygon 00495 unsigned int numRings = *(( int* )( feature + 1 + sizeof( int ) ) ); 00496 00497 if ( numRings == 0 ) // sanity check for zero rings in polygon 00498 return feature + 9; 00499 00500 unsigned int wkbType = *(( int* )( feature + 1 ) ); 00501 00502 bool hasZValue = ( wkbType == QGis::WKBPolygon25D ); 00503 00504 int total_points = 0; 00505 00506 // A vector containing a pointer to a pair of double vectors.The 00507 // first vector in the pair contains the x coordinates, and the 00508 // second the y coordinates. 00509 ringsType rings; 00510 00511 // Set pointer to the first ring 00512 unsigned char* ptr = feature + 1 + 2 * sizeof( int ); 00513 00514 for ( register unsigned int idx = 0; idx < numRings; idx++ ) 00515 { 00516 unsigned int nPoints = *(( int* )ptr ); 00517 00518 ringTypePtr ring = new ringType( std::vector<double>( nPoints ), std::vector<double>( nPoints ) ); 00519 ptr += 4; 00520 00521 // create a dummy vector for the z coordinate 00522 std::vector<double> zVector( nPoints, 0.0 ); 00523 // Extract the points from the WKB and store in a pair of 00524 // vectors. 00525 for ( register unsigned int jdx = 0; jdx < nPoints; jdx++ ) 00526 { 00527 ring->first[jdx] = *(( double * ) ptr ); 00528 ptr += sizeof( double ); 00529 ring->second[jdx] = *(( double * ) ptr ); 00530 ptr += sizeof( double ); 00531 00532 if ( hasZValue ) 00533 ptr += sizeof( double ); 00534 } 00535 // If ring has fewer than two points, what is it then? 00536 // Anyway, this check prevents a crash 00537 if ( nPoints < 1 ) 00538 { 00539 QgsDebugMsg( "Ring has only " + QString::number( nPoints ) + " points! Skipping this ring." ); 00540 continue; 00541 } 00542 00543 transformPoints( ring->first, ring->second, zVector, renderContext ); 00544 00545 // Work around a +/- 32768 limitation on coordinates 00546 // Look through the x and y coordinates and see if there are any 00547 // that need trimming. If one is found, there's no need to look at 00548 // the rest of them so end the loop at that point. 00549 for ( register unsigned int i = 0; i < nPoints; ++i ) 00550 { 00551 if ( qAbs( ring->first[i] ) > QgsClipper::MAX_X || 00552 qAbs( ring->second[i] ) > QgsClipper::MAX_Y ) 00553 { 00554 QgsClipper::trimFeature( ring->first, ring->second, false ); 00555 break; 00556 } 00557 } 00558 00559 // Don't bother keeping the ring if it has been trimmed out of 00560 // existence. 00561 if ( ring->first.size() == 0 ) 00562 delete ring; 00563 else 00564 { 00565 rings.push_back( ring ); 00566 total_points += ring->first.size(); 00567 } 00568 } 00569 00570 // Now we draw the polygons 00571 00572 // use painter paths for drawing polygons with holes 00573 // when adding polygon to the path they invert the area 00574 // this means that adding inner rings to the path creates 00575 // holes in outer ring 00576 QPainterPath path; // OddEven fill rule by default 00577 00578 // Only try to draw polygons if there is something to draw 00579 if ( total_points > 0 ) 00580 { 00581 //preserve a copy of the brush and pen before we start fiddling with it 00582 QBrush brush = p->brush(); //to be kept as original 00583 QPen pen = p->pen(); // to be kept original 00584 // 00585 // experimental alpha transparency 00586 // 255 = opaque 00587 // 00588 QBrush myTransparentBrush = p->brush(); 00589 QColor myColor = brush.color(); 00590 00591 //only set transparency from layer level if renderer does not provide 00592 //transparency on class level 00593 if ( !mRenderer->usesTransparency() ) 00594 { 00595 myColor.setAlpha( mTransparencyLevel ); 00596 } 00597 myTransparentBrush.setColor( myColor ); 00598 QPen myTransparentPen = p->pen(); // store current pen 00599 myColor = myTransparentPen.color(); 00600 00601 //only set transparency from layer level if renderer does not provide 00602 //transparency on class level 00603 if ( !mRenderer->usesTransparency() ) 00604 { 00605 myColor.setAlpha( mTransparencyLevel ); 00606 } 00607 myTransparentPen.setColor( myColor ); 00608 00609 p->setBrush( myTransparentBrush ); 00610 p->setPen( myTransparentPen ); 00611 00612 if ( numRings == 1 ) 00613 { 00614 ringTypePtr r = rings[0]; 00615 unsigned ringSize = r->first.size(); 00616 00617 QPolygonF pa( ringSize ); 00618 for ( register unsigned int j = 0; j != ringSize; ++j ) 00619 { 00620 pa[j].setX( r->first[j] ); 00621 pa[j].setY( r->second[j] ); 00622 } 00623 p->drawPolygon( pa ); 00624 00625 // draw vertex markers if in editing mode, but only to the main canvas 00626 if ( mEditable && renderContext.drawEditingInformation() ) 00627 { 00628 for ( register unsigned int j = 0; j != ringSize; ++j ) 00629 { 00630 drawVertexMarker( r->first[j], r->second[j], *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize ); 00631 } 00632 } 00633 00634 delete rings[0]; 00635 } 00636 else 00637 { 00638 // Store size here and use it in the loop to avoid penalty of 00639 // multiple calls to size() 00640 int numRings = rings.size(); 00641 for ( register int i = 0; i < numRings; ++i ) 00642 { 00643 // Store the pointer in a variable with a short name so as to make 00644 // the following code easier to type and read. 00645 ringTypePtr r = rings[i]; 00646 // only do this once to avoid penalty of additional calls 00647 unsigned ringSize = r->first.size(); 00648 00649 // Transfer points to the array of QPointF 00650 QPolygonF pa( ringSize ); 00651 for ( register unsigned int j = 0; j != ringSize; ++j ) 00652 { 00653 pa[j].setX( r->first[j] ); 00654 pa[j].setY( r->second[j] ); 00655 } 00656 00657 path.addPolygon( pa ); 00658 00659 // Tidy up the pointed to pairs of vectors as we finish with them 00660 delete rings[i]; 00661 } 00662 00663 #if 0 00664 // A bit of code to aid in working out what values of 00665 // QgsClipper::minX, etc cause the X11 zoom bug. 00666 int largestX = -std::numeric_limits<int>::max(); 00667 int smallestX = std::numeric_limits<int>::max(); 00668 int largestY = -std::numeric_limits<int>::max(); 00669 int smallestY = std::numeric_limits<int>::max(); 00670 00671 for ( int i = 0; i < pa.size(); ++i ) 00672 { 00673 largestX = qMax( largestX, pa.point( i ).x() ); 00674 smallestX = qMin( smallestX, pa.point( i ).x() ); 00675 largestY = qMax( largestY, pa.point( i ).y() ); 00676 smallestY = qMin( smallestY, pa.point( i ).y() ); 00677 } 00678 QgsDebugMsg( QString( "Largest X coordinate was %1" ).arg( largestX ) ); 00679 QgsDebugMsg( QString( "Smallest X coordinate was %1" ).arg( smallestX ) ); 00680 QgsDebugMsg( QString( "Largest Y coordinate was %1" ).arg( largestY ) ); 00681 QgsDebugMsg( QString( "Smallest Y coordinate was %1" ).arg( smallestY ) ); 00682 #endif 00683 00684 // 00685 // draw the polygon 00686 // 00687 p->drawPath( path ); 00688 00689 // draw vertex markers if in editing mode, but only to the main canvas 00690 if ( mEditable && renderContext.drawEditingInformation() ) 00691 { 00692 for ( int i = 0; i < path.elementCount(); ++i ) 00693 { 00694 const QPainterPath::Element & e = path.elementAt( i ); 00695 drawVertexMarker( e.x, e.y, *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize ); 00696 } 00697 } 00698 } 00699 00700 // 00701 //restore brush and pen to original 00702 // 00703 p->setBrush( brush ); 00704 p->setPen( pen ); 00705 00706 } // totalPoints > 0 00707 00708 return ptr; 00709 } 00710 00711 void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling ) 00712 { 00713 if ( !hasGeometryType() ) 00714 return; 00715 00716 QSettings settings; 00717 bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool(); 00718 00719 mRendererV2->startRender( rendererContext, this ); 00720 00721 #ifndef Q_WS_MAC 00722 int featureCount = 0; 00723 #endif //Q_WS_MAC 00724 00725 QgsFeature fet; 00726 while ( nextFeature( fet ) ) 00727 { 00728 try 00729 { 00730 if ( rendererContext.renderingStopped() ) 00731 { 00732 break; 00733 } 00734 00735 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing 00736 if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold ) 00737 { 00738 emit screenUpdateRequested(); 00739 // emit drawingProgress( featureCount, totalFeatures ); 00740 qApp->processEvents(); 00741 } 00742 else if ( featureCount % 1000 == 0 ) 00743 { 00744 // emit drawingProgress( featureCount, totalFeatures ); 00745 qApp->processEvents(); 00746 } 00747 #endif //Q_WS_MAC 00748 00749 bool sel = mSelectedFeatureIds.contains( fet.id() ); 00750 bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) ); 00751 00752 // render feature 00753 bool rendered = mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker ); 00754 00755 if ( mEditable ) 00756 { 00757 // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry. 00758 mCachedGeometries[fet.id()] = *fet.geometry(); 00759 } 00760 00761 // labeling - register feature 00762 if ( rendered && rendererContext.labelingEngine() ) 00763 { 00764 if ( labeling ) 00765 { 00766 rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); 00767 } 00768 if ( mDiagramRenderer ) 00769 { 00770 rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext ); 00771 } 00772 } 00773 } 00774 catch ( const QgsCsException &cse ) 00775 { 00776 Q_UNUSED( cse ); 00777 QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" ) 00778 .arg( fet.typeName() ).arg( cse.what() ) ); 00779 } 00780 #ifndef Q_WS_MAC 00781 ++featureCount; 00782 #endif //Q_WS_MAC 00783 } 00784 00785 stopRendererV2( rendererContext, NULL ); 00786 00787 #ifndef Q_WS_MAC 00788 QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) ); 00789 #endif 00790 } 00791 00792 void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling ) 00793 { 00794 if ( !hasGeometryType() ) 00795 return; 00796 00797 QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features 00798 00799 QSettings settings; 00800 bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool(); 00801 00802 // startRender must be called before symbolForFeature() calls to make sure renderer is ready 00803 mRendererV2->startRender( rendererContext, this ); 00804 00805 QgsSingleSymbolRendererV2* selRenderer = NULL; 00806 if ( !mSelectedFeatureIds.isEmpty() ) 00807 { 00808 selRenderer = new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geometryType() ) ); 00809 selRenderer->symbol()->setColor( QgsRenderer::selectionColor() ); 00810 selRenderer->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() ); 00811 selRenderer->startRender( rendererContext, this ); 00812 } 00813 00814 // 1. fetch features 00815 QgsFeature fet; 00816 #ifndef Q_WS_MAC 00817 int featureCount = 0; 00818 #endif //Q_WS_MAC 00819 while ( nextFeature( fet ) ) 00820 { 00821 if ( rendererContext.renderingStopped() ) 00822 { 00823 stopRendererV2( rendererContext, selRenderer ); 00824 return; 00825 } 00826 #ifndef Q_WS_MAC 00827 if ( featureCount % 1000 == 0 ) 00828 { 00829 qApp->processEvents(); 00830 } 00831 #endif //Q_WS_MAC 00832 QgsSymbolV2* sym = mRendererV2->symbolForFeature( fet ); 00833 if ( !sym ) 00834 { 00835 continue; 00836 } 00837 00838 if ( !features.contains( sym ) ) 00839 { 00840 features.insert( sym, QList<QgsFeature>() ); 00841 } 00842 features[sym].append( fet ); 00843 00844 if ( mEditable ) 00845 { 00846 // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry. 00847 mCachedGeometries[fet.id()] = *fet.geometry(); 00848 } 00849 00850 if ( sym && rendererContext.labelingEngine() ) 00851 { 00852 if ( labeling ) 00853 { 00854 rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); 00855 } 00856 if ( mDiagramRenderer ) 00857 { 00858 rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext ); 00859 } 00860 } 00861 00862 #ifndef Q_WS_MAC 00863 ++featureCount; 00864 #endif //Q_WS_MAC 00865 } 00866 00867 // find out the order 00868 QgsSymbolV2LevelOrder levels; 00869 QgsSymbolV2List symbols = mRendererV2->symbols(); 00870 for ( int i = 0; i < symbols.count(); i++ ) 00871 { 00872 QgsSymbolV2* sym = symbols[i]; 00873 for ( int j = 0; j < sym->symbolLayerCount(); j++ ) 00874 { 00875 int level = sym->symbolLayer( j )->renderingPass(); 00876 if ( level < 0 || level >= 1000 ) // ignore invalid levels 00877 continue; 00878 QgsSymbolV2LevelItem item( sym, j ); 00879 while ( level >= levels.count() ) // append new empty levels 00880 levels.append( QgsSymbolV2Level() ); 00881 levels[level].append( item ); 00882 } 00883 } 00884 00885 // 2. draw features in correct order 00886 for ( int l = 0; l < levels.count(); l++ ) 00887 { 00888 QgsSymbolV2Level& level = levels[l]; 00889 for ( int i = 0; i < level.count(); i++ ) 00890 { 00891 QgsSymbolV2LevelItem& item = level[i]; 00892 if ( !features.contains( item.symbol() ) ) 00893 { 00894 QgsDebugMsg( "level item's symbol not found!" ); 00895 continue; 00896 } 00897 int layer = item.layer(); 00898 QList<QgsFeature>& lst = features[item.symbol()]; 00899 QList<QgsFeature>::iterator fit; 00900 #ifndef Q_WS_MAC 00901 featureCount = 0; 00902 #endif //Q_WS_MAC 00903 for ( fit = lst.begin(); fit != lst.end(); ++fit ) 00904 { 00905 if ( rendererContext.renderingStopped() ) 00906 { 00907 stopRendererV2( rendererContext, selRenderer ); 00908 return; 00909 } 00910 #ifndef Q_WS_MAC 00911 if ( featureCount % 1000 == 0 ) 00912 { 00913 qApp->processEvents(); 00914 } 00915 #endif //Q_WS_MAC 00916 bool sel = mSelectedFeatureIds.contains( fit->id() ); 00917 // maybe vertex markers should be drawn only during the last pass... 00918 bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) ); 00919 00920 try 00921 { 00922 mRendererV2->renderFeature( *fit, rendererContext, layer, sel, drawMarker ); 00923 } 00924 catch ( const QgsCsException &cse ) 00925 { 00926 Q_UNUSED( cse ); 00927 QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" ) 00928 .arg( fet.typeName() ).arg( cse.what() ) ); 00929 } 00930 #ifndef Q_WS_MAC 00931 ++featureCount; 00932 #endif //Q_WS_MAC 00933 } 00934 } 00935 } 00936 00937 stopRendererV2( rendererContext, selRenderer ); 00938 } 00939 00940 void QgsVectorLayer::reload() 00941 { 00942 if ( mDataProvider ) 00943 { 00944 mDataProvider->reloadData(); 00945 } 00946 } 00947 00948 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext ) 00949 { 00950 if ( !hasGeometryType() ) 00951 return true; 00952 00953 //set update threshold before each draw to make sure the current setting is picked up 00954 QSettings settings; 00955 mUpdateThreshold = settings.value( "Map/updateThreshold", 0 ).toInt(); 00956 00957 if ( mUsingRendererV2 ) 00958 { 00959 if ( !mRendererV2 ) 00960 return false; 00961 00962 QgsDebugMsg( "rendering v2:\n" + mRendererV2->dump() ); 00963 00964 if ( mEditable ) 00965 { 00966 // Destroy all cached geometries and clear the references to them 00967 deleteCachedGeometries(); 00968 mCachedGeometriesRect = rendererContext.extent(); 00969 00970 // set editing vertex markers style 00971 mRendererV2->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() ); 00972 } 00973 00974 QgsAttributeList attributes; 00975 foreach( QString attrName, mRendererV2->usedAttributes() ) 00976 { 00977 int attrNum = fieldNameIndex( attrName ); 00978 attributes.append( attrNum ); 00979 QgsDebugMsg( "attrs: " + attrName + " - " + QString::number( attrNum ) ); 00980 } 00981 00982 bool labeling = false; 00983 //register label and diagram layer to the labeling engine 00984 prepareLabelingAndDiagrams( rendererContext, attributes, labeling ); 00985 00986 select( attributes, rendererContext.extent() ); 00987 00988 if (( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels ) 00989 && mRendererV2->usingSymbolLevels() ) 00990 drawRendererV2Levels( rendererContext, labeling ); 00991 else 00992 drawRendererV2( rendererContext, labeling ); 00993 00994 return true; 00995 } 00996 00997 //draw ( p, viewExtent, theMapToPixelTransform, ct, drawingToEditingCanvas, 1., 1.); 00998 00999 if ( mRenderer ) 01000 { 01001 // painter is active (begin has been called 01002 /* Steps to draw the layer 01003 1. get the features in the view extent by SQL query 01004 2. read WKB for a feature 01005 3. transform 01006 4. draw 01007 */ 01008 01009 QPen pen; 01010 /*Pointer to a marker image*/ 01011 QImage marker; 01012 //vertex marker type for selection 01013 QgsVectorLayer::VertexMarkerType vertexMarker = QgsVectorLayer::NoMarker; 01014 int vertexMarkerSize = 7; 01015 01016 if ( mEditable ) 01017 { 01018 // Destroy all cached geometries and clear the references to them 01019 deleteCachedGeometries(); 01020 mCachedGeometriesRect = rendererContext.extent(); 01021 vertexMarker = currentVertexMarkerType(); 01022 vertexMarkerSize = currentVertexMarkerSize(); 01023 mVertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool(); 01024 } 01025 01026 // int totalFeatures = pendingFeatureCount(); 01027 int featureCount = 0; 01028 QgsFeature fet; 01029 QgsAttributeList attributes = mRenderer->classificationAttributes(); 01030 01031 bool labeling = false; 01032 prepareLabelingAndDiagrams( rendererContext, attributes, labeling ); 01033 01034 select( attributes, rendererContext.extent() ); 01035 01036 try 01037 { 01038 while ( nextFeature( fet ) ) 01039 { 01040 01041 if ( rendererContext.renderingStopped() ) 01042 { 01043 break; 01044 } 01045 01046 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing 01047 if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold ) 01048 { 01049 emit screenUpdateRequested(); 01050 // emit drawingProgress( featureCount, totalFeatures ); 01051 qApp->processEvents(); 01052 } 01053 else if ( featureCount % 1000 == 0 ) 01054 { 01055 // emit drawingProgress( featureCount, totalFeatures ); 01056 qApp->processEvents(); 01057 } 01058 // #else 01059 // Q_UNUSED( totalFeatures ); 01060 #endif //Q_WS_MAC 01061 01062 // check if feature is selected 01063 // only show selections of the current layer 01064 // TODO: create a mechanism to let layer know whether it's current layer or not [MD] 01065 bool sel = mSelectedFeatureIds.contains( fet.id() ); 01066 01067 mCurrentVertexMarkerType = QgsVectorLayer::NoMarker; 01068 mCurrentVertexMarkerSize = 7; 01069 01070 if ( mEditable ) 01071 { 01072 // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry. 01073 mCachedGeometries[fet.id()] = *fet.geometry(); 01074 01075 if ( !mVertexMarkerOnlyForSelection || sel ) 01076 { 01077 mCurrentVertexMarkerType = vertexMarker; 01078 mCurrentVertexMarkerSize = vertexMarkerSize; 01079 } 01080 } 01081 01082 //QgsDebugMsg(QString("markerScale before renderFeature(): %1").arg(markerScaleFactor)); 01083 // markerScalerFactore reflects the wanted scaling of the marker 01084 01085 double opacity = 1.0; 01086 if ( !mRenderer->usesTransparency() ) 01087 { 01088 opacity = ( mTransparencyLevel * 1.0 ) / 255.0; 01089 } 01090 mRenderer->renderFeature( rendererContext, fet, &marker, sel, opacity ); 01091 01092 // markerScalerFactore now reflects the actual scaling of the marker that the render performed. 01093 //QgsDebugMsg(QString("markerScale after renderFeature(): %1").arg(markerScaleFactor)); 01094 01095 //double scale = rendererContext.scaleFactor() / markerScaleFactor; 01096 drawFeature( rendererContext, fet, &marker ); 01097 01098 if ( mRenderer->willRenderFeature( &fet ) && rendererContext.labelingEngine() ) 01099 { 01100 if ( labeling ) 01101 { 01102 rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); 01103 } 01104 if ( mDiagramRenderer ) 01105 { 01106 rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext ); 01107 } 01108 } 01109 ++featureCount; 01110 } 01111 } 01112 catch ( QgsCsException &cse ) 01113 { 01114 Q_UNUSED( cse ); 01115 QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Rendering stopped. %2" ) 01116 .arg( fet.typeName() ).arg( cse.what() ) ); 01117 return false; 01118 } 01119 01120 QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) ); 01121 } 01122 else 01123 { 01124 QgsDebugMsg( "QgsRenderer is null" ); 01125 } 01126 01127 if ( mEditable ) 01128 { 01129 QgsDebugMsg( QString( "Cached %1 geometries." ).arg( mCachedGeometries.count() ) ); 01130 } 01131 01132 return true; // Assume success always 01133 } 01134 01135 void QgsVectorLayer::deleteCachedGeometries() 01136 { 01137 // Destroy any cached geometries 01138 mCachedGeometries.clear(); 01139 mCachedGeometriesRect = QgsRectangle(); 01140 } 01141 01142 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m ) 01143 { 01144 if ( type == QgsVectorLayer::SemiTransparentCircle ) 01145 { 01146 p.setPen( QColor( 50, 100, 120, 200 ) ); 01147 p.setBrush( QColor( 200, 200, 210, 120 ) ); 01148 p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 ); 01149 } 01150 else if ( type == QgsVectorLayer::Cross ) 01151 { 01152 p.setPen( QColor( 255, 0, 0 ) ); 01153 p.drawLine( x - m, y + m, x + m, y - m ); 01154 p.drawLine( x - m, y - m, x + m, y + m ); 01155 } 01156 } 01157 01158 void QgsVectorLayer::select( QgsFeatureId fid, bool emitSignal ) 01159 { 01160 mSelectedFeatureIds.insert( fid ); 01161 01162 if ( emitSignal ) 01163 { 01164 // invalidate cache 01165 setCacheImage( 0 ); 01166 01167 emit selectionChanged(); 01168 } 01169 } 01170 01171 void QgsVectorLayer::deselect( QgsFeatureId fid, bool emitSignal ) 01172 { 01173 mSelectedFeatureIds.remove( fid ); 01174 01175 if ( emitSignal ) 01176 { 01177 // invalidate cache 01178 setCacheImage( 0 ); 01179 01180 emit selectionChanged(); 01181 } 01182 } 01183 01184 void QgsVectorLayer::select( QgsRectangle & rect, bool lock ) 01185 { 01186 // normalize the rectangle 01187 rect.normalize(); 01188 01189 if ( !lock ) 01190 { 01191 removeSelection( false ); // don't emit signal 01192 } 01193 01194 //select all the elements 01195 select( QgsAttributeList(), rect, false, true ); 01196 01197 QgsFeature f; 01198 while ( nextFeature( f ) ) 01199 { 01200 select( f.id(), false ); // don't emit signal (not to redraw it everytime) 01201 } 01202 01203 // invalidate cache 01204 setCacheImage( 0 ); 01205 01206 emit selectionChanged(); // now emit signal to redraw layer 01207 } 01208 01209 void QgsVectorLayer::invertSelection() 01210 { 01211 // copy the ids of selected features to tmp 01212 QgsFeatureIds tmp = mSelectedFeatureIds; 01213 01214 removeSelection( false ); // don't emit signal 01215 01216 select( QgsAttributeList(), QgsRectangle(), false ); 01217 01218 QgsFeature fet; 01219 while ( nextFeature( fet ) ) 01220 { 01221 select( fet.id(), false ); // don't emit signal 01222 } 01223 01224 for ( QgsFeatureIds::iterator iter = tmp.begin(); iter != tmp.end(); ++iter ) 01225 { 01226 mSelectedFeatureIds.remove( *iter ); 01227 } 01228 01229 // invalidate cache 01230 setCacheImage( 0 ); 01231 01232 emit selectionChanged(); 01233 } 01234 01235 void QgsVectorLayer::invertSelectionInRectangle( QgsRectangle & rect ) 01236 { 01237 // normalize the rectangle 01238 rect.normalize(); 01239 01240 select( QgsAttributeList(), rect, false, true ); 01241 01242 QgsFeature fet; 01243 while ( nextFeature( fet ) ) 01244 { 01245 if ( mSelectedFeatureIds.contains( fet.id() ) ) 01246 { 01247 deselect( fet.id(), false ); // don't emit signal 01248 } 01249 else 01250 { 01251 select( fet.id(), false ); // don't emit signal 01252 } 01253 } 01254 01255 // invalidate cache 01256 setCacheImage( 0 ); 01257 01258 emit selectionChanged(); 01259 } 01260 01261 void QgsVectorLayer::removeSelection( bool emitSignal ) 01262 { 01263 if ( mSelectedFeatureIds.size() == 0 ) 01264 return; 01265 01266 mSelectedFeatureIds.clear(); 01267 01268 if ( emitSignal ) 01269 { 01270 // invalidate cache 01271 setCacheImage( 0 ); 01272 01273 emit selectionChanged(); 01274 } 01275 } 01276 01277 void QgsVectorLayer::triggerRepaint() 01278 { 01279 emit repaintRequested(); 01280 } 01281 01282 QgsVectorDataProvider* QgsVectorLayer::dataProvider() 01283 { 01284 return mDataProvider; 01285 } 01286 01287 const QgsVectorDataProvider* QgsVectorLayer::dataProvider() const 01288 { 01289 return mDataProvider; 01290 } 01291 01292 void QgsVectorLayer::setProviderEncoding( const QString& encoding ) 01293 { 01294 if ( mDataProvider ) 01295 { 01296 mDataProvider->setEncoding( encoding ); 01297 } 01298 } 01299 01300 01301 const QgsRenderer* QgsVectorLayer::renderer() const 01302 { 01303 return mRenderer; 01304 } 01305 01306 void QgsVectorLayer::setRenderer( QgsRenderer *r ) 01307 { 01308 if ( !hasGeometryType() ) 01309 return; 01310 01311 if ( r != mRenderer ) 01312 { 01313 if ( r ) 01314 setUsingRendererV2( false ); 01315 delete mRenderer; 01316 mRenderer = r; 01317 } 01318 } 01319 01320 void QgsVectorLayer::setDiagramRenderer( QgsDiagramRendererV2* r ) 01321 { 01322 delete mDiagramRenderer; 01323 mDiagramRenderer = r; 01324 } 01325 01326 QGis::GeometryType QgsVectorLayer::geometryType() const 01327 { 01328 if ( mDataProvider ) 01329 { 01330 int type = mDataProvider->geometryType(); 01331 switch ( type ) 01332 { 01333 case QGis::WKBPoint: 01334 case QGis::WKBPoint25D: 01335 return QGis::Point; 01336 01337 case QGis::WKBLineString: 01338 case QGis::WKBLineString25D: 01339 return QGis::Line; 01340 01341 case QGis::WKBPolygon: 01342 case QGis::WKBPolygon25D: 01343 return QGis::Polygon; 01344 01345 case QGis::WKBMultiPoint: 01346 case QGis::WKBMultiPoint25D: 01347 return QGis::Point; 01348 01349 case QGis::WKBMultiLineString: 01350 case QGis::WKBMultiLineString25D: 01351 return QGis::Line; 01352 01353 case QGis::WKBMultiPolygon: 01354 case QGis::WKBMultiPolygon25D: 01355 return QGis::Polygon; 01356 01357 case QGis::WKBNoGeometry: 01358 return QGis::NoGeometry; 01359 } 01360 QgsDebugMsg( QString( "Data Provider Geometry type is not recognised, is %1" ).arg( type ) ); 01361 } 01362 else 01363 { 01364 QgsDebugMsg( "pointer to mDataProvider is null" ); 01365 } 01366 01367 // We shouldn't get here, and if we have, other things are likely to 01368 // go wrong. Code that uses the type() return value should be 01369 // rewritten to cope with a value of QGis::Unknown. To make this 01370 // need known, the following message is printed every time we get 01371 // here. 01372 QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." ); 01373 01374 return QGis::UnknownGeometry; 01375 } 01376 01377 bool QgsVectorLayer::hasGeometryType() const 01378 { 01379 QGis::GeometryType t = geometryType(); 01380 return ( t != QGis::NoGeometry && t != QGis::UnknownGeometry ); 01381 } 01382 01383 QGis::WkbType QgsVectorLayer::wkbType() const 01384 { 01385 return ( QGis::WkbType )( mWkbType ); 01386 } 01387 01388 QgsRectangle QgsVectorLayer::boundingBoxOfSelected() 01389 { 01390 if ( mSelectedFeatureIds.size() == 0 ) //no selected features 01391 { 01392 return QgsRectangle( 0, 0, 0, 0 ); 01393 } 01394 01395 QgsRectangle r, retval; 01396 retval.setMinimal(); 01397 01398 QgsFeature fet; 01399 if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId ) 01400 { 01401 foreach( QgsFeatureId fid, mSelectedFeatureIds ) 01402 { 01403 if ( featureAtId( fid, fet, true, false ) && fet.geometry() ) 01404 { 01405 r = fet.geometry()->boundingBox(); 01406 retval.combineExtentWith( &r ); 01407 } 01408 } 01409 } 01410 else 01411 { 01412 select( QgsAttributeList(), QgsRectangle(), true ); 01413 01414 while ( nextFeature( fet ) ) 01415 { 01416 if ( mSelectedFeatureIds.contains( fet.id() ) ) 01417 { 01418 if ( fet.geometry() ) 01419 { 01420 r = fet.geometry()->boundingBox(); 01421 retval.combineExtentWith( &r ); 01422 } 01423 } 01424 } 01425 } 01426 01427 if ( retval.width() == 0.0 || retval.height() == 0.0 ) 01428 { 01429 // If all of the features are at the one point, buffer the 01430 // rectangle a bit. If they are all at zero, do something a bit 01431 // more crude. 01432 01433 if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 && 01434 retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 ) 01435 { 01436 retval.set( -1.0, -1.0, 1.0, 1.0 ); 01437 } 01438 } 01439 01440 return retval; 01441 } 01442 01443 01444 01445 long QgsVectorLayer::featureCount() const 01446 { 01447 if ( !mDataProvider ) 01448 { 01449 QgsDebugMsg( "invoked with null mDataProvider" ); 01450 return 0; 01451 } 01452 01453 return mDataProvider->featureCount(); 01454 } 01455 01456 long QgsVectorLayer::updateFeatureCount() const 01457 { 01458 return -1; 01459 } 01460 01461 void QgsVectorLayer::updateExtents() 01462 { 01463 if ( !hasGeometryType() ) 01464 return; 01465 01466 mLayerExtent.setMinimal(); 01467 01468 if ( !mDataProvider ) 01469 { 01470 QgsDebugMsg( "invoked with null mDataProvider" ); 01471 } 01472 01473 if ( mDeletedFeatureIds.isEmpty() && mChangedGeometries.isEmpty() ) 01474 { 01475 mDataProvider->updateExtents(); 01476 01477 // get the extent of the layer from the provider 01478 // but only when there are some features already 01479 if ( mDataProvider->featureCount() != 0 ) 01480 { 01481 QgsRectangle r = mDataProvider->extent(); 01482 mLayerExtent.combineExtentWith( &r ); 01483 } 01484 01485 for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ ) 01486 { 01487 QgsRectangle r = it->geometry()->boundingBox(); 01488 mLayerExtent.combineExtentWith( &r ); 01489 } 01490 } 01491 else 01492 { 01493 select( QgsAttributeList(), QgsRectangle(), true ); 01494 01495 QgsFeature fet; 01496 while ( nextFeature( fet ) ) 01497 { 01498 if ( fet.geometry() ) 01499 { 01500 QgsRectangle bb = fet.geometry()->boundingBox(); 01501 mLayerExtent.combineExtentWith( &bb ); 01502 } 01503 } 01504 } 01505 01506 if ( mLayerExtent.xMinimum() > mLayerExtent.xMaximum() && mLayerExtent.yMinimum() > mLayerExtent.yMaximum() ) 01507 { 01508 // special case when there are no features in provider nor any added 01509 mLayerExtent = QgsRectangle(); // use rectangle with zero coordinates 01510 } 01511 01512 // Send this (hopefully) up the chain to the map canvas 01513 emit recalculateExtents(); 01514 } 01515 01516 QString QgsVectorLayer::subsetString() 01517 { 01518 if ( ! mDataProvider ) 01519 { 01520 QgsDebugMsg( "invoked with null mDataProvider" ); 01521 return 0; 01522 } 01523 return mDataProvider->subsetString(); 01524 } 01525 01526 bool QgsVectorLayer::setSubsetString( QString subset ) 01527 { 01528 if ( ! mDataProvider ) 01529 { 01530 QgsDebugMsg( "invoked with null mDataProvider" ); 01531 return false; 01532 } 01533 01534 bool res = mDataProvider->setSubsetString( subset ); 01535 01536 // get the updated data source string from the provider 01537 mDataSource = mDataProvider->dataSourceUri(); 01538 updateExtents(); 01539 01540 if ( res ) 01541 setCacheImage( 0 ); 01542 01543 return res; 01544 } 01545 01546 void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, bool all ) 01547 { 01548 if ( mDataProvider && ( all || ( mFetchAttributes.size() > 0 && mJoinBuffer->containsFetchJoins() ) ) ) 01549 { 01550 int index = 0; 01551 QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), index ); 01552 mJoinBuffer->updateFeatureAttributes( f, index, all ); 01553 } 01554 01555 01556 // do not update when we aren't in editing mode 01557 if ( !mEditable ) 01558 return; 01559 01560 if ( mChangedAttributeValues.contains( f.id() ) ) 01561 { 01562 const QgsAttributeMap &map = mChangedAttributeValues[f.id()]; 01563 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ ) 01564 f.changeAttribute( it.key(), it.value() ); 01565 } 01566 01567 // remove all attributes that will disappear 01568 QgsAttributeMap map = f.attributeMap(); 01569 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ ) 01570 if ( !mUpdatedFields.contains( it.key() ) ) 01571 f.deleteAttribute( it.key() ); 01572 01573 // null/add all attributes that were added, but don't exist in the feature yet 01574 for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ ) 01575 if ( !map.contains( it.key() ) && ( all || mFetchAttributes.contains( it.key() ) ) ) 01576 f.changeAttribute( it.key(), QVariant( QString::null ) ); 01577 } 01578 01579 void QgsVectorLayer::addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName, 01580 const QVariant& joinValue, const QgsAttributeList& attributes, int attributeIndexOffset ) 01581 { 01582 const QHash< QString, QgsAttributeMap>& memoryCache = joinInfo.cachedAttributes; 01583 if ( !memoryCache.isEmpty() ) //use join memory cache 01584 { 01585 QgsAttributeMap featureAttributes = memoryCache.value( joinValue.toString() ); 01586 bool found = !featureAttributes.isEmpty(); 01587 QgsAttributeList::const_iterator attIt = attributes.constBegin(); 01588 for ( ; attIt != attributes.constEnd(); ++attIt ) 01589 { 01590 if ( found ) 01591 { 01592 f.addAttribute( *attIt + attributeIndexOffset, featureAttributes.value( *attIt ) ); 01593 } 01594 else 01595 { 01596 f.addAttribute( *attIt + attributeIndexOffset, QVariant() ); 01597 } 01598 } 01599 } 01600 else //work with subset string 01601 { 01602 QgsVectorLayer* joinLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) ); 01603 if ( !joinLayer ) 01604 { 01605 return; 01606 } 01607 01608 //no memory cache, query the joined values by setting substring 01609 QString subsetString = joinLayer->dataProvider()->subsetString(); //provider might already have a subset string 01610 QString bkSubsetString = subsetString; 01611 if ( !subsetString.isEmpty() ) 01612 { 01613 subsetString.append( " AND " ); 01614 } 01615 01616 subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" ); 01617 joinLayer->dataProvider()->setSubsetString( subsetString, false ); 01618 01619 //select (no geometry) 01620 joinLayer->select( attributes, QgsRectangle(), false, false ); 01621 01622 //get first feature 01623 QgsFeature fet; 01624 if ( joinLayer->nextFeature( fet ) ) 01625 { 01626 QgsAttributeMap attMap = fet.attributeMap(); 01627 QgsAttributeMap::const_iterator attIt = attMap.constBegin(); 01628 for ( ; attIt != attMap.constEnd(); ++attIt ) 01629 { 01630 f.addAttribute( attIt.key() + attributeIndexOffset, attIt.value() ); 01631 } 01632 } 01633 else //no suitable join feature found, insert invalid variants 01634 { 01635 QgsAttributeList::const_iterator attIt = attributes.constBegin(); 01636 for ( ; attIt != attributes.constEnd(); ++attIt ) 01637 { 01638 f.addAttribute( *attIt + attributeIndexOffset, QVariant() ); 01639 } 01640 } 01641 01642 joinLayer->dataProvider()->setSubsetString( bkSubsetString, false ); 01643 } 01644 } 01645 01646 void QgsVectorLayer::updateFeatureGeometry( QgsFeature &f ) 01647 { 01648 if ( mChangedGeometries.contains( f.id() ) ) 01649 f.setGeometry( mChangedGeometries[f.id()] ); 01650 } 01651 01652 01653 void QgsVectorLayer::select( QgsAttributeList attributes, QgsRectangle rect, bool fetchGeometries, bool useIntersect ) 01654 { 01655 if ( !mDataProvider ) 01656 return; 01657 01658 mFetching = true; 01659 mFetchRect = rect; 01660 mFetchAttributes = attributes; 01661 mFetchGeometry = fetchGeometries; 01662 mFetchConsidered = mDeletedFeatureIds; 01663 QgsAttributeList targetJoinFieldList; 01664 01665 if ( mEditable ) 01666 { 01667 mFetchAddedFeaturesIt = mAddedFeatures.begin(); 01668 mFetchChangedGeomIt = mChangedGeometries.begin(); 01669 } 01670 01671 //look in the normal features of the provider 01672 if ( mFetchAttributes.size() > 0 ) 01673 { 01674 if ( mEditable || mJoinBuffer->containsJoins() ) 01675 { 01676 QgsAttributeList joinFields; 01677 01678 int maxProviderIndex = 0; 01679 if ( mDataProvider ) 01680 { 01681 QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex ); 01682 } 01683 01684 mJoinBuffer->select( mFetchAttributes, joinFields, maxProviderIndex ); 01685 QgsAttributeList::const_iterator joinFieldIt = joinFields.constBegin(); 01686 for ( ; joinFieldIt != joinFields.constEnd(); ++joinFieldIt ) 01687 { 01688 if ( !mFetchAttributes.contains( *joinFieldIt ) ) 01689 { 01690 mFetchAttributes.append( *joinFieldIt ); 01691 } 01692 } 01693 01694 //detect which fields are from the provider 01695 mFetchProvAttributes.clear(); 01696 for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ ) 01697 { 01698 if ( mDataProvider->fields().contains( *it ) ) 01699 { 01700 mFetchProvAttributes << *it; 01701 } 01702 } 01703 01704 mDataProvider->select( mFetchProvAttributes, rect, fetchGeometries, useIntersect ); 01705 } 01706 else 01707 { 01708 mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect ); 01709 } 01710 } 01711 else //we don't need any attributes at all 01712 { 01713 mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect ); 01714 } 01715 } 01716 01717 bool QgsVectorLayer::nextFeature( QgsFeature &f ) 01718 { 01719 if ( !mFetching ) 01720 return false; 01721 01722 if ( mEditable ) 01723 { 01724 if ( !mFetchRect.isEmpty() ) 01725 { 01726 // check if changed geometries are in rectangle 01727 for ( ; mFetchChangedGeomIt != mChangedGeometries.end(); mFetchChangedGeomIt++ ) 01728 { 01729 QgsFeatureId fid = mFetchChangedGeomIt.key(); 01730 01731 if ( mFetchConsidered.contains( fid ) ) 01732 // skip deleted features 01733 continue; 01734 01735 mFetchConsidered << fid; 01736 01737 if ( !mFetchChangedGeomIt->intersects( mFetchRect ) ) 01738 // skip changed geometries not in rectangle and don't check again 01739 continue; 01740 01741 f.setFeatureId( fid ); 01742 f.setValid( true ); 01743 01744 if ( mFetchGeometry ) 01745 f.setGeometry( mFetchChangedGeomIt.value() ); 01746 01747 if ( mFetchAttributes.size() > 0 ) 01748 { 01749 if ( fid < 0 ) 01750 { 01751 // fid<0 => in mAddedFeatures 01752 bool found = false; 01753 01754 for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ ) 01755 { 01756 if ( fid == it->id() ) 01757 { 01758 found = true; 01759 f.setAttributeMap( it->attributeMap() ); 01760 updateFeatureAttributes( f ); 01761 break; 01762 } 01763 } 01764 01765 if ( !found ) 01766 { 01767 QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) ); 01768 } 01769 } 01770 else 01771 { 01772 // retrieve attributes from provider 01773 QgsFeature tmp; 01774 mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes ); 01775 updateFeatureAttributes( tmp ); 01776 f.setAttributeMap( tmp.attributeMap() ); 01777 } 01778 } 01779 01780 // return complete feature 01781 mFetchChangedGeomIt++; 01782 return true; 01783 } 01784 01785 // no more changed geometries 01786 } 01787 01788 for ( ; mFetchAddedFeaturesIt != mAddedFeatures.end(); mFetchAddedFeaturesIt++ ) 01789 { 01790 QgsFeatureId fid = mFetchAddedFeaturesIt->id(); 01791 01792 if ( mFetchConsidered.contains( fid ) ) 01793 // must have changed geometry outside rectangle 01794 continue; 01795 01796 if ( !mFetchRect.isEmpty() && 01797 mFetchAddedFeaturesIt->geometry() && 01798 !mFetchAddedFeaturesIt->geometry()->intersects( mFetchRect ) ) 01799 // skip added features not in rectangle 01800 continue; 01801 01802 f.setFeatureId( fid ); 01803 f.setValid( true ); 01804 01805 if ( mFetchGeometry ) 01806 f.setGeometry( *mFetchAddedFeaturesIt->geometry() ); 01807 01808 if ( mFetchAttributes.size() > 0 ) 01809 { 01810 f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() ); 01811 updateFeatureAttributes( f ); 01812 } 01813 01814 mFetchAddedFeaturesIt++; 01815 return true; 01816 } 01817 01818 // no more added features 01819 } 01820 01821 while ( dataProvider()->nextFeature( f ) ) 01822 { 01823 if ( mFetchConsidered.contains( f.id() ) ) 01824 { 01825 continue; 01826 } 01827 if ( mFetchAttributes.size() > 0 ) 01828 { 01829 updateFeatureAttributes( f ); //check joined attributes / changed attributes 01830 } 01831 if ( mEditable && mFetchGeometry ) 01832 { 01833 updateFeatureGeometry( f ); 01834 } 01835 01836 return true; 01837 } 01838 01839 mFetching = false; 01840 return false; 01841 } 01842 01843 bool QgsVectorLayer::featureAtId( QgsFeatureId featureId, QgsFeature& f, bool fetchGeometries, bool fetchAttributes ) 01844 { 01845 if ( !mDataProvider ) 01846 return false; 01847 01848 if ( mDeletedFeatureIds.contains( featureId ) ) 01849 return false; 01850 01851 if ( fetchGeometries && mChangedGeometries.contains( featureId ) ) 01852 { 01853 f.setFeatureId( featureId ); 01854 f.setValid( true ); 01855 f.setGeometry( mChangedGeometries[featureId] ); 01856 01857 if ( fetchAttributes ) 01858 { 01859 if ( featureId < 0 ) 01860 { 01861 // featureId<0 => in mAddedFeatures 01862 bool found = false; 01863 01864 for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ ) 01865 { 01866 if ( featureId != it->id() ) 01867 { 01868 found = true; 01869 f.setAttributeMap( it->attributeMap() ); 01870 break; 01871 } 01872 } 01873 01874 if ( !found ) 01875 { 01876 QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) ); 01877 } 01878 } 01879 else 01880 { 01881 // retrieve attributes from provider 01882 QgsFeature tmp; 01883 mDataProvider->featureAtId( featureId, tmp, false, mDataProvider->attributeIndexes() ); 01884 f.setAttributeMap( tmp.attributeMap() ); 01885 } 01886 updateFeatureAttributes( f, true ); 01887 } 01888 return true; 01889 } 01890 01891 //added features 01892 for ( QgsFeatureList::iterator iter = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter ) 01893 { 01894 if ( iter->id() == featureId ) 01895 { 01896 f.setFeatureId( iter->id() ); 01897 f.setValid( true ); 01898 if ( fetchGeometries ) 01899 f.setGeometry( *iter->geometry() ); 01900 01901 if ( fetchAttributes ) 01902 f.setAttributeMap( iter->attributeMap() ); 01903 01904 return true; 01905 } 01906 } 01907 01908 // regular features 01909 if ( fetchAttributes ) 01910 { 01911 if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() ) ) 01912 { 01913 updateFeatureAttributes( f, true ); 01914 return true; 01915 } 01916 } 01917 else 01918 { 01919 if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, QgsAttributeList() ) ) 01920 { 01921 return true; 01922 } 01923 } 01924 return false; 01925 } 01926 01927 bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent ) 01928 { 01929 static int addedIdLowWaterMark = -1; 01930 01931 if ( !mDataProvider ) 01932 { 01933 return false; 01934 } 01935 01936 if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) 01937 { 01938 return false; 01939 } 01940 01941 if ( !isEditable() ) 01942 { 01943 return false; 01944 } 01945 01946 //assign a temporary id to the feature (use negative numbers) 01947 addedIdLowWaterMark--; 01948 01949 QgsDebugMsg( "Assigned feature id " + QString::number( addedIdLowWaterMark ) ); 01950 01951 // Force a feature ID (to keep other functions in QGIS happy, 01952 // providers will use their own new feature ID when we commit the new feature) 01953 // and add to the known added features. 01954 f.setFeatureId( addedIdLowWaterMark ); 01955 editFeatureAdd( f ); 01956 01957 if ( f.geometry() ) 01958 mCachedGeometries[f.id()] = *f.geometry(); 01959 01960 setModified( true ); 01961 01962 if ( alsoUpdateExtent ) 01963 { 01964 updateExtents(); 01965 } 01966 01967 emit featureAdded( f.id() ); 01968 01969 return true; 01970 } 01971 01972 bool QgsVectorLayer::updateFeature( QgsFeature &f ) 01973 { 01974 QgsFeature current; 01975 if ( !featureAtId( f.id(), current, f.geometry(), !f.attributeMap().isEmpty() ) ) 01976 { 01977 QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) ); 01978 return false; 01979 } 01980 01981 if ( f.geometry() && current.geometry() && f.geometry() != current.geometry() && !f.geometry()->isGeosEqual( *current.geometry() ) ) 01982 { 01983 if ( !changeGeometry( f.id(), f.geometry() ) ) 01984 { 01985 QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) ); 01986 return false; 01987 } 01988 } 01989 01990 const QgsAttributeMap &fa = f.attributeMap(); 01991 const QgsAttributeMap &ca = current.attributeMap(); 01992 01993 foreach( int attr, fa.keys() ) 01994 { 01995 if ( fa.contains( attr ) && ca.contains( attr ) && fa[attr] != ca[attr] ) 01996 { 01997 if ( !changeAttributeValue( f.id(), attr, fa[attr] ) ) 01998 { 01999 QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) ); 02000 return false; 02001 } 02002 } 02003 } 02004 02005 return true; 02006 } 02007 02008 02009 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex ) 02010 { 02011 if ( !hasGeometryType() ) 02012 return false; 02013 02014 if ( !mEditable ) 02015 { 02016 return false; 02017 } 02018 02019 if ( mDataProvider ) 02020 { 02021 QgsGeometry geometry; 02022 if ( !mChangedGeometries.contains( atFeatureId ) ) 02023 { 02024 // first time this geometry has changed since last commit 02025 if ( !mCachedGeometries.contains( atFeatureId ) ) 02026 { 02027 return false; 02028 } 02029 geometry = mCachedGeometries[atFeatureId]; 02030 //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId]; 02031 } 02032 else 02033 { 02034 geometry = mChangedGeometries[atFeatureId]; 02035 } 02036 geometry.insertVertex( x, y, beforeVertex ); 02037 mCachedGeometries[atFeatureId] = geometry; 02038 editGeometryChange( atFeatureId, geometry ); 02039 02040 setModified( true, true ); // only geometry was changed 02041 02042 return true; 02043 } 02044 return false; 02045 } 02046 02047 02048 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex ) 02049 { 02050 if ( !hasGeometryType() ) 02051 return false; 02052 02053 if ( !mEditable ) 02054 { 02055 return false; 02056 } 02057 02058 if ( mDataProvider ) 02059 { 02060 QgsGeometry geometry; 02061 if ( !mChangedGeometries.contains( atFeatureId ) ) 02062 { 02063 // first time this geometry has changed since last commit 02064 if ( !mCachedGeometries.contains( atFeatureId ) ) 02065 { 02066 return false; 02067 } 02068 geometry = mCachedGeometries[atFeatureId]; 02069 //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId]; 02070 } 02071 else 02072 { 02073 geometry = mChangedGeometries[atFeatureId]; 02074 } 02075 02076 geometry.moveVertex( x, y, atVertex ); 02077 mCachedGeometries[atFeatureId] = geometry; 02078 editGeometryChange( atFeatureId, geometry ); 02079 02080 setModified( true, true ); // only geometry was changed 02081 02082 return true; 02083 } 02084 return false; 02085 } 02086 02087 02088 bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex ) 02089 { 02090 if ( !hasGeometryType() ) 02091 return false; 02092 02093 if ( !mEditable ) 02094 { 02095 return false; 02096 } 02097 02098 if ( mDataProvider ) 02099 { 02100 QgsGeometry geometry; 02101 if ( !mChangedGeometries.contains( atFeatureId ) ) 02102 { 02103 // first time this geometry has changed since last commit 02104 if ( !mCachedGeometries.contains( atFeatureId ) ) 02105 { 02106 return false; 02107 } 02108 geometry = mCachedGeometries[atFeatureId]; 02109 } 02110 else 02111 { 02112 geometry = mChangedGeometries[atFeatureId]; 02113 } 02114 02115 if ( !geometry.deleteVertex( atVertex ) ) 02116 { 02117 return false; 02118 } 02119 mCachedGeometries[atFeatureId] = geometry; 02120 editGeometryChange( atFeatureId, geometry ); 02121 02122 setModified( true, true ); // only geometry was changed 02123 02124 return true; 02125 } 02126 return false; 02127 } 02128 02129 02130 bool QgsVectorLayer::deleteSelectedFeatures() 02131 { 02132 if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) ) 02133 { 02134 return false; 02135 } 02136 02137 if ( !isEditable() ) 02138 { 02139 return false; 02140 } 02141 02142 if ( mSelectedFeatureIds.size() == 0 ) 02143 return true; 02144 02145 while ( mSelectedFeatureIds.size() > 0 ) 02146 { 02147 QgsFeatureId fid = *mSelectedFeatureIds.begin(); 02148 deleteFeature( fid ); // removes from selection 02149 } 02150 02151 // invalidate cache 02152 setCacheImage( 0 ); 02153 02154 emit selectionChanged(); 02155 02156 triggerRepaint(); 02157 updateExtents(); 02158 02159 return true; 02160 } 02161 02162 int QgsVectorLayer::addRing( const QList<QgsPoint>& ring ) 02163 { 02164 if ( !hasGeometryType() ) 02165 return 5; 02166 02167 int addRingReturnCode = 5; //default: return code for 'ring not inserted' 02168 double xMin, yMin, xMax, yMax; 02169 QgsRectangle bBox; 02170 02171 if ( boundingBoxFromPointList( ring, xMin, yMin, xMax, yMax ) == 0 ) 02172 { 02173 bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); 02174 bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); 02175 } 02176 else 02177 { 02178 return 3; //ring not valid 02179 } 02180 02181 select( QgsAttributeList(), bBox, true, true ); 02182 02183 QgsFeature f; 02184 while ( nextFeature( f ) ) 02185 { 02186 addRingReturnCode = f.geometry()->addRing( ring ); 02187 if ( addRingReturnCode == 0 ) 02188 { 02189 editGeometryChange( f.id(), *f.geometry() ); 02190 02191 setModified( true, true ); 02192 break; 02193 } 02194 } 02195 02196 return addRingReturnCode; 02197 } 02198 02199 int QgsVectorLayer::addPart( const QList<QgsPoint> &points ) 02200 { 02201 if ( !hasGeometryType() ) 02202 return 6; 02203 02204 //number of selected features must be 1 02205 02206 if ( mSelectedFeatureIds.size() < 1 ) 02207 { 02208 QgsDebugMsg( "Number of selected features <1" ); 02209 return 4; 02210 } 02211 else if ( mSelectedFeatureIds.size() > 1 ) 02212 { 02213 QgsDebugMsg( "Number of selected features >1" ); 02214 return 5; 02215 } 02216 02217 QgsFeatureId selectedFeatureId = *mSelectedFeatureIds.constBegin(); 02218 02219 //look if geometry of selected feature already contains geometry changes 02220 QgsGeometryMap::iterator changedIt = mChangedGeometries.find( selectedFeatureId ); 02221 if ( changedIt != mChangedGeometries.end() ) 02222 { 02223 QgsGeometry geom = *changedIt; 02224 int returnValue = geom.addPart( points ); 02225 editGeometryChange( selectedFeatureId, geom ); 02226 mCachedGeometries[selectedFeatureId] = geom; 02227 return returnValue; 02228 } 02229 02230 //look if id of selected feature belongs to an added feature 02231 #if 0 02232 for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt ) 02233 { 02234 if ( addedIt->id() == selectedFeatureId ) 02235 { 02236 return addedIt->geometry()->addPart( ring ); 02237 mCachedGeometries[selectedFeatureId] = *addedIt->geometry(); 02238 } 02239 } 02240 #endif 02241 02242 //is the feature contained in the view extent (mCachedGeometries) ? 02243 QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( selectedFeatureId ); 02244 if ( cachedIt != mCachedGeometries.end() ) 02245 { 02246 int errorCode = cachedIt->addPart( points ); 02247 if ( errorCode == 0 ) 02248 { 02249 editGeometryChange( selectedFeatureId, *cachedIt ); 02250 mCachedGeometries[selectedFeatureId] = *cachedIt; 02251 setModified( true, true ); 02252 } 02253 return errorCode; 02254 } 02255 else //maybe the selected feature has been moved outside the visible area and therefore is not contained in mCachedGeometries 02256 { 02257 QgsFeature f; 02258 QgsGeometry* fGeom = 0; 02259 if ( featureAtId( selectedFeatureId, f, true, false ) ) 02260 { 02261 fGeom = f.geometryAndOwnership(); 02262 if ( fGeom ) 02263 { 02264 int errorCode = fGeom->addPart( points ); 02265 editGeometryChange( selectedFeatureId, *fGeom ); 02266 setModified( true, true ); 02267 delete fGeom; 02268 return errorCode; 02269 } 02270 } 02271 } 02272 02273 return 6; //geometry not found 02274 } 02275 02276 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy ) 02277 { 02278 if ( !hasGeometryType() ) 02279 return 1; 02280 02281 //look if geometry of selected feature already contains geometry changes 02282 QgsGeometryMap::iterator changedIt = mChangedGeometries.find( featureId ); 02283 if ( changedIt != mChangedGeometries.end() ) 02284 { 02285 QgsGeometry geom = *changedIt; 02286 int errorCode = geom.translate( dx, dy ); 02287 editGeometryChange( featureId, geom ); 02288 return errorCode; 02289 } 02290 02291 //look if id of selected feature belongs to an added feature 02292 #if 0 02293 for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt ) 02294 { 02295 if ( addedIt->id() == featureId ) 02296 { 02297 return addedIt->geometry()->translate( dx, dy ); 02298 } 02299 } 02300 #endif 02301 02302 //else look in mCachedGeometries to make access faster 02303 QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( featureId ); 02304 if ( cachedIt != mCachedGeometries.end() ) 02305 { 02306 int errorCode = cachedIt->translate( dx, dy ); 02307 if ( errorCode == 0 ) 02308 { 02309 editGeometryChange( featureId, *cachedIt ); 02310 setModified( true, true ); 02311 } 02312 return errorCode; 02313 } 02314 02315 //else get the geometry from provider (may be slow) 02316 QgsFeature f; 02317 if ( mDataProvider && mDataProvider->featureAtId( featureId, f, true ) ) 02318 { 02319 if ( f.geometry() ) 02320 { 02321 QgsGeometry translateGeom( *( f.geometry() ) ); 02322 int errorCode = translateGeom.translate( dx, dy ); 02323 if ( errorCode == 0 ) 02324 { 02325 editGeometryChange( featureId, translateGeom ); 02326 setModified( true, true ); 02327 } 02328 return errorCode; 02329 } 02330 } 02331 return 1; //geometry not found 02332 } 02333 02334 int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) 02335 { 02336 if ( !hasGeometryType() ) 02337 return 4; 02338 02339 QgsFeatureList newFeatures; //store all the newly created features 02340 double xMin, yMin, xMax, yMax; 02341 QgsRectangle bBox; //bounding box of the split line 02342 int returnCode = 0; 02343 int splitFunctionReturn; //return code of QgsGeometry::splitGeometry 02344 int numberOfSplittedFeatures = 0; 02345 02346 QgsFeatureList featureList; 02347 const QgsFeatureIds selectedIds = selectedFeaturesIds(); 02348 02349 if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection 02350 { 02351 featureList = selectedFeatures(); 02352 } 02353 else //else consider all the feature that intersect the bounding box of the split line 02354 { 02355 if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) 02356 { 02357 bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); 02358 bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); 02359 } 02360 else 02361 { 02362 return 1; 02363 } 02364 02365 if ( bBox.isEmpty() ) 02366 { 02367 //if the bbox is a line, try to make a square out of it 02368 if ( bBox.width() == 0.0 && bBox.height() > 0 ) 02369 { 02370 bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); 02371 bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); 02372 } 02373 else if ( bBox.height() == 0.0 && bBox.width() > 0 ) 02374 { 02375 bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); 02376 bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); 02377 } 02378 else 02379 { 02380 return 2; 02381 } 02382 } 02383 02384 select( pendingAllAttributesList(), bBox, true, true ); 02385 02386 QgsFeature f; 02387 while ( nextFeature( f ) ) 02388 featureList << QgsFeature( f ); 02389 } 02390 02391 QgsFeatureList::iterator select_it = featureList.begin(); 02392 for ( ; select_it != featureList.end(); ++select_it ) 02393 { 02394 QList<QgsGeometry*> newGeometries; 02395 QList<QgsPoint> topologyTestPoints; 02396 QgsGeometry* newGeometry = 0; 02397 splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); 02398 if ( splitFunctionReturn == 0 ) 02399 { 02400 //change this geometry 02401 editGeometryChange( select_it->id(), *( select_it->geometry() ) ); 02402 //update of cached geometries is necessary because we use addTopologicalPoints() later 02403 mCachedGeometries[select_it->id()] = *( select_it->geometry() ); 02404 02405 //insert new features 02406 for ( int i = 0; i < newGeometries.size(); ++i ) 02407 { 02408 newGeometry = newGeometries.at( i ); 02409 QgsFeature newFeature; 02410 newFeature.setGeometry( newGeometry ); 02411 02412 //use default value where possible (primary key issue), otherwise the value from the original (splitted) feature 02413 QgsAttributeMap newAttributes = select_it->attributeMap(); 02414 QVariant defaultValue; 02415 for ( int j = 0; j < newAttributes.size(); ++j ) 02416 { 02417 if ( mDataProvider ) 02418 { 02419 defaultValue = mDataProvider->defaultValue( j ); 02420 if ( !defaultValue.isNull() ) 02421 { 02422 newAttributes.insert( j, defaultValue ); 02423 } 02424 } 02425 } 02426 02427 newFeature.setAttributeMap( newAttributes ); 02428 newFeatures.append( newFeature ); 02429 } 02430 02431 setModified( true, true ); 02432 if ( topologicalEditing ) 02433 { 02434 QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); 02435 for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) 02436 { 02437 addTopologicalPoints( *topol_it ); 02438 } 02439 } 02440 ++numberOfSplittedFeatures; 02441 } 02442 else if ( splitFunctionReturn > 1 ) //1 means no split but also no error 02443 { 02444 returnCode = splitFunctionReturn; 02445 } 02446 } 02447 02448 if ( numberOfSplittedFeatures == 0 && selectedIds.size() > 0 ) 02449 { 02450 //There is a selection but no feature has been split. 02451 //Maybe user forgot that only the selected features are split 02452 returnCode = 4; 02453 } 02454 02455 02456 //now add the new features to this vectorlayer 02457 addFeatures( newFeatures, false ); 02458 02459 return returnCode; 02460 } 02461 02462 int QgsVectorLayer::removePolygonIntersections( QgsGeometry* geom ) 02463 { 02464 if ( !hasGeometryType() ) 02465 return 1; 02466 02467 int returnValue = 0; 02468 02469 //first test if geom really has type polygon or multipolygon 02470 if ( geom->type() != QGis::Polygon ) 02471 { 02472 return 1; 02473 } 02474 02475 //get bounding box of geom 02476 QgsRectangle geomBBox = geom->boundingBox(); 02477 02478 //get list of features that intersect this bounding box 02479 select( QgsAttributeList(), geomBBox, true, true ); 02480 02481 QgsFeature f; 02482 while ( nextFeature( f ) ) 02483 { 02484 //call geometry->makeDifference for each feature 02485 QgsGeometry *currentGeom = f.geometry(); 02486 if ( currentGeom ) 02487 { 02488 if ( geom->makeDifference( currentGeom ) != 0 ) 02489 { 02490 returnValue = 2; 02491 } 02492 } 02493 } 02494 return returnValue; 02495 } 02496 02497 int QgsVectorLayer::addTopologicalPoints( QgsGeometry* geom ) 02498 { 02499 if ( !hasGeometryType() ) 02500 return 1; 02501 02502 if ( !geom ) 02503 { 02504 return 1; 02505 } 02506 02507 int returnVal = 0; 02508 02509 QGis::WkbType wkbType = geom->wkbType(); 02510 02511 switch ( wkbType ) 02512 { 02513 //line 02514 case QGis::WKBLineString25D: 02515 case QGis::WKBLineString: 02516 { 02517 QgsPolyline theLine = geom->asPolyline(); 02518 QgsPolyline::const_iterator line_it = theLine.constBegin(); 02519 for ( ; line_it != theLine.constEnd(); ++line_it ) 02520 { 02521 if ( addTopologicalPoints( *line_it ) != 0 ) 02522 { 02523 returnVal = 2; 02524 } 02525 } 02526 break; 02527 } 02528 02529 //multiline 02530 case QGis::WKBMultiLineString25D: 02531 case QGis::WKBMultiLineString: 02532 { 02533 QgsMultiPolyline theMultiLine = geom->asMultiPolyline(); 02534 QgsPolyline currentPolyline; 02535 02536 for ( int i = 0; i < theMultiLine.size(); ++i ) 02537 { 02538 QgsPolyline::const_iterator line_it = currentPolyline.constBegin(); 02539 for ( ; line_it != currentPolyline.constEnd(); ++line_it ) 02540 { 02541 if ( addTopologicalPoints( *line_it ) != 0 ) 02542 { 02543 returnVal = 2; 02544 } 02545 } 02546 } 02547 break; 02548 } 02549 02550 //polygon 02551 case QGis::WKBPolygon25D: 02552 case QGis::WKBPolygon: 02553 { 02554 QgsPolygon thePolygon = geom->asPolygon(); 02555 QgsPolyline currentRing; 02556 02557 for ( int i = 0; i < thePolygon.size(); ++i ) 02558 { 02559 currentRing = thePolygon.at( i ); 02560 QgsPolyline::const_iterator line_it = currentRing.constBegin(); 02561 for ( ; line_it != currentRing.constEnd(); ++line_it ) 02562 { 02563 if ( addTopologicalPoints( *line_it ) != 0 ) 02564 { 02565 returnVal = 2; 02566 } 02567 } 02568 } 02569 break; 02570 } 02571 02572 //multipolygon 02573 case QGis::WKBMultiPolygon25D: 02574 case QGis::WKBMultiPolygon: 02575 { 02576 QgsMultiPolygon theMultiPolygon = geom->asMultiPolygon(); 02577 QgsPolygon currentPolygon; 02578 QgsPolyline currentRing; 02579 02580 for ( int i = 0; i < theMultiPolygon.size(); ++i ) 02581 { 02582 currentPolygon = theMultiPolygon.at( i ); 02583 for ( int j = 0; j < currentPolygon.size(); ++j ) 02584 { 02585 currentRing = currentPolygon.at( j ); 02586 QgsPolyline::const_iterator line_it = currentRing.constBegin(); 02587 for ( ; line_it != currentRing.constEnd(); ++line_it ) 02588 { 02589 if ( addTopologicalPoints( *line_it ) != 0 ) 02590 { 02591 returnVal = 2; 02592 } 02593 } 02594 } 02595 } 02596 break; 02597 } 02598 default: 02599 break; 02600 } 02601 return returnVal; 02602 } 02603 02604 int QgsVectorLayer::addTopologicalPoints( const QgsPoint& p ) 02605 { 02606 if ( !hasGeometryType() ) 02607 return 1; 02608 02609 QMultiMap<double, QgsSnappingResult> snapResults; //results from the snapper object 02610 //we also need to snap to vertex to make sure the vertex does not already exist in this geometry 02611 QMultiMap<double, QgsSnappingResult> vertexSnapResults; 02612 02613 QList<QgsSnappingResult> filteredSnapResults; //we filter out the results that are on existing vertices 02614 02615 //work with a tolerance because coordinate projection may introduce some rounding 02616 double threshold = 0.0000001; 02617 if ( crs().mapUnits() == QGis::Meters ) 02618 { 02619 threshold = 0.001; 02620 } 02621 else if ( crs().mapUnits() == QGis::Feet ) 02622 { 02623 threshold = 0.0001; 02624 } 02625 02626 02627 if ( snapWithContext( p, threshold, snapResults, QgsSnapper::SnapToSegment ) != 0 ) 02628 { 02629 return 2; 02630 } 02631 02632 QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin(); 02633 QMultiMap<double, QgsSnappingResult>::const_iterator vertex_snap_it; 02634 for ( ; snap_it != snapResults.constEnd(); ++snap_it ) 02635 { 02636 //test if p is already a vertex of this geometry. If yes, don't insert it 02637 bool vertexAlreadyExists = false; 02638 if ( snapWithContext( p, threshold, vertexSnapResults, QgsSnapper::SnapToVertex ) != 0 ) 02639 { 02640 continue; 02641 } 02642 02643 vertex_snap_it = vertexSnapResults.constBegin(); 02644 for ( ; vertex_snap_it != vertexSnapResults.constEnd(); ++vertex_snap_it ) 02645 { 02646 if ( snap_it.value().snappedAtGeometry == vertex_snap_it.value().snappedAtGeometry ) 02647 { 02648 vertexAlreadyExists = true; 02649 } 02650 } 02651 02652 if ( !vertexAlreadyExists ) 02653 { 02654 filteredSnapResults.push_back( *snap_it ); 02655 } 02656 } 02657 insertSegmentVerticesForSnap( filteredSnapResults ); 02658 return 0; 02659 } 02660 02661 QgsLabel *QgsVectorLayer::label() 02662 { 02663 return mLabel; 02664 } 02665 02666 const QgsLabel *QgsVectorLayer::label() const 02667 { 02668 return mLabel; 02669 } 02670 02671 void QgsVectorLayer::enableLabels( bool on ) 02672 { 02673 mLabelOn = on; 02674 } 02675 02676 bool QgsVectorLayer::hasLabelsEnabled( void ) const 02677 { 02678 return mLabelOn; 02679 } 02680 02681 bool QgsVectorLayer::startEditing() 02682 { 02683 if ( !mDataProvider ) 02684 { 02685 return false; 02686 } 02687 02688 // allow editing if provider supports any of the capabilities 02689 if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities ) ) 02690 { 02691 return false; 02692 } 02693 02694 if ( mReadOnly ) 02695 { 02696 return false; 02697 } 02698 02699 if ( mEditable ) 02700 { 02701 // editing already underway 02702 return false; 02703 } 02704 02705 mEditable = true; 02706 02707 mAddedAttributeIds.clear(); 02708 mDeletedAttributeIds.clear(); 02709 updateFieldMap(); 02710 02711 for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ ) 02712 if ( it.key() > mMaxUpdatedIndex ) 02713 mMaxUpdatedIndex = it.key(); 02714 02715 emit editingStarted(); 02716 02717 return true; 02718 } 02719 02720 bool QgsVectorLayer::readXml( const QDomNode& layer_node ) 02721 { 02722 QgsDebugMsg( QString( "Datasource in QgsVectorLayer::readXml: " ) + mDataSource.toLocal8Bit().data() ); 02723 02724 //process provider key 02725 QDomNode pkeyNode = layer_node.namedItem( "provider" ); 02726 02727 if ( pkeyNode.isNull() ) 02728 { 02729 mProviderKey = ""; 02730 } 02731 else 02732 { 02733 QDomElement pkeyElt = pkeyNode.toElement(); 02734 mProviderKey = pkeyElt.text(); 02735 } 02736 02737 // determine type of vector layer 02738 if ( ! mProviderKey.isNull() ) 02739 { 02740 // if the provider string isn't empty, then we successfully 02741 // got the stored provider 02742 } 02743 else if ( mDataSource.contains( "dbname=" ) ) 02744 { 02745 mProviderKey = "postgres"; 02746 } 02747 else 02748 { 02749 mProviderKey = "ogr"; 02750 } 02751 02752 if ( ! setDataProvider( mProviderKey ) ) 02753 { 02754 return false; 02755 } 02756 02757 QDomElement pkeyElem = pkeyNode.toElement(); 02758 if ( !pkeyElem.isNull() ) 02759 { 02760 QString encodingString = pkeyElem.attribute( "encoding" ); 02761 if ( !encodingString.isEmpty() ) 02762 { 02763 mDataProvider->setEncoding( encodingString ); 02764 } 02765 } 02766 02767 //load vector joins 02768 if ( !mJoinBuffer ) 02769 { 02770 mJoinBuffer = new QgsVectorLayerJoinBuffer(); 02771 } 02772 mJoinBuffer->readXml( layer_node ); 02773 02774 updateFieldMap(); 02775 connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) ); 02776 02777 QString errorMsg; 02778 if ( !readSymbology( layer_node, errorMsg ) ) 02779 { 02780 return false; 02781 } 02782 02783 return mValid; // should be true if read successfully 02784 02785 } // void QgsVectorLayer::readXml 02786 02787 02788 02789 bool QgsVectorLayer::setDataProvider( QString const & provider ) 02790 { 02791 // XXX should I check for and possibly delete any pre-existing providers? 02792 // XXX How often will that scenario occur? 02793 02794 mProviderKey = provider; // XXX is this necessary? Usually already set 02795 // XXX when execution gets here. 02796 02797 //XXX - This was a dynamic cast but that kills the Windows 02798 // version big-time with an abnormal termination error 02799 mDataProvider = 02800 ( QgsVectorDataProvider* )( QgsProviderRegistry::instance()->provider( provider, mDataSource ) ); 02801 02802 if ( mDataProvider ) 02803 { 02804 QgsDebugMsg( "Instantiated the data provider plugin" ); 02805 02806 mValid = mDataProvider->isValid(); 02807 if ( mValid ) 02808 { 02809 02810 // TODO: Check if the provider has the capability to send fullExtentCalculated 02811 connect( mDataProvider, SIGNAL( fullExtentCalculated() ), this, SLOT( updateExtents() ) ); 02812 02813 // get the extent 02814 QgsRectangle mbr = mDataProvider->extent(); 02815 02816 // show the extent 02817 QString s = mbr.toString(); 02818 QgsDebugMsg( "Extent of layer: " + s ); 02819 // store the extent 02820 mLayerExtent.setXMaximum( mbr.xMaximum() ); 02821 mLayerExtent.setXMinimum( mbr.xMinimum() ); 02822 mLayerExtent.setYMaximum( mbr.yMaximum() ); 02823 mLayerExtent.setYMinimum( mbr.yMinimum() ); 02824 02825 // get and store the feature type 02826 mWkbType = mDataProvider->geometryType(); 02827 02828 // look at the fields in the layer and set the primary 02829 // display field using some real fuzzy logic 02830 setDisplayField(); 02831 02832 if ( mProviderKey == "postgres" ) 02833 { 02834 QgsDebugMsg( "Beautifying layer name " + name() ); 02835 02836 // adjust the display name for postgres layers 02837 QRegExp reg( "\"[^\"]+\"\\.\"([^\"]+)\"( \\([^)]+\\))?" ); 02838 if ( reg.indexIn( name() ) >= 0 ) 02839 { 02840 QStringList stuff = reg.capturedTexts(); 02841 QString lName = stuff[1]; 02842 02843 const QMap<QString, QgsMapLayer*> &layers = QgsMapLayerRegistry::instance()->mapLayers(); 02844 02845 QMap<QString, QgsMapLayer*>::const_iterator it; 02846 for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; it++ ) 02847 ; 02848 02849 if ( it != layers.constEnd() && stuff.size() > 2 ) 02850 { 02851 lName += "." + stuff[2].mid( 2, stuff[2].length() - 3 ); 02852 } 02853 02854 if ( !lName.isEmpty() ) 02855 setLayerName( lName ); 02856 } 02857 02858 QgsDebugMsg( "Beautified layer name " + name() ); 02859 02860 // deal with unnecessary schema qualification to make v.in.ogr happy 02861 mDataSource = mDataProvider->dataSourceUri(); 02862 } 02863 else if ( mProviderKey == "osm" ) 02864 { 02865 // make sure that the "observer" has been removed from URI to avoid crashes 02866 mDataSource = mDataProvider->dataSourceUri(); 02867 } 02868 else if ( provider == "ogr" ) 02869 { 02870 // make sure that the /vsigzip or /vsizip is added to uri, if applicable 02871 mDataSource = mDataProvider->dataSourceUri(); 02872 if ( mDataSource.right( 10 ) == "|layerid=0" ) 02873 mDataSource.chop( 10 ); 02874 } 02875 02876 // label 02877 mLabel = new QgsLabel( mDataProvider->fields() ); 02878 mLabelOn = false; 02879 } 02880 else 02881 { 02882 QgsDebugMsg( "Invalid provider plugin " + QString( mDataSource.toUtf8() ) ); 02883 return false; 02884 } 02885 } 02886 else 02887 { 02888 QgsDebugMsg( " unable to get data provider" ); 02889 return false; 02890 } 02891 02892 return true; 02893 02894 } // QgsVectorLayer:: setDataProvider 02895 02896 02897 02898 02899 /* virtual */ 02900 bool QgsVectorLayer::writeXml( QDomNode & layer_node, 02901 QDomDocument & document ) 02902 { 02903 // first get the layer element so that we can append the type attribute 02904 02905 QDomElement mapLayerNode = layer_node.toElement(); 02906 02907 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) ) 02908 { 02909 QgsDebugMsg( "can't find <maplayer>" ); 02910 return false; 02911 } 02912 02913 mapLayerNode.setAttribute( "type", "vector" ); 02914 02915 // set the geometry type 02916 mapLayerNode.setAttribute( "geometry", QGis::qgisVectorGeometryType[geometryType()] ); 02917 02918 // add provider node 02919 if ( mDataProvider ) 02920 { 02921 QDomElement provider = document.createElement( "provider" ); 02922 provider.setAttribute( "encoding", mDataProvider->encoding() ); 02923 QDomText providerText = document.createTextNode( providerType() ); 02924 provider.appendChild( providerText ); 02925 layer_node.appendChild( provider ); 02926 } 02927 02928 //save joins 02929 mJoinBuffer->writeXml( layer_node, document ); 02930 02931 // renderer specific settings 02932 QString errorMsg; 02933 return writeSymbology( layer_node, document, errorMsg ); 02934 } // bool QgsVectorLayer::writeXml 02935 02936 bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage ) 02937 { 02938 if ( hasGeometryType() ) 02939 { 02940 // try renderer v2 first 02941 QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME ); 02942 if ( !rendererElement.isNull() ) 02943 { 02944 // using renderer v2 02945 setUsingRendererV2( true ); 02946 02947 QgsFeatureRendererV2* r = QgsFeatureRendererV2::load( rendererElement ); 02948 if ( !r ) 02949 return false; 02950 02951 setRendererV2( r ); 02952 } 02953 else 02954 { 02955 // using renderer v1 02956 setUsingRendererV2( false ); 02957 02958 // create and bind a renderer to this layer 02959 02960 QDomNode singlenode = node.namedItem( "singlesymbol" ); 02961 QDomNode graduatednode = node.namedItem( "graduatedsymbol" ); 02962 QDomNode continuousnode = node.namedItem( "continuoussymbol" ); 02963 QDomNode uniquevaluenode = node.namedItem( "uniquevalue" ); 02964 02965 QgsRenderer * renderer = 0; 02966 int returnCode = 1; 02967 02968 if ( !singlenode.isNull() ) 02969 { 02970 renderer = new QgsSingleSymbolRenderer( geometryType() ); 02971 returnCode = renderer->readXML( singlenode, *this ); 02972 } 02973 else if ( !graduatednode.isNull() ) 02974 { 02975 renderer = new QgsGraduatedSymbolRenderer( geometryType() ); 02976 returnCode = renderer->readXML( graduatednode, *this ); 02977 } 02978 else if ( !continuousnode.isNull() ) 02979 { 02980 renderer = new QgsContinuousColorRenderer( geometryType() ); 02981 returnCode = renderer->readXML( continuousnode, *this ); 02982 } 02983 else if ( !uniquevaluenode.isNull() ) 02984 { 02985 renderer = new QgsUniqueValueRenderer( geometryType() ); 02986 returnCode = renderer->readXML( uniquevaluenode, *this ); 02987 } 02988 02989 if ( !renderer ) 02990 { 02991 errorMessage = tr( "Unknown renderer" ); 02992 return false; 02993 } 02994 02995 if ( returnCode == 1 ) 02996 { 02997 errorMessage = tr( "No renderer object" ); 02998 delete renderer; 02999 return false; 03000 } 03001 else if ( returnCode == 2 ) 03002 { 03003 errorMessage = tr( "Classification field not found" ); 03004 delete renderer; 03005 return false; 03006 } 03007 03008 mRenderer = renderer; 03009 } 03010 03011 // get and set the display field if it exists. 03012 QDomNode displayFieldNode = node.namedItem( "displayfield" ); 03013 if ( !displayFieldNode.isNull() ) 03014 { 03015 QDomElement e = displayFieldNode.toElement(); 03016 setDisplayField( e.text() ); 03017 } 03018 03019 // use scale dependent visibility flag 03020 QDomElement e = node.toElement(); 03021 mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" ); 03022 mLabel->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() ); 03023 mLabel->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() ); 03024 03025 //also restore custom properties (for labeling-ng) 03026 readCustomProperties( node, "labeling" ); 03027 03028 // Test if labeling is on or off 03029 QDomNode labelnode = node.namedItem( "label" ); 03030 QDomElement element = labelnode.toElement(); 03031 int hasLabelsEnabled = element.text().toInt(); 03032 if ( hasLabelsEnabled < 1 ) 03033 { 03034 enableLabels( false ); 03035 } 03036 else 03037 { 03038 enableLabels( true ); 03039 } 03040 03041 QDomNode labelattributesnode = node.namedItem( "labelattributes" ); 03042 03043 if ( !labelattributesnode.isNull() ) 03044 { 03045 QgsDebugMsg( "calling readXML" ); 03046 mLabel->readXML( labelattributesnode ); 03047 } 03048 03049 //diagram renderer and diagram layer settings 03050 delete mDiagramRenderer; mDiagramRenderer = 0; 03051 QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" ); 03052 if ( !singleCatDiagramElem.isNull() ) 03053 { 03054 mDiagramRenderer = new QgsSingleCategoryDiagramRenderer(); 03055 mDiagramRenderer->readXML( singleCatDiagramElem ); 03056 } 03057 QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" ); 03058 if ( !linearDiagramElem.isNull() ) 03059 { 03060 mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer(); 03061 mDiagramRenderer->readXML( linearDiagramElem ); 03062 } 03063 03064 if ( mDiagramRenderer ) 03065 { 03066 QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" ); 03067 if ( !diagramSettingsElem.isNull() ) 03068 { 03069 mDiagramLayerSettings = new QgsDiagramLayerSettings(); 03070 mDiagramLayerSettings->readXML( diagramSettingsElem ); 03071 } 03072 } 03073 } 03074 03075 // process the attribute actions 03076 mActions->readXML( node ); 03077 03078 mEditTypes.clear(); 03079 QDomNode editTypesNode = node.namedItem( "edittypes" ); 03080 if ( !editTypesNode.isNull() ) 03081 { 03082 QDomNodeList editTypeNodes = editTypesNode.childNodes(); 03083 03084 for ( int i = 0; i < editTypeNodes.size(); i++ ) 03085 { 03086 QDomNode editTypeNode = editTypeNodes.at( i ); 03087 QDomElement editTypeElement = editTypeNode.toElement(); 03088 03089 QString name = editTypeElement.attribute( "name" ); 03090 if ( fieldNameIndex( name ) < -1 ) 03091 continue; 03092 03093 EditType editType = ( EditType ) editTypeElement.attribute( "type" ).toInt(); 03094 mEditTypes.insert( name, editType ); 03095 03096 switch ( editType ) 03097 { 03098 case ValueMap: 03099 if ( editTypeNode.hasChildNodes() ) 03100 { 03101 mValueMaps.insert( name, QMap<QString, QVariant>() ); 03102 03103 QDomNodeList valueMapNodes = editTypeNode.childNodes(); 03104 for ( int j = 0; j < valueMapNodes.size(); j++ ) 03105 { 03106 QDomElement value = valueMapNodes.at( j ).toElement(); 03107 mValueMaps[ name ].insert( value.attribute( "key" ), value.attribute( "value" ) ); 03108 } 03109 } 03110 break; 03111 03112 case EditRange: 03113 case SliderRange: 03114 case DialRange: 03115 { 03116 QVariant min = editTypeElement.attribute( "min" ); 03117 QVariant max = editTypeElement.attribute( "max" ); 03118 QVariant step = editTypeElement.attribute( "step" ); 03119 03120 mRanges[ name ] = RangeData( min, max, step ); 03121 } 03122 break; 03123 03124 case CheckBox: 03125 mCheckedStates[ name ] = QPair<QString, QString>( editTypeElement.attribute( "checked" ), editTypeElement.attribute( "unchecked" ) ); 03126 break; 03127 03128 case ValueRelation: 03129 { 03130 QString id = editTypeElement.attribute( "layer" ); 03131 QString key = editTypeElement.attribute( "key" ); 03132 QString value = editTypeElement.attribute( "value" ); 03133 bool allowNull = editTypeElement.attribute( "allowNull" ) == "true"; 03134 bool orderByValue = editTypeElement.attribute( "orderByValue" ) == "true"; 03135 mValueRelations[ name ] = ValueRelationData( id, key, value, allowNull, orderByValue ); 03136 } 03137 break; 03138 03139 case Classification: 03140 case FileName: 03141 case Immutable: 03142 case Hidden: 03143 case LineEdit: 03144 case TextEdit: 03145 case Calendar: 03146 case Enumeration: 03147 case UniqueValues: 03148 case UniqueValuesEditable: 03149 case UuidGenerator: 03150 break; 03151 } 03152 } 03153 } 03154 03155 QDomNode editFormNode = node.namedItem( "editform" ); 03156 if ( !editFormNode.isNull() ) 03157 { 03158 QDomElement e = editFormNode.toElement(); 03159 mEditForm = QgsProject::instance()->readPath( e.text() ); 03160 } 03161 03162 QDomNode editFormInitNode = node.namedItem( "editforminit" ); 03163 if ( !editFormInitNode.isNull() ) 03164 { 03165 mEditFormInit = editFormInitNode.toElement().text(); 03166 } 03167 03168 QDomNode annotationFormNode = node.namedItem( "annotationform" ); 03169 if ( !annotationFormNode.isNull() ) 03170 { 03171 QDomElement e = annotationFormNode.toElement(); 03172 mAnnotationForm = QgsProject::instance()->readPath( e.text() ); 03173 } 03174 03175 mAttributeAliasMap.clear(); 03176 QDomNode aliasesNode = node.namedItem( "aliases" ); 03177 if ( !aliasesNode.isNull() ) 03178 { 03179 QDomElement aliasElem; 03180 QString name; 03181 03182 QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( "alias" ); 03183 for ( int i = 0; i < aliasNodeList.size(); ++i ) 03184 { 03185 aliasElem = aliasNodeList.at( i ).toElement(); 03186 03187 QString field; 03188 if ( aliasElem.hasAttribute( "field" ) ) 03189 { 03190 field = aliasElem.attribute( "field" ); 03191 } 03192 else 03193 { 03194 int index = aliasElem.attribute( "index" ).toInt(); 03195 03196 if ( pendingFields().contains( index ) ) 03197 field = pendingFields()[ index ].name(); 03198 } 03199 03200 mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) ); 03201 } 03202 } 03203 03204 return true; 03205 } 03206 03207 bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const 03208 { 03209 QDomElement mapLayerNode = node.toElement(); 03210 03211 if ( hasGeometryType() ) 03212 { 03213 if ( mUsingRendererV2 ) 03214 { 03215 QDomElement rendererElement = mRendererV2->save( doc ); 03216 node.appendChild( rendererElement ); 03217 } 03218 else 03219 { 03220 // use scale dependent visibility flag 03221 mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", mLabel->scaleBasedVisibility() ? 1 : 0 ); 03222 mapLayerNode.setAttribute( "minLabelScale", QString::number( mLabel->minScale() ) ); 03223 mapLayerNode.setAttribute( "maxLabelScale", QString::number( mLabel->maxScale() ) ); 03224 03225 //classification field(s) 03226 QgsAttributeList attributes = mRenderer->classificationAttributes(); 03227 const QgsFieldMap providerFields = mDataProvider->fields(); 03228 for ( QgsAttributeList::const_iterator it = attributes.begin(); it != attributes.end(); ++it ) 03229 { 03230 QDomElement classificationElement = doc.createElement( "classificationattribute" ); 03231 QDomText classificationText = doc.createTextNode( providerFields[*it].name() ); 03232 classificationElement.appendChild( classificationText ); 03233 node.appendChild( classificationElement ); 03234 } 03235 03236 // renderer settings 03237 const QgsRenderer * myRenderer = renderer(); 03238 if ( myRenderer ) 03239 { 03240 if ( !myRenderer->writeXML( node, doc, *this ) ) 03241 { 03242 errorMessage = tr( "renderer failed to save" ); 03243 return false; 03244 } 03245 } 03246 else 03247 { 03248 QgsDebugMsg( "no renderer" ); 03249 errorMessage = tr( "no renderer" ); 03250 return false; 03251 } 03252 } 03253 03254 //save customproperties (for labeling ng) 03255 writeCustomProperties( node, doc ); 03256 03257 // add the display field 03258 QDomElement dField = doc.createElement( "displayfield" ); 03259 QDomText dFieldText = doc.createTextNode( displayField() ); 03260 dField.appendChild( dFieldText ); 03261 node.appendChild( dField ); 03262 03263 // add label node 03264 QDomElement labelElem = doc.createElement( "label" ); 03265 QDomText labelText = doc.createTextNode( "" ); 03266 03267 if ( hasLabelsEnabled() ) 03268 { 03269 labelText.setData( "1" ); 03270 } 03271 else 03272 { 03273 labelText.setData( "0" ); 03274 } 03275 labelElem.appendChild( labelText ); 03276 03277 node.appendChild( labelElem ); 03278 03279 // Now we get to do all that all over again for QgsLabel 03280 03281 QString fieldname = mLabel->labelField( QgsLabel::Text ); 03282 if ( fieldname != "" ) 03283 { 03284 dField = doc.createElement( "labelfield" ); 03285 dFieldText = doc.createTextNode( fieldname ); 03286 dField.appendChild( dFieldText ); 03287 node.appendChild( dField ); 03288 } 03289 03290 mLabel->writeXML( node, doc ); 03291 03292 if ( mDiagramRenderer ) 03293 { 03294 mDiagramRenderer->writeXML( mapLayerNode, doc ); 03295 if ( mDiagramLayerSettings ) 03296 mDiagramLayerSettings->writeXML( mapLayerNode, doc ); 03297 } 03298 } 03299 03300 //edit types 03301 if ( mEditTypes.size() > 0 ) 03302 { 03303 QDomElement editTypesElement = doc.createElement( "edittypes" ); 03304 03305 for ( QMap<QString, EditType>::const_iterator it = mEditTypes.begin(); it != mEditTypes.end(); ++it ) 03306 { 03307 QDomElement editTypeElement = doc.createElement( "edittype" ); 03308 editTypeElement.setAttribute( "name", it.key() ); 03309 editTypeElement.setAttribute( "type", it.value() ); 03310 03311 switch (( EditType ) it.value() ) 03312 { 03313 case ValueMap: 03314 if ( mValueMaps.contains( it.key() ) ) 03315 { 03316 const QMap<QString, QVariant> &map = mValueMaps[ it.key()]; 03317 03318 for ( QMap<QString, QVariant>::const_iterator vmit = map.begin(); vmit != map.end(); vmit++ ) 03319 { 03320 QDomElement value = doc.createElement( "valuepair" ); 03321 value.setAttribute( "key", vmit.key() ); 03322 value.setAttribute( "value", vmit.value().toString() ); 03323 editTypeElement.appendChild( value ); 03324 } 03325 } 03326 break; 03327 03328 case EditRange: 03329 case SliderRange: 03330 case DialRange: 03331 if ( mRanges.contains( it.key() ) ) 03332 { 03333 editTypeElement.setAttribute( "min", mRanges[ it.key()].mMin.toString() ); 03334 editTypeElement.setAttribute( "max", mRanges[ it.key()].mMax.toString() ); 03335 editTypeElement.setAttribute( "step", mRanges[ it.key()].mStep.toString() ); 03336 } 03337 break; 03338 03339 case CheckBox: 03340 if ( mCheckedStates.contains( it.key() ) ) 03341 { 03342 editTypeElement.setAttribute( "checked", mCheckedStates[ it.key()].first ); 03343 editTypeElement.setAttribute( "unchecked", mCheckedStates[ it.key()].second ); 03344 } 03345 break; 03346 03347 case ValueRelation: 03348 if ( mValueRelations.contains( it.key() ) ) 03349 { 03350 const ValueRelationData &data = mValueRelations[ it.key()]; 03351 editTypeElement.setAttribute( "layer", data.mLayer ); 03352 editTypeElement.setAttribute( "key", data.mKey ); 03353 editTypeElement.setAttribute( "value", data.mValue ); 03354 editTypeElement.setAttribute( "allowNull", data.mAllowNull ? "true" : "false" ); 03355 editTypeElement.setAttribute( "orderByValue", data.mOrderByValue ? "true" : "false" ); 03356 } 03357 break; 03358 03359 case LineEdit: 03360 case UniqueValues: 03361 case UniqueValuesEditable: 03362 case Classification: 03363 case FileName: 03364 case Hidden: 03365 case TextEdit: 03366 case Calendar: 03367 case Enumeration: 03368 case Immutable: 03369 case UuidGenerator: 03370 break; 03371 } 03372 03373 editTypesElement.appendChild( editTypeElement ); 03374 } 03375 03376 node.appendChild( editTypesElement ); 03377 } 03378 03379 QDomElement efField = doc.createElement( "editform" ); 03380 QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( mEditForm ) ); 03381 efField.appendChild( efText ); 03382 node.appendChild( efField ); 03383 03384 QDomElement efiField = doc.createElement( "editforminit" ); 03385 QDomText efiText = doc.createTextNode( mEditFormInit ); 03386 efiField.appendChild( efiText ); 03387 node.appendChild( efiField ); 03388 03389 QDomElement afField = doc.createElement( "annotationform" ); 03390 QDomText afText = doc.createTextNode( QgsProject::instance()->writePath( mAnnotationForm ) ); 03391 afField.appendChild( afText ); 03392 node.appendChild( afField ); 03393 03394 //attribute aliases 03395 if ( mAttributeAliasMap.size() > 0 ) 03396 { 03397 QDomElement aliasElem = doc.createElement( "aliases" ); 03398 QMap<QString, QString>::const_iterator a_it = mAttributeAliasMap.constBegin(); 03399 for ( ; a_it != mAttributeAliasMap.constEnd(); ++a_it ) 03400 { 03401 int idx = fieldNameIndex( a_it.key() ); 03402 if ( idx < 0 ) 03403 continue; 03404 03405 QDomElement aliasEntryElem = doc.createElement( "alias" ); 03406 aliasEntryElem.setAttribute( "field", a_it.key() ); 03407 aliasEntryElem.setAttribute( "index", idx ); 03408 aliasEntryElem.setAttribute( "name", a_it.value() ); 03409 aliasElem.appendChild( aliasEntryElem ); 03410 } 03411 node.appendChild( aliasElem ); 03412 } 03413 03414 // add attribute actions 03415 mActions->writeXML( node, doc ); 03416 03417 //save vector overlays (e.g. diagrams) 03418 QList<QgsVectorOverlay*>::const_iterator overlay_it = mOverlays.constBegin(); 03419 for ( ; overlay_it != mOverlays.constEnd(); ++overlay_it ) 03420 { 03421 if ( *overlay_it ) 03422 { 03423 ( *overlay_it )->writeXML( mapLayerNode, doc ); 03424 } 03425 } 03426 03427 return true; 03428 } 03429 03430 bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage ) 03431 { 03432 // get the Name element 03433 QDomElement nameElem = node.firstChildElement( "Name" ); 03434 if ( nameElem.isNull() ) 03435 { 03436 errorMessage = "Warning: Name element not found within NamedLayer while it's required."; 03437 } 03438 03439 if ( hasGeometryType() ) 03440 { 03441 setUsingRendererV2( true ); 03442 03443 QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage ); 03444 if ( !r ) 03445 return false; 03446 03447 setRendererV2( r ); 03448 } 03449 return true; 03450 } 03451 03452 03453 bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const 03454 { 03455 Q_UNUSED( errorMessage ); 03456 03457 // store the Name element 03458 QDomElement nameNode = doc.createElement( "se:Name" ); 03459 nameNode.appendChild( doc.createTextNode( name() ) ); 03460 node.appendChild( nameNode ); 03461 03462 if ( hasGeometryType() ) 03463 { 03464 if ( mUsingRendererV2 ) 03465 { 03466 node.appendChild( mRendererV2->writeSld( doc, *this ) ); 03467 } 03468 else 03469 { 03470 node.appendChild( doc.createComment( "Old Renderer not supported yet" ) ); 03471 return false; 03472 } 03473 } 03474 return true; 03475 } 03476 03477 03478 bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom ) 03479 { 03480 if ( !mEditable || !mDataProvider || !hasGeometryType() ) 03481 { 03482 return false; 03483 } 03484 03485 editGeometryChange( fid, *geom ); 03486 mCachedGeometries[fid] = *geom; 03487 setModified( true, true ); 03488 03489 return true; 03490 } 03491 03492 03493 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value, bool emitSignal ) 03494 { 03495 if ( !isEditable() ) 03496 return false; 03497 03498 editAttributeChange( fid, field, value ); 03499 setModified( true, false ); 03500 03501 if ( emitSignal ) 03502 emit attributeValueChanged( fid, field, value ); 03503 03504 return true; 03505 } 03506 03507 bool QgsVectorLayer::addAttribute( const QgsField &field ) 03508 { 03509 if ( !isEditable() ) 03510 return false; 03511 03512 if ( field.name().isEmpty() ) 03513 return false; 03514 03515 for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ ) 03516 { 03517 if ( it.value().name() == field.name() ) 03518 return false; 03519 } 03520 03521 if ( !mDataProvider->supportedType( field ) ) 03522 return false; 03523 03524 mMaxUpdatedIndex++; 03525 03526 if ( mActiveCommand != NULL ) 03527 { 03528 mActiveCommand->storeAttributeAdd( mMaxUpdatedIndex, field ); 03529 } 03530 03531 mUpdatedFields.insert( mMaxUpdatedIndex, field ); 03532 mAddedAttributeIds.insert( mMaxUpdatedIndex ); 03533 03534 setModified( true, false ); 03535 03536 emit attributeAdded( mMaxUpdatedIndex ); 03537 03538 return true; 03539 } 03540 03541 bool QgsVectorLayer::addAttribute( QString name, QString type ) 03542 { 03543 const QList< QgsVectorDataProvider::NativeType > &types = mDataProvider->nativeTypes(); 03544 03545 int i; 03546 for ( i = 0; i < types.size() && types[i].mTypeName != type; i++ ) 03547 ; 03548 03549 return i < types.size() && addAttribute( QgsField( name, types[i].mType, type ) ); 03550 } 03551 03552 void QgsVectorLayer::addAttributeAlias( int attIndex, QString aliasString ) 03553 { 03554 if ( !pendingFields().contains( attIndex ) ) 03555 return; 03556 03557 QString name = pendingFields()[ attIndex ].name(); 03558 03559 mAttributeAliasMap.insert( name, aliasString ); 03560 emit layerModified( false ); 03561 } 03562 03563 QString QgsVectorLayer::attributeAlias( int attributeIndex ) const 03564 { 03565 if ( !pendingFields().contains( attributeIndex ) ) 03566 return ""; 03567 03568 QString name = pendingFields()[ attributeIndex ].name(); 03569 03570 return mAttributeAliasMap.value( name, "" ); 03571 } 03572 03573 QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const 03574 { 03575 QString displayName = attributeAlias( attributeIndex ); 03576 if ( displayName.isEmpty() ) 03577 { 03578 const QgsFieldMap& fields = pendingFields(); 03579 QgsFieldMap::const_iterator fieldIt = fields.find( attributeIndex ); 03580 if ( fieldIt != fields.constEnd() ) 03581 { 03582 displayName = fieldIt->name(); 03583 } 03584 } 03585 return displayName; 03586 } 03587 03588 bool QgsVectorLayer::deleteAttribute( int index ) 03589 { 03590 if ( !isEditable() ) 03591 return false; 03592 03593 if ( mDeletedAttributeIds.contains( index ) ) 03594 return false; 03595 03596 if ( !mAddedAttributeIds.contains( index ) && 03597 !mDataProvider->fields().contains( index ) ) 03598 return false; 03599 03600 if ( mActiveCommand != NULL ) 03601 { 03602 mActiveCommand->storeAttributeDelete( index, mUpdatedFields[index] ); 03603 } 03604 03605 mDeletedAttributeIds.insert( index ); 03606 mAddedAttributeIds.remove( index ); 03607 mUpdatedFields.remove( index ); 03608 03609 setModified( true, false ); 03610 03611 emit attributeDeleted( index ); 03612 03613 return true; 03614 } 03615 03616 bool QgsVectorLayer::deleteFeature( QgsFeatureId fid ) 03617 { 03618 if ( !isEditable() ) 03619 return false; 03620 03621 if ( mDeletedFeatureIds.contains( fid ) ) 03622 return true; 03623 03624 mSelectedFeatureIds.remove( fid ); // remove it from selection 03625 editFeatureDelete( fid ); 03626 03627 setModified( true, false ); 03628 03629 emit featureDeleted( fid ); 03630 03631 return true; 03632 } 03633 03634 const QgsFieldMap &QgsVectorLayer::pendingFields() const 03635 { 03636 return mUpdatedFields; 03637 } 03638 03639 QgsAttributeList QgsVectorLayer::pendingAllAttributesList() 03640 { 03641 return mUpdatedFields.keys(); 03642 } 03643 03644 int QgsVectorLayer::pendingFeatureCount() 03645 { 03646 return mDataProvider->featureCount() 03647 + mAddedFeatures.size() 03648 - mDeletedFeatureIds.size(); 03649 } 03650 03651 bool QgsVectorLayer::commitChanges() 03652 { 03653 bool success = true; 03654 03655 //clear the cache image so markers don't appear anymore on next draw 03656 setCacheImage( 0 ); 03657 03658 mCommitErrors.clear(); 03659 03660 if ( !mDataProvider ) 03661 { 03662 mCommitErrors << tr( "ERROR: no provider" ); 03663 return false; 03664 } 03665 03666 if ( !isEditable() ) 03667 { 03668 mCommitErrors << tr( "ERROR: layer not editable" ); 03669 return false; 03670 } 03671 03672 int cap = mDataProvider->capabilities(); 03673 03674 // 03675 // delete attributes 03676 // 03677 bool attributesChanged = false; 03678 if ( mDeletedAttributeIds.size() > 0 ) 03679 { 03680 if (( cap & QgsVectorDataProvider::DeleteAttributes ) && mDataProvider->deleteAttributes( mDeletedAttributeIds ) ) 03681 { 03682 mCommitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() ); 03683 03684 emit committedAttributesDeleted( id(), mDeletedAttributeIds ); 03685 03686 mDeletedAttributeIds.clear(); 03687 attributesChanged = true; 03688 } 03689 else 03690 { 03691 mCommitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() ); 03692 success = false; 03693 } 03694 } 03695 03696 // 03697 // add attributes 03698 // 03699 if ( mAddedAttributeIds.size() > 0 ) 03700 { 03701 QList<QgsField> addedAttributes; 03702 for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ ) 03703 { 03704 addedAttributes << mUpdatedFields[*it]; 03705 } 03706 03707 03708 if (( cap & QgsVectorDataProvider::AddAttributes ) && mDataProvider->addAttributes( addedAttributes ) ) 03709 { 03710 mCommitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributeIds.size() ); 03711 03712 emit committedAttributesAdded( id(), addedAttributes ); 03713 03714 mAddedAttributeIds.clear(); 03715 attributesChanged = true; 03716 } 03717 else 03718 { 03719 mCommitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributeIds.size() ); 03720 success = false; 03721 } 03722 } 03723 03724 // 03725 // remap changed and attributes of added features 03726 // 03727 bool attributeChangesOk = true; 03728 if ( attributesChanged ) 03729 { 03730 // map updates field indexes to names 03731 QMap<int, QString> src; 03732 for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ ) 03733 { 03734 src[ it.key()] = it.value().name(); 03735 } 03736 03737 int maxAttrIdx = -1; 03738 const QgsFieldMap &pFields = mDataProvider->fields(); 03739 03740 // map provider table names to field indexes 03741 QMap<QString, int> dst; 03742 for ( QgsFieldMap::const_iterator it = pFields.begin(); it != pFields.end(); it++ ) 03743 { 03744 dst[ it.value().name()] = it.key(); 03745 if ( it.key() > maxAttrIdx ) 03746 maxAttrIdx = it.key(); 03747 } 03748 03749 // if adding attributes failed add fields that are now missing 03750 // (otherwise we'll loose updates when doing the remapping) 03751 if ( mAddedAttributeIds.size() > 0 ) 03752 { 03753 for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ ) 03754 { 03755 QString name = mUpdatedFields[ *it ].name(); 03756 if ( dst.contains( name ) ) 03757 { 03758 // it's there => so we don't need to add it anymore 03759 mAddedAttributeIds.remove( *it ); 03760 mCommitErrors << tr( "SUCCESS: attribute %1 was added." ).arg( name ); 03761 } 03762 else 03763 { 03764 // field not there => put it behind the existing attributes 03765 dst[ name ] = ++maxAttrIdx; 03766 attributeChangesOk = false; // don't try attribute updates - they'll fail. 03767 mCommitErrors << tr( "ERROR: attribute %1 not added" ).arg( name ); 03768 } 03769 } 03770 } 03771 03772 // map updated fields to provider fields 03773 QMap<int, int> remap; 03774 for ( QMap<int, QString>::const_iterator it = src.begin(); it != src.end(); it++ ) 03775 { 03776 if ( dst.contains( it.value() ) ) 03777 { 03778 remap[ it.key()] = dst[ it.value()]; 03779 } 03780 } 03781 03782 // remap changed attributes 03783 for ( QgsChangedAttributesMap::iterator fit = mChangedAttributeValues.begin(); fit != mChangedAttributeValues.end(); fit++ ) 03784 { 03785 QgsAttributeMap &src = fit.value(); 03786 QgsAttributeMap dst; 03787 03788 for ( QgsAttributeMap::const_iterator it = src.begin(); it != src.end(); it++ ) 03789 { 03790 if ( remap.contains( it.key() ) ) 03791 { 03792 dst[ remap[it.key()] ] = it.value(); 03793 } 03794 } 03795 src = dst; 03796 } 03797 03798 // remap attributes of added features 03799 for ( QgsFeatureList::iterator fit = mAddedFeatures.begin(); fit != mAddedFeatures.end(); fit++ ) 03800 { 03801 const QgsAttributeMap &src = fit->attributeMap(); 03802 QgsAttributeMap dst; 03803 03804 for ( QgsAttributeMap::const_iterator it = src.begin(); it != src.end(); it++ ) 03805 if ( remap.contains( it.key() ) ) 03806 dst[ remap[it.key()] ] = it.value(); 03807 03808 fit->setAttributeMap( dst ); 03809 } 03810 03811 QgsFieldMap attributes; 03812 03813 // update private field map 03814 for ( QMap<int, int>::iterator it = remap.begin(); it != remap.end(); it++ ) 03815 attributes[ it.value()] = mUpdatedFields[ it.key()]; 03816 03817 mUpdatedFields = attributes; 03818 } 03819 03820 if ( attributeChangesOk ) 03821 { 03822 // 03823 // change attributes 03824 // 03825 if ( mChangedAttributeValues.size() > 0 ) 03826 { 03827 if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && mDataProvider->changeAttributeValues( mChangedAttributeValues ) ) 03828 { 03829 mCommitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() ); 03830 03831 emit committedAttributeValuesChanges( id(), mChangedAttributeValues ); 03832 03833 mChangedAttributeValues.clear(); 03834 } 03835 else 03836 { 03837 mCommitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() ); 03838 success = false; 03839 } 03840 } 03841 03842 // 03843 // add features 03844 // 03845 if ( mAddedFeatures.size() > 0 ) 03846 { 03847 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 03848 { 03849 QgsFeature &f = mAddedFeatures[i]; 03850 03851 if ( mDeletedFeatureIds.contains( f.id() ) ) 03852 { 03853 mDeletedFeatureIds.remove( f.id() ); 03854 03855 if ( mChangedGeometries.contains( f.id() ) ) 03856 mChangedGeometries.remove( f.id() ); 03857 03858 mAddedFeatures.removeAt( i-- ); 03859 continue; 03860 } 03861 03862 if ( mChangedGeometries.contains( f.id() ) ) 03863 { 03864 f.setGeometry( mChangedGeometries.take( f.id() ) ); 03865 } 03866 } 03867 03868 if ( cap & QgsVectorDataProvider::AddFeatures ) 03869 { 03870 QList<QgsFeatureId> ids; 03871 foreach( const QgsFeature &f, mAddedFeatures ) 03872 { 03873 ids << f.id(); 03874 } 03875 03876 if ( mDataProvider->addFeatures( mAddedFeatures ) ) 03877 { 03878 mCommitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", mAddedFeatures.size() ); 03879 03880 emit committedFeaturesAdded( id(), mAddedFeatures ); 03881 03882 // notify everyone that the features with temporary ids were updated with permanent ids 03883 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 03884 { 03885 if ( mAddedFeatures[i].id() != ids[i] ) 03886 { 03887 emit featureDeleted( ids[i] ); 03888 emit featureAdded( mAddedFeatures[i].id() ); 03889 } 03890 } 03891 03892 mAddedFeatures.clear(); 03893 } 03894 else 03895 { 03896 mCommitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() ); 03897 success = false; 03898 } 03899 } 03900 else 03901 { 03902 mCommitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() ); 03903 success = false; 03904 } 03905 } 03906 } 03907 03908 // 03909 // update geometries 03910 // 03911 if ( mChangedGeometries.size() > 0 ) 03912 { 03913 if (( cap & QgsVectorDataProvider::ChangeGeometries ) && mDataProvider->changeGeometryValues( mChangedGeometries ) ) 03914 { 03915 mCommitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() ); 03916 03917 emit committedGeometriesChanges( id(), mChangedGeometries ); 03918 03919 mChangedGeometries.clear(); 03920 } 03921 else 03922 { 03923 mCommitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() ); 03924 success = false; 03925 } 03926 } 03927 03928 // 03929 // delete features 03930 // 03931 if ( mDeletedFeatureIds.size() > 0 ) 03932 { 03933 if (( cap & QgsVectorDataProvider::DeleteFeatures ) && mDataProvider->deleteFeatures( mDeletedFeatureIds ) ) 03934 { 03935 mCommitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() ); 03936 for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); it++ ) 03937 { 03938 mChangedAttributeValues.remove( *it ); 03939 mChangedGeometries.remove( *it ); 03940 } 03941 03942 emit committedFeaturesRemoved( id(), mDeletedFeatureIds ); 03943 03944 mDeletedFeatureIds.clear(); 03945 } 03946 else 03947 { 03948 mCommitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() ); 03949 success = false; 03950 } 03951 } 03952 03953 if ( !success ) 03954 { 03955 if ( mDataProvider->hasErrors() ) 03956 { 03957 mCommitErrors << tr( "\n Provider errors:" ) << mDataProvider->errors(); 03958 mDataProvider->clearErrors(); 03959 } 03960 03961 QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( "\n " ) ) ); 03962 } 03963 03964 deleteCachedGeometries(); 03965 03966 if ( success ) 03967 { 03968 mEditable = false; 03969 setModified( false ); 03970 undoStack()->clear(); 03971 emit editingStopped(); 03972 } 03973 03974 updateFieldMap(); 03975 mDataProvider->updateExtents(); 03976 03977 return success; 03978 } 03979 03980 const QStringList &QgsVectorLayer::commitErrors() 03981 { 03982 return mCommitErrors; 03983 } 03984 03985 bool QgsVectorLayer::rollBack() 03986 { 03987 if ( !isEditable() ) 03988 { 03989 return false; 03990 } 03991 03992 if ( isModified() ) 03993 { 03994 while ( undoStack()->canUndo() ) 03995 { 03996 undoStack()->undo(); 03997 } 03998 03999 Q_ASSERT( mAddedAttributeIds.isEmpty() ); 04000 Q_ASSERT( mDeletedAttributeIds.isEmpty() ); 04001 Q_ASSERT( mChangedAttributeValues.isEmpty() ); 04002 Q_ASSERT( mChangedGeometries.isEmpty() ); 04003 Q_ASSERT( mAddedFeatures.isEmpty() ); 04004 04005 updateFieldMap(); 04006 } 04007 04008 deleteCachedGeometries(); 04009 04010 mEditable = false; 04011 emit editingStopped(); 04012 04013 setModified( false ); 04014 // invalidate the cache so the layer updates properly to show its original 04015 // after the rollback 04016 setCacheImage( 0 ); 04017 return true; 04018 } 04019 04020 void QgsVectorLayer::setSelectedFeatures( const QgsFeatureIds& ids ) 04021 { 04022 // TODO: check whether features with these ID exist 04023 mSelectedFeatureIds = ids; 04024 04025 // invalidate cache 04026 setCacheImage( 0 ); 04027 04028 emit selectionChanged(); 04029 } 04030 04031 int QgsVectorLayer::selectedFeatureCount() 04032 { 04033 return mSelectedFeatureIds.size(); 04034 } 04035 04036 const QgsFeatureIds& QgsVectorLayer::selectedFeaturesIds() const 04037 { 04038 return mSelectedFeatureIds; 04039 } 04040 04041 04042 QgsFeatureList QgsVectorLayer::selectedFeatures() 04043 { 04044 QgsFeatureList features; 04045 04046 foreach( QgsFeatureId fid, mSelectedFeatureIds ) 04047 { 04048 features.push_back( QgsFeature() ); 04049 featureAtId( fid, features.back(), geometryType() != QGis::NoGeometry, true ); 04050 } 04051 04052 return features; 04053 } 04054 04055 bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected ) 04056 { 04057 if ( !mDataProvider ) 04058 { 04059 return false; 04060 } 04061 04062 if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) 04063 { 04064 return false; 04065 } 04066 04067 if ( !isEditable() ) 04068 { 04069 return false; 04070 } 04071 04072 if ( makeSelected ) 04073 { 04074 mSelectedFeatureIds.clear(); 04075 } 04076 04077 for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter ) 04078 { 04079 addFeature( *iter ); 04080 04081 if ( makeSelected ) 04082 { 04083 mSelectedFeatureIds.insert( iter->id() ); 04084 } 04085 } 04086 04087 updateExtents(); 04088 04089 if ( makeSelected ) 04090 { 04091 // invalidate cache 04092 setCacheImage( 0 ); 04093 04094 emit selectionChanged(); 04095 } 04096 04097 return true; 04098 } 04099 04100 04101 bool QgsVectorLayer::copySymbologySettings( const QgsMapLayer& other ) 04102 { 04103 if ( !hasGeometryType() ) 04104 return false; 04105 04106 const QgsVectorLayer* vl = qobject_cast<const QgsVectorLayer *>( &other ); 04107 04108 // exit if both vectorlayer are the same 04109 if ( this == vl ) 04110 { 04111 return false; 04112 } 04113 04114 if ( !vl ) 04115 { 04116 return false; 04117 } 04118 delete mRenderer; 04119 04120 QgsRenderer* r = vl->mRenderer; 04121 if ( r ) 04122 { 04123 mRenderer = r->clone(); 04124 return true; 04125 } 04126 else 04127 { 04128 return false; 04129 } 04130 } 04131 04132 bool QgsVectorLayer::hasCompatibleSymbology( const QgsMapLayer& other ) const 04133 { 04134 // vector layers are symbology compatible if they have the same type, the same sequence of numerical/ non numerical fields and the same field names 04135 04136 const QgsVectorLayer* otherVectorLayer = qobject_cast<const QgsVectorLayer *>( &other ); 04137 if ( otherVectorLayer ) 04138 { 04139 if ( otherVectorLayer->type() != type() ) 04140 { 04141 return false; 04142 } 04143 04144 const QgsFieldMap& fieldsThis = mDataProvider->fields(); 04145 const QgsFieldMap& fieldsOther = otherVectorLayer ->mDataProvider->fields(); 04146 04147 if ( fieldsThis.size() != fieldsOther.size() ) 04148 { 04149 return false; 04150 } 04151 04152 // TODO: fill two sets with the numerical types for both layers 04153 04154 uint fieldsThisSize = fieldsThis.size(); 04155 04156 for ( uint i = 0; i < fieldsThisSize; ++i ) 04157 { 04158 if ( fieldsThis[i].name() != fieldsOther[i].name() ) // field names need to be the same 04159 { 04160 return false; 04161 } 04162 // TODO: compare types of the fields 04163 } 04164 return true; // layers are symbology compatible if the code reaches this point 04165 } 04166 return false; 04167 } 04168 04169 bool QgsVectorLayer::snapPoint( QgsPoint& point, double tolerance ) 04170 { 04171 if ( !hasGeometryType() ) 04172 return false; 04173 04174 QMultiMap<double, QgsSnappingResult> snapResults; 04175 int result = snapWithContext( point, tolerance, snapResults, QgsSnapper::SnapToVertex ); 04176 04177 if ( result != 0 ) 04178 { 04179 return false; 04180 } 04181 04182 if ( snapResults.size() < 1 ) 04183 { 04184 return false; 04185 } 04186 04187 QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin(); 04188 point.setX( snap_it.value().snappedVertex.x() ); 04189 point.setY( snap_it.value().snappedVertex.y() ); 04190 return true; 04191 } 04192 04193 04194 int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snappingTolerance, 04195 QMultiMap<double, QgsSnappingResult>& snappingResults, 04196 QgsSnapper::SnappingType snap_to ) 04197 { 04198 if ( !hasGeometryType() ) 04199 return 1; 04200 04201 if ( snappingTolerance <= 0 || !mDataProvider ) 04202 { 04203 return 1; 04204 } 04205 04206 QList<QgsFeature> featureList; 04207 QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance, 04208 startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance ); 04209 double sqrSnappingTolerance = snappingTolerance * snappingTolerance; 04210 04211 int n = 0; 04212 QgsFeature f; 04213 04214 if ( mCachedGeometriesRect.contains( searchRect ) ) 04215 { 04216 QgsGeometryMap::iterator it = mCachedGeometries.begin(); 04217 for ( ; it != mCachedGeometries.end() ; ++it ) 04218 { 04219 QgsGeometry* g = &( it.value() ); 04220 if ( g->boundingBox().intersects( searchRect ) ) 04221 { 04222 snapToGeometry( startPoint, it.key(), g, sqrSnappingTolerance, snappingResults, snap_to ); 04223 ++n; 04224 } 04225 } 04226 } 04227 else 04228 { 04229 // snapping outside cached area 04230 04231 select( QgsAttributeList(), searchRect, true, true ); 04232 04233 while ( nextFeature( f ) ) 04234 { 04235 snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to ); 04236 ++n; 04237 } 04238 } 04239 04240 return n == 0 ? 2 : 0; 04241 } 04242 04243 void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint, 04244 QgsFeatureId featureId, 04245 QgsGeometry* geom, 04246 double sqrSnappingTolerance, 04247 QMultiMap<double, QgsSnappingResult>& snappingResults, 04248 QgsSnapper::SnappingType snap_to ) const 04249 { 04250 if ( !geom ) 04251 { 04252 return; 04253 } 04254 04255 int atVertex, beforeVertex, afterVertex; 04256 double sqrDistVertexSnap, sqrDistSegmentSnap; 04257 QgsPoint snappedPoint; 04258 QgsSnappingResult snappingResultVertex; 04259 QgsSnappingResult snappingResultSegment; 04260 04261 if ( snap_to == QgsSnapper::SnapToVertex || snap_to == QgsSnapper::SnapToVertexAndSegment ) 04262 { 04263 snappedPoint = geom->closestVertex( startPoint, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap ); 04264 if ( sqrDistVertexSnap < sqrSnappingTolerance ) 04265 { 04266 snappingResultVertex.snappedVertex = snappedPoint; 04267 snappingResultVertex.snappedVertexNr = atVertex; 04268 snappingResultVertex.beforeVertexNr = beforeVertex; 04269 if ( beforeVertex != -1 ) // make sure the vertex is valid 04270 { 04271 snappingResultVertex.beforeVertex = geom->vertexAt( beforeVertex ); 04272 } 04273 snappingResultVertex.afterVertexNr = afterVertex; 04274 if ( afterVertex != -1 ) // make sure the vertex is valid 04275 { 04276 snappingResultVertex.afterVertex = geom->vertexAt( afterVertex ); 04277 } 04278 snappingResultVertex.snappedAtGeometry = featureId; 04279 snappingResultVertex.layer = this; 04280 snappingResults.insert( sqrt( sqrDistVertexSnap ), snappingResultVertex ); 04281 return; 04282 } 04283 } 04284 if ( snap_to == QgsSnapper::SnapToSegment || snap_to == QgsSnapper::SnapToVertexAndSegment ) // snap to segment 04285 { 04286 if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints 04287 { 04288 sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 ); 04289 04290 if ( sqrDistSegmentSnap < sqrSnappingTolerance ) 04291 { 04292 snappingResultSegment.snappedVertex = snappedPoint; 04293 snappingResultSegment.snappedVertexNr = -1; 04294 snappingResultSegment.beforeVertexNr = afterVertex - 1; 04295 snappingResultSegment.afterVertexNr = afterVertex; 04296 snappingResultSegment.snappedAtGeometry = featureId; 04297 snappingResultSegment.beforeVertex = geom->vertexAt( afterVertex - 1 ); 04298 snappingResultSegment.afterVertex = geom->vertexAt( afterVertex ); 04299 snappingResultSegment.layer = this; 04300 snappingResults.insert( sqrt( sqrDistSegmentSnap ), snappingResultSegment ); 04301 } 04302 } 04303 } 04304 } 04305 04306 int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults ) 04307 { 04308 if ( !hasGeometryType() ) 04309 return 1; 04310 04311 int returnval = 0; 04312 QgsPoint layerPoint; 04313 04314 QList<QgsSnappingResult>::const_iterator it = snapResults.constBegin(); 04315 for ( ; it != snapResults.constEnd(); ++it ) 04316 { 04317 if ( it->snappedVertexNr == -1 ) // segment snap 04318 { 04319 layerPoint = it->snappedVertex; 04320 if ( !insertVertex( layerPoint.x(), layerPoint.y(), it->snappedAtGeometry, it->afterVertexNr ) ) 04321 { 04322 returnval = 3; 04323 } 04324 } 04325 } 04326 return returnval; 04327 } 04328 04329 int QgsVectorLayer::boundingBoxFromPointList( const QList<QgsPoint>& list, double& xmin, double& ymin, double& xmax, double& ymax ) const 04330 { 04331 if ( list.size() < 1 ) 04332 { 04333 return 1; 04334 } 04335 04336 xmin = std::numeric_limits<double>::max(); 04337 xmax = -std::numeric_limits<double>::max(); 04338 ymin = std::numeric_limits<double>::max(); 04339 ymax = -std::numeric_limits<double>::max(); 04340 04341 for ( QList<QgsPoint>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) 04342 { 04343 if ( it->x() < xmin ) 04344 { 04345 xmin = it->x(); 04346 } 04347 if ( it->x() > xmax ) 04348 { 04349 xmax = it->x(); 04350 } 04351 if ( it->y() < ymin ) 04352 { 04353 ymin = it->y(); 04354 } 04355 if ( it->y() > ymax ) 04356 { 04357 ymax = it->y(); 04358 } 04359 } 04360 04361 return 0; 04362 } 04363 04364 QgsVectorLayer::VertexMarkerType QgsVectorLayer::currentVertexMarkerType() 04365 { 04366 QSettings settings; 04367 QString markerTypeString = settings.value( "/qgis/digitizing/marker_style", "Cross" ).toString(); 04368 if ( markerTypeString == "Cross" ) 04369 { 04370 return QgsVectorLayer::Cross; 04371 } 04372 else if ( markerTypeString == "SemiTransparentCircle" ) 04373 { 04374 return QgsVectorLayer::SemiTransparentCircle; 04375 } 04376 else 04377 { 04378 return QgsVectorLayer::NoMarker; 04379 } 04380 } 04381 04382 int QgsVectorLayer::currentVertexMarkerSize() 04383 { 04384 QSettings settings; 04385 return settings.value( "/qgis/digitizing/marker_size", 3 ).toInt(); 04386 } 04387 04388 void QgsVectorLayer::drawFeature( QgsRenderContext &renderContext, 04389 QgsFeature& fet, 04390 QImage * marker ) 04391 { 04392 QPainter *p = renderContext.painter(); 04393 // Only have variables, etc outside the switch() statement that are 04394 // used in all cases of the statement (otherwise they may get 04395 // executed, but never used, in a bit of code where performance is 04396 // critical). 04397 if ( ! fet.isValid() ) 04398 { 04399 return; 04400 } 04401 04402 QgsGeometry* geom = fet.geometry(); 04403 if ( !geom ) 04404 { 04405 return; 04406 } 04407 unsigned char* feature = geom->asWkb(); 04408 04409 QGis::WkbType wkbType = geom->wkbType(); 04410 04411 switch ( wkbType ) 04412 { 04413 case QGis::WKBPoint: 04414 case QGis::WKBPoint25D: 04415 { 04416 double x = *(( double * )( feature + 5 ) ); 04417 double y = *(( double * )( feature + 5 + sizeof( double ) ) ); 04418 04419 transformPoint( x, y, &renderContext.mapToPixel(), renderContext.coordinateTransform() ); 04420 if ( qAbs( x ) > QgsClipper::MAX_X || 04421 qAbs( y ) > QgsClipper::MAX_Y ) 04422 { 04423 break; 04424 } 04425 04426 //QPointF pt(x - (marker->width()/2), y - (marker->height()/2)); 04427 QPointF pt( x * renderContext.rasterScaleFactor() - ( marker->width() / 2 ), 04428 y * renderContext.rasterScaleFactor() - ( marker->height() / 2 ) ); 04429 04430 p->save(); 04431 //p->scale(markerScaleFactor,markerScaleFactor); 04432 p->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() ); 04433 p->drawImage( pt, *marker ); 04434 p->restore(); 04435 04436 break; 04437 } 04438 case QGis::WKBMultiPoint: 04439 case QGis::WKBMultiPoint25D: 04440 { 04441 unsigned char *ptr = feature + 5; 04442 unsigned int nPoints = *(( int* )ptr ); 04443 ptr += 4; 04444 04445 p->save(); 04446 //p->scale(markerScaleFactor, markerScaleFactor); 04447 p->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() ); 04448 04449 for ( register unsigned int i = 0; i < nPoints; ++i ) 04450 { 04451 ptr += 5; 04452 double x = *(( double * ) ptr ); 04453 ptr += sizeof( double ); 04454 double y = *(( double * ) ptr ); 04455 ptr += sizeof( double ); 04456 04457 if ( wkbType == QGis::WKBMultiPoint25D ) // ignore Z value 04458 ptr += sizeof( double ); 04459 04460 transformPoint( x, y, &renderContext.mapToPixel(), renderContext.coordinateTransform() ); 04461 //QPointF pt(x - (marker->width()/2), y - (marker->height()/2)); 04462 //QPointF pt(x/markerScaleFactor - (marker->width()/2), y/markerScaleFactor - (marker->height()/2)); 04463 QPointF pt( x * renderContext.rasterScaleFactor() - ( marker->width() / 2 ), 04464 y * renderContext.rasterScaleFactor() - ( marker->height() / 2 ) ); 04465 //QPointF pt( x, y ); 04466 04467 // Work around a +/- 32768 limitation on coordinates 04468 if ( qAbs( x ) <= QgsClipper::MAX_X && 04469 qAbs( y ) <= QgsClipper::MAX_Y ) 04470 p->drawImage( pt, *marker ); 04471 } 04472 p->restore(); 04473 04474 break; 04475 } 04476 case QGis::WKBLineString: 04477 case QGis::WKBLineString25D: 04478 { 04479 drawLineString( feature, renderContext ); 04480 break; 04481 } 04482 case QGis::WKBMultiLineString: 04483 case QGis::WKBMultiLineString25D: 04484 { 04485 unsigned char* ptr = feature + 5; 04486 unsigned int numLineStrings = *(( int* )ptr ); 04487 ptr = feature + 9; 04488 04489 for ( register unsigned int jdx = 0; jdx < numLineStrings; jdx++ ) 04490 { 04491 ptr = drawLineString( ptr, renderContext ); 04492 } 04493 break; 04494 } 04495 case QGis::WKBPolygon: 04496 case QGis::WKBPolygon25D: 04497 { 04498 drawPolygon( feature, renderContext ); 04499 break; 04500 } 04501 case QGis::WKBMultiPolygon: 04502 case QGis::WKBMultiPolygon25D: 04503 { 04504 unsigned char *ptr = feature + 5; 04505 unsigned int numPolygons = *(( int* )ptr ); 04506 ptr = feature + 9; 04507 for ( register unsigned int kdx = 0; kdx < numPolygons; kdx++ ) 04508 ptr = drawPolygon( ptr, renderContext ); 04509 break; 04510 } 04511 default: 04512 QgsDebugMsg( "Unknown WkbType ENCOUNTERED" ); 04513 break; 04514 } 04515 } 04516 04517 04518 04519 void QgsVectorLayer::setCoordinateSystem() 04520 { 04521 QgsDebugMsg( "----- Computing Coordinate System" ); 04522 04523 // 04524 // Get the layers project info and set up the QgsCoordinateTransform 04525 // for this layer 04526 // 04527 04528 if ( hasGeometryType() ) 04529 { 04530 // get CRS directly from provider 04531 setCrs( mDataProvider->crs() ); 04532 } 04533 else 04534 { 04535 setCrs( QgsCoordinateReferenceSystem( GEO_EPSG_CRS_AUTHID ) ); 04536 } 04537 } 04538 04539 // Convenience function to transform the given point 04540 inline void QgsVectorLayer::transformPoint( 04541 double& x, double& y, 04542 const QgsMapToPixel* mtp, 04543 const QgsCoordinateTransform* ct ) 04544 { 04545 // transform the point 04546 if ( ct ) 04547 { 04548 double z = 0; 04549 ct->transformInPlace( x, y, z ); 04550 } 04551 04552 // transform from projected coordinate system to pixel 04553 // position on map canvas 04554 mtp->transformInPlace( x, y ); 04555 } 04556 04557 inline void QgsVectorLayer::transformPoints( 04558 std::vector<double>& x, std::vector<double>& y, std::vector<double>& z, 04559 QgsRenderContext &renderContext ) 04560 { 04561 // transform the point 04562 if ( renderContext.coordinateTransform() ) 04563 renderContext.coordinateTransform()->transformInPlace( x, y, z ); 04564 04565 // transform from projected coordinate system to pixel 04566 // position on map canvas 04567 renderContext.mapToPixel().transformInPlace( x, y ); 04568 } 04569 04570 04571 const QString QgsVectorLayer::displayField() const 04572 { 04573 return mDisplayField; 04574 } 04575 04576 bool QgsVectorLayer::isEditable() const 04577 { 04578 return ( mEditable && mDataProvider ); 04579 } 04580 04581 bool QgsVectorLayer::isReadOnly() const 04582 { 04583 return mReadOnly; 04584 } 04585 04586 bool QgsVectorLayer::setReadOnly( bool readonly ) 04587 { 04588 // exit if the layer is in editing mode 04589 if ( readonly && mEditable ) 04590 return false; 04591 04592 mReadOnly = readonly; 04593 return true; 04594 } 04595 04596 bool QgsVectorLayer::isModified() const 04597 { 04598 return mModified; 04599 } 04600 04601 void QgsVectorLayer::setModified( bool modified, bool onlyGeometry ) 04602 { 04603 mModified = modified; 04604 emit layerModified( onlyGeometry ); 04605 } 04606 04607 QgsVectorLayer::EditType QgsVectorLayer::editType( int idx ) 04608 { 04609 const QgsFieldMap &fields = pendingFields(); 04610 if ( fields.contains( idx ) && mEditTypes.contains( fields[idx].name() ) ) 04611 return mEditTypes[ fields[idx].name()]; 04612 else 04613 return LineEdit; 04614 } 04615 04616 void QgsVectorLayer::setEditType( int idx, EditType type ) 04617 { 04618 const QgsFieldMap &fields = pendingFields(); 04619 if ( fields.contains( idx ) ) 04620 mEditTypes[ fields[idx].name()] = type; 04621 } 04622 04623 QString QgsVectorLayer::editForm() 04624 { 04625 return mEditForm; 04626 } 04627 04628 void QgsVectorLayer::setEditForm( QString ui ) 04629 { 04630 mEditForm = ui; 04631 } 04632 04633 void QgsVectorLayer::setAnnotationForm( const QString& ui ) 04634 { 04635 mAnnotationForm = ui; 04636 } 04637 04638 QString QgsVectorLayer::editFormInit() 04639 { 04640 return mEditFormInit; 04641 } 04642 04643 void QgsVectorLayer::setEditFormInit( QString function ) 04644 { 04645 mEditFormInit = function; 04646 } 04647 04648 QMap< QString, QVariant > &QgsVectorLayer::valueMap( int idx ) 04649 { 04650 const QgsFieldMap &fields = pendingFields(); 04651 04652 // FIXME: throw an exception!? 04653 if ( !fields.contains( idx ) ) 04654 { 04655 QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) ); 04656 } 04657 04658 if ( !mValueMaps.contains( fields[idx].name() ) ) 04659 mValueMaps[ fields[idx].name()] = QMap<QString, QVariant>(); 04660 04661 return mValueMaps[ fields[idx].name()]; 04662 } 04663 04664 QgsVectorLayer::RangeData &QgsVectorLayer::range( int idx ) 04665 { 04666 const QgsFieldMap &fields = pendingFields(); 04667 04668 // FIXME: throw an exception!? 04669 if ( fields.contains( idx ) ) 04670 { 04671 QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) ); 04672 } 04673 04674 if ( !mRanges.contains( fields[idx].name() ) ) 04675 mRanges[ fields[idx].name()] = RangeData(); 04676 04677 return mRanges[ fields[idx].name()]; 04678 } 04679 04680 void QgsVectorLayer::addOverlay( QgsVectorOverlay* overlay ) 04681 { 04682 mOverlays.push_back( overlay ); 04683 } 04684 04685 void QgsVectorLayer::removeOverlay( const QString& typeName ) 04686 { 04687 for ( int i = mOverlays.size() - 1; i >= 0; --i ) 04688 { 04689 if ( mOverlays.at( i )->typeName() == typeName ) 04690 { 04691 mOverlays.removeAt( i ); 04692 } 04693 } 04694 } 04695 04696 void QgsVectorLayer::vectorOverlays( QList<QgsVectorOverlay*>& overlayList ) 04697 { 04698 overlayList = mOverlays; 04699 } 04700 04701 QgsVectorOverlay* QgsVectorLayer::findOverlayByType( const QString& typeName ) 04702 { 04703 QList<QgsVectorOverlay*>::iterator it = mOverlays.begin(); 04704 for ( ; it != mOverlays.end(); ++it ) 04705 { 04706 if (( *it )->typeName() == typeName ) 04707 { 04708 return *it; 04709 } 04710 } 04711 return 0; //not found 04712 } 04713 04714 04715 QgsFeatureRendererV2* QgsVectorLayer::rendererV2() 04716 { 04717 return mRendererV2; 04718 } 04719 04720 void QgsVectorLayer::setRendererV2( QgsFeatureRendererV2 *r ) 04721 { 04722 if ( !hasGeometryType() ) 04723 return; 04724 04725 if ( r != mRendererV2 ) 04726 { 04727 if ( r ) 04728 setUsingRendererV2( true ); 04729 delete mRendererV2; 04730 mRendererV2 = r; 04731 } 04732 } 04733 bool QgsVectorLayer::isUsingRendererV2() 04734 { 04735 return mUsingRendererV2; 04736 } 04737 void QgsVectorLayer::setUsingRendererV2( bool usingRendererV2 ) 04738 { 04739 if ( !hasGeometryType() ) 04740 return; 04741 04742 mUsingRendererV2 = usingRendererV2; 04743 } 04744 04745 04746 void QgsVectorLayer::editGeometryChange( QgsFeatureId featureId, QgsGeometry& geometry ) 04747 { 04748 if ( mActiveCommand ) 04749 { 04750 mActiveCommand->storeGeometryChange( featureId, mChangedGeometries[ featureId ], geometry ); 04751 } 04752 mChangedGeometries[ featureId ] = geometry; 04753 emit geometryChanged( featureId, geometry ); 04754 } 04755 04756 04757 void QgsVectorLayer::editFeatureAdd( QgsFeature& feature ) 04758 { 04759 if ( mActiveCommand ) 04760 { 04761 mActiveCommand->storeFeatureAdd( feature ); 04762 } 04763 mAddedFeatures.append( feature ); 04764 } 04765 04766 void QgsVectorLayer::editFeatureDelete( QgsFeatureId featureId ) 04767 { 04768 if ( mActiveCommand ) 04769 { 04770 mActiveCommand->storeFeatureDelete( featureId ); 04771 } 04772 mDeletedFeatureIds.insert( featureId ); 04773 } 04774 04775 void QgsVectorLayer::editAttributeChange( QgsFeatureId featureId, int field, QVariant value ) 04776 { 04777 if ( mActiveCommand != NULL ) 04778 { 04779 QVariant original; 04780 bool isFirstChange = true; 04781 if ( featureId < 0 ) 04782 { 04783 // work with added feature 04784 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 04785 { 04786 if ( mAddedFeatures[i].id() == featureId && mAddedFeatures[i].attributeMap().contains( field ) ) 04787 { 04788 original = mAddedFeatures[i].attributeMap()[field]; 04789 isFirstChange = false; 04790 break; 04791 } 04792 } 04793 } 04794 else 04795 { 04796 if ( mChangedAttributeValues.contains( featureId ) && mChangedAttributeValues[featureId].contains( field ) ) 04797 { 04798 original = mChangedAttributeValues[featureId][field]; 04799 isFirstChange = false; 04800 } 04801 } 04802 mActiveCommand->storeAttributeChange( featureId, field, original, value, isFirstChange ); 04803 } 04804 04805 if ( !FID_IS_NEW( featureId ) ) 04806 { 04807 // changed attribute of existing feature 04808 if ( !mChangedAttributeValues.contains( featureId ) ) 04809 { 04810 mChangedAttributeValues.insert( featureId, QgsAttributeMap() ); 04811 } 04812 04813 mChangedAttributeValues[featureId].insert( field, value ); 04814 } 04815 else 04816 { 04817 // updated added feature 04818 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 04819 { 04820 if ( mAddedFeatures[i].id() == featureId ) 04821 { 04822 mAddedFeatures[i].changeAttribute( field, value ); 04823 break; 04824 } 04825 } 04826 } 04827 } 04828 04829 void QgsVectorLayer::beginEditCommand( QString text ) 04830 { 04831 if ( !mActiveCommand ) 04832 { 04833 mActiveCommand = new QgsUndoCommand( this, text ); 04834 } 04835 } 04836 04837 void QgsVectorLayer::endEditCommand() 04838 { 04839 if ( mActiveCommand ) 04840 { 04841 undoStack()->push( mActiveCommand ); 04842 mActiveCommand = 0; 04843 } 04844 04845 } 04846 04847 void QgsVectorLayer::destroyEditCommand() 04848 { 04849 if ( mActiveCommand ) 04850 { 04851 undoEditCommand( mActiveCommand ); 04852 delete mActiveCommand; 04853 mActiveCommand = 0; 04854 } 04855 04856 } 04857 04858 void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd ) 04859 { 04860 QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>& geometryChange = cmd->mGeometryChange; 04861 QgsFeatureIds& deletedFeatureIdChange = cmd->mDeletedFeatureIdChange; 04862 QgsFeatureList& addedFeatures = cmd->mAddedFeatures; 04863 QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>& attributeChange = cmd->mAttributeChange; 04864 QgsFieldMap& addedAttributes = cmd->mAddedAttributes; 04865 QgsFieldMap& deletedAttributes = cmd->mDeletedAttributes; 04866 04867 04868 // geometry changes 04869 QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>::iterator it = geometryChange.begin(); 04870 for ( ; it != geometryChange.end(); ++it ) 04871 { 04872 if ( !it.value().target ) 04873 { 04874 mChangedGeometries.remove( it.key() ); 04875 04876 QgsFeature f; 04877 if ( featureAtId( it.key(), f, true, false ) && f.geometry() ) 04878 { 04879 emit geometryChanged( it.key(), *f.geometry() ); 04880 } 04881 } 04882 else 04883 { 04884 mChangedGeometries[it.key()] = *it.value().target; 04885 emit geometryChanged( it.key(), *it.value().target ); 04886 } 04887 } 04888 04889 // deleted features 04890 QgsFeatureIds::iterator delIt = deletedFeatureIdChange.begin(); 04891 for ( ; delIt != deletedFeatureIdChange.end(); ++delIt ) 04892 { 04893 mDeletedFeatureIds.insert( *delIt ); 04894 emit featureDeleted( *delIt ); 04895 } 04896 04897 // added features 04898 QgsFeatureList::iterator addIt = addedFeatures.begin(); 04899 for ( ; addIt != addedFeatures.end(); ++addIt ) 04900 { 04901 mAddedFeatures.append( *addIt ); 04902 emit featureAdded( addIt->id() ); 04903 } 04904 04905 // changed attributes 04906 QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>::iterator attrFeatIt = attributeChange.begin(); 04907 for ( ; attrFeatIt != attributeChange.end(); ++attrFeatIt ) 04908 { 04909 QgsFeatureId fid = attrFeatIt.key(); 04910 // for every changed attribute in feature 04911 QMap<int, QgsUndoCommand::AttributeChangeEntry>::iterator attrChIt = attrFeatIt.value().begin(); 04912 for ( ; attrChIt != attrFeatIt.value().end(); ++attrChIt ) 04913 { 04914 if ( !FID_IS_NEW( fid ) ) 04915 { 04916 // existing feature 04917 if ( attrChIt.value().target.isNull() ) 04918 { 04919 mChangedAttributeValues[fid].remove( attrChIt.key() ); 04920 if ( mChangedAttributeValues[fid].isEmpty() ) 04921 mChangedAttributeValues.remove( fid ); 04922 } 04923 else 04924 { 04925 mChangedAttributeValues[fid][attrChIt.key()] = attrChIt.value().target; 04926 } 04927 } 04928 else 04929 { 04930 // added feature 04931 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 04932 { 04933 if ( mAddedFeatures[i].id() == fid ) 04934 { 04935 mAddedFeatures[i].changeAttribute( attrChIt.key(), attrChIt.value().target ); 04936 break; 04937 } 04938 } 04939 } 04940 emit attributeValueChanged( fid, attrChIt.key(), attrChIt.value().target ); 04941 } 04942 } 04943 04944 // added attributes 04945 QgsFieldMap::iterator attrIt = addedAttributes.begin(); 04946 for ( ; attrIt != addedAttributes.end(); ++attrIt ) 04947 { 04948 int attrIndex = attrIt.key(); 04949 mAddedAttributeIds.insert( attrIndex ); 04950 mUpdatedFields.insert( attrIndex, attrIt.value() ); 04951 emit attributeAdded( attrIndex ); 04952 } 04953 04954 // deleted attributes 04955 QgsFieldMap::iterator dAttrIt = deletedAttributes.begin(); 04956 for ( ; dAttrIt != deletedAttributes.end(); ++dAttrIt ) 04957 { 04958 int attrIndex = dAttrIt.key(); 04959 mDeletedAttributeIds.insert( attrIndex ); 04960 mUpdatedFields.remove( attrIndex ); 04961 emit attributeDeleted( attrIndex ); 04962 } 04963 setModified( true ); 04964 04965 // it's not ideal to trigger refresh from here 04966 triggerRepaint(); 04967 } 04968 04969 void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd ) 04970 { 04971 QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>& geometryChange = cmd->mGeometryChange; 04972 QgsFeatureIds& deletedFeatureIdChange = cmd->mDeletedFeatureIdChange; 04973 QgsFeatureList& addedFeatures = cmd->mAddedFeatures; 04974 QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>& attributeChange = cmd->mAttributeChange; 04975 QgsFieldMap& addedAttributes = cmd->mAddedAttributes; 04976 QgsFieldMap& deletedAttributes = cmd->mDeletedAttributes; 04977 04978 // deleted attributes 04979 QgsFieldMap::iterator dAttrIt = deletedAttributes.begin(); 04980 for ( ; dAttrIt != deletedAttributes.end(); ++dAttrIt ) 04981 { 04982 int attrIndex = dAttrIt.key(); 04983 mDeletedAttributeIds.remove( attrIndex ); 04984 mUpdatedFields.insert( attrIndex, dAttrIt.value() ); 04985 emit attributeAdded( attrIndex ); 04986 } 04987 04988 // added attributes 04989 QgsFieldMap::iterator attrIt = addedAttributes.begin(); 04990 for ( ; attrIt != addedAttributes.end(); ++attrIt ) 04991 { 04992 int attrIndex = attrIt.key(); 04993 mAddedAttributeIds.remove( attrIndex ); 04994 mUpdatedFields.remove( attrIndex ); 04995 emit attributeDeleted( attrIndex ); 04996 } 04997 04998 // geometry changes 04999 QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>::iterator it = geometryChange.begin(); 05000 for ( ; it != geometryChange.end(); ++it ) 05001 { 05002 if ( !it.value().original ) 05003 { 05004 mChangedGeometries.remove( it.key() ); 05005 05006 QgsFeature f; 05007 if ( featureAtId( it.key(), f, true, false ) && f.geometry() ) 05008 { 05009 emit geometryChanged( it.key(), *f.geometry() ); 05010 } 05011 } 05012 else 05013 { 05014 mChangedGeometries[it.key()] = *( it.value().original ); 05015 emit geometryChanged( it.key(), *it.value().original ); 05016 } 05017 } 05018 05019 // deleted features 05020 QgsFeatureIds::iterator delIt = deletedFeatureIdChange.begin(); 05021 for ( ; delIt != deletedFeatureIdChange.end(); ++delIt ) 05022 { 05023 mDeletedFeatureIds.remove( *delIt ); 05024 emit featureAdded( *delIt ); 05025 } 05026 05027 // added features 05028 QgsFeatureList::iterator addIt = addedFeatures.begin(); 05029 for ( ; addIt != addedFeatures.end(); ++addIt ) 05030 { 05031 QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); 05032 for ( ; addedIt != mAddedFeatures.end(); ++addedIt ) 05033 { 05034 if ( addedIt->id() == addIt->id() ) 05035 { 05036 mAddedFeatures.erase( addedIt ); 05037 emit featureDeleted( addIt->id() ); 05038 break; // feature was found so move to next one 05039 } 05040 } 05041 } 05042 05043 // updated attributes 05044 QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>::iterator attrFeatIt = attributeChange.begin(); 05045 for ( ; attrFeatIt != attributeChange.end(); ++attrFeatIt ) 05046 { 05047 QgsFeatureId fid = attrFeatIt.key(); 05048 QMap<int, QgsUndoCommand::AttributeChangeEntry>::iterator attrChIt = attrFeatIt.value().begin(); 05049 for ( ; attrChIt != attrFeatIt.value().end(); ++attrChIt ) 05050 { 05051 if ( !FID_IS_NEW( fid ) ) 05052 { 05053 if ( attrChIt.value().isFirstChange ) 05054 { 05055 mChangedAttributeValues[fid].remove( attrChIt.key() ); 05056 if ( mChangedAttributeValues[fid].isEmpty() ) 05057 mChangedAttributeValues.remove( fid ); 05058 } 05059 else 05060 { 05061 mChangedAttributeValues[fid][attrChIt.key()] = attrChIt.value().original; 05062 } 05063 } 05064 else 05065 { 05066 // added feature TODO: 05067 for ( int i = 0; i < mAddedFeatures.size(); i++ ) 05068 { 05069 if ( mAddedFeatures[i].id() == fid ) 05070 { 05071 mAddedFeatures[i].changeAttribute( attrChIt.key(), attrChIt.value().original ); 05072 break; 05073 } 05074 } 05075 } 05076 QVariant original = attrChIt.value().original; 05077 if ( attrChIt.value().isFirstChange ) 05078 { 05079 QgsFeature tmp; 05080 mDataProvider->featureAtId( fid, tmp, false, QgsAttributeList() << attrChIt.key() ); 05081 original = tmp.attributeMap()[ attrChIt.key()]; 05082 } 05083 emit attributeValueChanged( fid, attrChIt.key(), original ); 05084 } 05085 } 05086 setModified( true ); 05087 05088 // it's not ideal to trigger refresh from here 05089 triggerRepaint(); 05090 } 05091 05092 void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked ) 05093 { 05094 const QgsFieldMap &fields = pendingFields(); 05095 if ( fields.contains( idx ) ) 05096 mCheckedStates[ fields[idx].name()] = QPair<QString, QString>( checked, unchecked ); 05097 } 05098 05099 QPair<QString, QString> QgsVectorLayer::checkedState( int idx ) 05100 { 05101 const QgsFieldMap &fields = pendingFields(); 05102 if ( fields.contains( idx ) && mCheckedStates.contains( fields[idx].name() ) ) 05103 return mCheckedStates[ fields[idx].name()]; 05104 else 05105 return QPair<QString, QString>( "1", "0" ); 05106 } 05107 05108 int QgsVectorLayer::fieldNameIndex( const QString& fieldName ) const 05109 { 05110 const QgsFieldMap &theFields = pendingFields(); 05111 05112 for ( QgsFieldMap::const_iterator it = theFields.constBegin(); it != theFields.constEnd(); ++it ) 05113 { 05114 if ( QString::compare( it->name(), fieldName, Qt::CaseInsensitive ) == 0 ) 05115 { 05116 return it.key(); 05117 } 05118 } 05119 return -1; 05120 } 05121 05122 void QgsVectorLayer::addJoin( QgsVectorJoinInfo joinInfo ) 05123 { 05124 mJoinBuffer->addJoin( joinInfo ); 05125 updateFieldMap(); 05126 } 05127 05128 void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId ) 05129 { 05130 removeJoin( theLayerId ); 05131 } 05132 05133 void QgsVectorLayer::removeJoin( const QString& joinLayerId ) 05134 { 05135 mJoinBuffer->removeJoin( joinLayerId ); 05136 updateFieldMap(); 05137 } 05138 05139 const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const 05140 { 05141 return mJoinBuffer->vectorJoins(); 05142 } 05143 05144 void QgsVectorLayer::updateFieldMap() 05145 { 05146 //first backup mAddedAttributes 05147 QgsFieldMap bkAddedAttributes; 05148 QgsAttributeIds::const_iterator attIdIt = mAddedAttributeIds.constBegin(); 05149 for ( ; attIdIt != mAddedAttributeIds.constEnd(); ++attIdIt ) 05150 { 05151 bkAddedAttributes.insert( *attIdIt, mUpdatedFields.value( *attIdIt ) ); 05152 } 05153 05154 mUpdatedFields = QgsFieldMap(); 05155 if ( mDataProvider ) 05156 { 05157 mUpdatedFields = mDataProvider->fields(); 05158 } 05159 05160 int currentMaxIndex = 0; //maximum index of current layer 05161 if ( !QgsVectorLayerJoinBuffer::maximumIndex( mUpdatedFields, currentMaxIndex ) ) 05162 { 05163 return; 05164 } 05165 05166 mMaxUpdatedIndex = currentMaxIndex; 05167 05168 //joined fields 05169 if ( mJoinBuffer->containsJoins() ) 05170 { 05171 mJoinBuffer->updateFieldMap( mUpdatedFields, mMaxUpdatedIndex ); 05172 } 05173 05174 //insert added attributes after provider fields and joined fields 05175 mAddedAttributeIds.clear(); 05176 QgsFieldMap::const_iterator fieldIt = bkAddedAttributes.constBegin(); 05177 for ( ; fieldIt != bkAddedAttributes.constEnd(); ++fieldIt ) 05178 { 05179 ++mMaxUpdatedIndex; 05180 mUpdatedFields.insert( mMaxUpdatedIndex, fieldIt.value() ); 05181 mAddedAttributeIds.insert( mMaxUpdatedIndex ); 05182 05183 //go through the changed attributes map and adapt indices of added attributes 05184 for ( int i = 0; i < mChangedAttributeValues.size(); ++i ) 05185 { 05186 updateAttributeMapIndex( mChangedAttributeValues[i], fieldIt.key(), mMaxUpdatedIndex ); 05187 } 05188 05189 //go through added features and adapt attribute maps 05190 QgsFeatureList::iterator featureIt = mAddedFeatures.begin(); 05191 for ( ; featureIt != mAddedFeatures.end(); ++featureIt ) 05192 { 05193 QgsAttributeMap attMap = featureIt->attributeMap(); 05194 updateAttributeMapIndex( attMap, fieldIt.key(), mMaxUpdatedIndex ); 05195 featureIt->setAttributeMap( attMap ); 05196 } 05197 } 05198 05199 //remove deleted attributes 05200 QgsAttributeIds::const_iterator deletedIt = mDeletedAttributeIds.constBegin(); 05201 for ( ; deletedIt != mDeletedAttributeIds.constEnd(); ++deletedIt ) 05202 { 05203 mUpdatedFields.remove( *deletedIt ); 05204 } 05205 } 05206 05207 void QgsVectorLayer::createJoinCaches() 05208 { 05209 if ( mJoinBuffer->containsJoins() ) 05210 { 05211 mJoinBuffer->createJoinCaches(); 05212 } 05213 } 05214 05215 void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) 05216 { 05217 uniqueValues.clear(); 05218 if ( !mDataProvider ) 05219 { 05220 return; 05221 } 05222 05223 int maxProviderIndex; 05224 QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex ); 05225 05226 if ( index <= maxProviderIndex && !mEditable ) //a provider field 05227 { 05228 return mDataProvider->uniqueValues( index, uniqueValues, limit ); 05229 } 05230 else // a joined field? 05231 { 05232 if ( mJoinBuffer ) 05233 { 05234 int indexOffset; //offset between layer index and joined provider index 05235 const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset ); 05236 if ( join ) 05237 { 05238 QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) ); 05239 if ( vl && vl->dataProvider() ) 05240 { 05241 return vl->dataProvider()->uniqueValues( index - indexOffset, uniqueValues, limit ); 05242 } 05243 } 05244 } 05245 } 05246 05247 05248 //the layer is editable, but in certain cases it can still be avoided going through all features 05249 if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 ) 05250 { 05251 return mDataProvider->uniqueValues( index, uniqueValues, limit ); 05252 } 05253 05254 //we need to go through each feature 05255 QgsAttributeList attList; 05256 attList << index; 05257 05258 select( attList, QgsRectangle(), false, false ); 05259 05260 QgsFeature f; 05261 QVariant currentValue; 05262 QHash<QString, QVariant> val; 05263 while ( nextFeature( f ) ) 05264 { 05265 currentValue = f.attributeMap()[index]; 05266 val.insert( currentValue.toString(), currentValue ); 05267 if ( limit >= 0 && val.size() >= limit ) 05268 { 05269 break; 05270 } 05271 } 05272 05273 uniqueValues = val.values(); 05274 } 05275 05276 QVariant QgsVectorLayer::minimumValue( int index ) 05277 { 05278 if ( !mDataProvider ) 05279 { 05280 return QVariant(); 05281 } 05282 05283 int maxProviderIndex; 05284 QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex ); 05285 05286 if ( index <= maxProviderIndex && !mEditable ) //a provider field 05287 { 05288 return mDataProvider->minimumValue( index ); 05289 } 05290 else // a joined field? 05291 { 05292 int indexOffset; //offset between layer index and joined provider index 05293 const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset ); 05294 if ( join ) 05295 { 05296 QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) ); 05297 if ( vl ) 05298 { 05299 return vl->minimumValue( index ); 05300 } 05301 } 05302 } 05303 05304 //the layer is editable, but in certain cases it can still be avoided going through all features 05305 if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 ) 05306 { 05307 return mDataProvider->minimumValue( index ); 05308 } 05309 05310 //we need to go through each feature 05311 QgsAttributeList attList; 05312 attList << index; 05313 05314 select( attList, QgsRectangle(), false, false ); 05315 05316 QgsFeature f; 05317 double minimumValue = std::numeric_limits<double>::max(); 05318 double currentValue = 0; 05319 while ( nextFeature( f ) ) 05320 { 05321 currentValue = f.attributeMap()[index].toDouble(); 05322 if ( currentValue < minimumValue ) 05323 { 05324 minimumValue = currentValue; 05325 } 05326 } 05327 return QVariant( minimumValue ); 05328 } 05329 05330 QVariant QgsVectorLayer::maximumValue( int index ) 05331 { 05332 if ( !mDataProvider ) 05333 { 05334 return QVariant(); 05335 } 05336 05337 int maxProviderIndex; 05338 QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex ); 05339 05340 if ( index <= maxProviderIndex && !mEditable ) //a provider field 05341 { 05342 return mDataProvider->maximumValue( index ); 05343 } 05344 else // a joined field? 05345 { 05346 int indexOffset; //offset between layer index and joined provider index 05347 const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset ); 05348 if ( join ) 05349 { 05350 QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) ); 05351 if ( vl ) 05352 { 05353 return vl->maximumValue( index ); 05354 } 05355 } 05356 } 05357 05358 //the layer is editable, but in certain cases it can still be avoided going through all features 05359 if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 ) 05360 { 05361 return mDataProvider->maximumValue( index ); 05362 } 05363 05364 //we need to go through each feature 05365 QgsAttributeList attList; 05366 attList << index; 05367 05368 select( attList, QgsRectangle(), false, false ); 05369 05370 QgsFeature f; 05371 double maximumValue = -std::numeric_limits<double>::max(); 05372 double currentValue = 0; 05373 while ( nextFeature( f ) ) 05374 { 05375 currentValue = f.attributeMap()[index].toDouble(); 05376 if ( currentValue > maximumValue ) 05377 { 05378 maximumValue = currentValue; 05379 } 05380 } 05381 return QVariant( maximumValue ); 05382 } 05383 05384 void QgsVectorLayer::stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer ) 05385 { 05386 mRendererV2->stopRender( rendererContext ); 05387 if ( selRenderer ) 05388 { 05389 selRenderer->stopRender( rendererContext ); 05390 delete selRenderer; 05391 } 05392 } 05393 05394 void QgsVectorLayer::updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex, int newIndex ) const 05395 { 05396 QgsAttributeMap::const_iterator it = map.find( oldIndex ); 05397 if ( it == map.constEnd() ) 05398 { 05399 return; 05400 } 05401 05402 map.insert( newIndex, it.value() ); 05403 map.remove( oldIndex ); 05404 } 05405 05406 void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling ) 05407 { 05408 if ( !rendererContext.labelingEngine() ) 05409 return; 05410 05411 QSet<int> attrIndex; 05412 if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) ) 05413 { 05414 QSet<int>::const_iterator attIt = attrIndex.constBegin(); 05415 for ( ; attIt != attrIndex.constEnd(); ++attIt ) 05416 { 05417 if ( !attributes.contains( *attIt ) ) 05418 { 05419 attributes << *attIt; 05420 } 05421 } 05422 labeling = true; 05423 } 05424 05425 //register diagram layers 05426 if ( mDiagramRenderer && mDiagramLayerSettings ) 05427 { 05428 mDiagramLayerSettings->renderer = mDiagramRenderer; 05429 rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings ); 05430 //add attributes needed by the diagram renderer 05431 QList<int> att = mDiagramRenderer->diagramAttributes(); 05432 QList<int>::const_iterator attIt = att.constBegin(); 05433 for ( ; attIt != att.constEnd(); ++attIt ) 05434 { 05435 if ( !attributes.contains( *attIt ) ) 05436 { 05437 attributes << *attIt; 05438 } 05439 } 05440 //and the ones needed for data defined diagram positions 05441 if ( mDiagramLayerSettings->xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->xPosColumn ) ) 05442 { 05443 attributes << mDiagramLayerSettings->xPosColumn; 05444 } 05445 if ( mDiagramLayerSettings->yPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->yPosColumn ) ) 05446 { 05447 attributes << mDiagramLayerSettings->yPosColumn; 05448 } 05449 } 05450 } 05451 05452 void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s ) 05453 { 05454 if ( !mDiagramLayerSettings ) 05455 mDiagramLayerSettings = new QgsDiagramLayerSettings(); 05456 *mDiagramLayerSettings = s; 05457 } 05458 05459 QString QgsVectorLayer::metadata() 05460 { 05461 QString myMetadata = "<html><body>"; 05462 myMetadata += "<table width=\"100%\">"; 05463 05464 //------------- 05465 05466 myMetadata += "<tr class=\"glossy\"><td>"; 05467 myMetadata += tr( "General:" ); 05468 myMetadata += "</td></tr>"; 05469 05470 // data comment 05471 if ( !( dataComment().isEmpty() ) ) 05472 { 05473 myMetadata += "<tr><td>"; 05474 myMetadata += tr( "Layer comment: %1" ).arg( dataComment() ); 05475 myMetadata += "</td></tr>"; 05476 } 05477 05478 //storage type 05479 myMetadata += "<tr><td>"; 05480 myMetadata += tr( "Storage type of this layer: %1" ).arg( storageType() ); 05481 myMetadata += "</td></tr>"; 05482 05483 // data source 05484 myMetadata += "<tr><td>"; 05485 myMetadata += tr( "Source for this layer: %1" ).arg( publicSource() ); 05486 myMetadata += "</td></tr>"; 05487 05488 //geom type 05489 05490 QGis::GeometryType type = geometryType(); 05491 05492 if ( type < 0 || type > QGis::NoGeometry ) 05493 { 05494 QgsDebugMsg( "Invalid vector type" ); 05495 } 05496 else 05497 { 05498 QString typeString( QGis::qgisVectorGeometryType[geometryType()] ); 05499 05500 myMetadata += "<tr><td>"; 05501 myMetadata += tr( "Geometry type of the features in this layer: %1" ).arg( typeString ); 05502 myMetadata += "</td></tr>"; 05503 } 05504 05505 05506 //feature count 05507 myMetadata += "<tr><td>"; 05508 myMetadata += tr( "The number of features in this layer: %1" ).arg( featureCount() ); 05509 myMetadata += "</td></tr>"; 05510 //capabilities 05511 myMetadata += "<tr><td>"; 05512 myMetadata += tr( "Editing capabilities of this layer: %1" ).arg( capabilitiesString() ); 05513 myMetadata += "</td></tr>"; 05514 05515 //------------- 05516 05517 QgsRectangle myExtent = extent(); 05518 myMetadata += "<tr class=\"glossy\"><td>"; 05519 myMetadata += tr( "Extents:" ); 05520 myMetadata += "</td></tr>"; 05521 //extents in layer cs TODO...maybe make a little nested table to improve layout... 05522 myMetadata += "<tr><td>" + tr( "In layer spatial reference system units : " ); 05523 05524 // Try to be a bit clever over what number format we use for the 05525 // extents. Some people don't like it using scientific notation when the 05526 // numbers get large, but for small numbers this is the more practical 05527 // option (so we can't force the format to 'f' for all values). 05528 // The scheme: 05529 // - for all numbers with more than 5 digits, force non-scientific notation 05530 // and 2 digits after the decimal point. 05531 // - for all smaller numbers let the OS decide which format to use (it will 05532 // generally use non-scientific unless the number gets much less than 1). 05533 05534 if ( !myExtent.isEmpty() ) 05535 { 05536 QString xMin, yMin, xMax, yMax; 05537 double changeoverValue = 99999; // The 'largest' 5 digit number 05538 if ( qAbs( myExtent.xMinimum() ) > changeoverValue ) 05539 { 05540 xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 ); 05541 } 05542 else 05543 { 05544 xMin = QString( "%1" ).arg( myExtent.xMinimum() ); 05545 } 05546 if ( qAbs( myExtent.yMinimum() ) > changeoverValue ) 05547 { 05548 yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 ); 05549 } 05550 else 05551 { 05552 yMin = QString( "%1" ).arg( myExtent.yMinimum() ); 05553 } 05554 if ( qAbs( myExtent.xMaximum() ) > changeoverValue ) 05555 { 05556 xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 ); 05557 } 05558 else 05559 { 05560 xMax = QString( "%1" ).arg( myExtent.xMaximum() ); 05561 } 05562 if ( qAbs( myExtent.yMaximum() ) > changeoverValue ) 05563 { 05564 yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 ); 05565 } 05566 else 05567 { 05568 yMax = QString( "%1" ).arg( myExtent.yMaximum() ); 05569 } 05570 05571 myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" ) 05572 .arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax ); 05573 } 05574 else 05575 { 05576 myMetadata += tr( "unknown extent" ); 05577 } 05578 05579 myMetadata += "</td></tr>"; 05580 05581 //extents in project cs 05582 05583 try 05584 { 05585 #if 0 05586 // TODO: currently disabled, will revisit later [MD] 05587 QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() ); 05588 myMetadata += "<tr><td>"; 05589 myMetadata += tr( "In project spatial reference system units : " ) 05590 + tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" ) 05591 .arg( myProjectedExtent.xMinimum() ) 05592 .arg( myProjectedExtent.yMinimum() ) 05593 .arg( myProjectedExtent.xMaximum() ) 05594 .arg( myProjectedExtent.yMaximum() ); 05595 myMetadata += "</td></tr>"; 05596 #endif 05597 05598 // 05599 // Display layer spatial ref system 05600 // 05601 myMetadata += "<tr class=\"glossy\"><td>"; 05602 myMetadata += tr( "Layer Spatial Reference System:" ); 05603 myMetadata += "</td></tr>"; 05604 myMetadata += "<tr><td>"; 05605 myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" ); 05606 myMetadata += "</td></tr>"; 05607 05608 // 05609 // Display project (output) spatial ref system 05610 // 05611 #if 0 05612 // TODO: disabled for now, will revisit later [MD] 05613 myMetadata += "<tr><td bgcolor=\"gray\">"; 05614 myMetadata += tr( "Project (Output) Spatial Reference System:" ); 05615 myMetadata += "</td></tr>"; 05616 myMetadata += "<tr><td>"; 05617 myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" ); 05618 myMetadata += "</td></tr>"; 05619 #endif 05620 } 05621 catch ( QgsCsException &cse ) 05622 { 05623 Q_UNUSED( cse ); 05624 QgsDebugMsg( cse.what() ); 05625 05626 myMetadata += "<tr><td>"; 05627 myMetadata += tr( "In project spatial reference system units : " ) 05628 + tr( "(Invalid transformation of layer extents)" ); 05629 myMetadata += "</td></tr>"; 05630 05631 } 05632 05633 #if 0 05634 // 05635 // Add the info about each field in the attribute table 05636 // 05637 myMetadata += "<tr class=\"glossy\"><td>"; 05638 myMetadata += tr( "Attribute field info:" ); 05639 myMetadata += "</td></tr>"; 05640 myMetadata += "<tr><td>"; 05641 05642 // Start a nested table in this trow 05643 myMetadata += "<table width=\"100%\">"; 05644 myMetadata += "<tr><th>"; 05645 myMetadata += tr( "Field" ); 05646 myMetadata += "</th>"; 05647 myMetadata += "<th>"; 05648 myMetadata += tr( "Type" ); 05649 myMetadata += "</th>"; 05650 myMetadata += "<th>"; 05651 myMetadata += tr( "Length" ); 05652 myMetadata += "</th>"; 05653 myMetadata += "<th>"; 05654 myMetadata += tr( "Precision" ); 05655 myMetadata += "</th>"; 05656 myMetadata += "<th>"; 05657 myMetadata += tr( "Comment" ); 05658 myMetadata += "</th>"; 05659 05660 //get info for each field by looping through them 05661 const QgsFieldMap& myFields = pendingFields(); 05662 for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it ) 05663 { 05664 const QgsField& myField = *it; 05665 05666 myMetadata += "<tr><td>"; 05667 myMetadata += myField.name(); 05668 myMetadata += "</td>"; 05669 myMetadata += "<td>"; 05670 myMetadata += myField.typeName(); 05671 myMetadata += "</td>"; 05672 myMetadata += "<td>"; 05673 myMetadata += QString( "%1" ).arg( myField.length() ); 05674 myMetadata += "</td>"; 05675 myMetadata += "<td>"; 05676 myMetadata += QString( "%1" ).arg( myField.precision() ); 05677 myMetadata += "</td>"; 05678 myMetadata += "<td>"; 05679 myMetadata += QString( "%1" ).arg( myField.comment() ); 05680 myMetadata += "</td></tr>"; 05681 } 05682 05683 //close field list 05684 myMetadata += "</table>"; //end of nested table 05685 #endif 05686 05687 myMetadata += "</td></tr>"; //end of stats container table row 05688 // 05689 // Close the table 05690 // 05691 05692 myMetadata += "</table>"; 05693 05694 myMetadata += "</body></html>"; 05695 return myMetadata; 05696 } 05697 05698 QgsVectorLayer::ValueRelationData &QgsVectorLayer::valueRelation( int idx ) 05699 { 05700 const QgsFieldMap &fields = pendingFields(); 05701 05702 // FIXME: throw an exception!? 05703 if ( fields.contains( idx ) ) 05704 { 05705 QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) ); 05706 } 05707 05708 if ( !mValueRelations.contains( fields[idx].name() ) ) 05709 { 05710 mValueRelations[ fields[idx].name()] = ValueRelationData(); 05711 } 05712 05713 return mValueRelations[ fields[idx].name()]; 05714 }