Example #1
0
void QgsMapToolRotateLabel::canvasReleaseEvent( QgsMapMouseEvent* e )
{
  Q_UNUSED( e );

  if ( !mLabelRubberBand ) //no rubber band created (most likely because the current label cannot be rotated )
  {
    return;
  }

  deleteRubberBands();
  delete mRotationItem;
  mRotationItem = nullptr;
  delete mRotationPreviewBox;
  mRotationPreviewBox = nullptr;

  QgsVectorLayer* vlayer = mCurrentLabel.layer;
  if ( !vlayer )
  {
    return;
  }

  int rotationCol;
  if ( !labelIsRotatable( vlayer, mCurrentLabel.settings, rotationCol ) )
  {
    return;
  }

  double rotation = mCtrlPressed ? roundTo15Degrees( mCurrentRotation ) : mCurrentRotation;
  if ( rotation == mStartRotation ) //mouse button pressed / released, but no rotation
  {
    return;
  }

  vlayer->beginEditCommand( tr( "Rotated label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) );
  vlayer->changeAttributeValue( mCurrentLabel.pos.featureId, rotationCol, rotation );
  vlayer->endEditCommand();
  vlayer->triggerRepaint();
}
void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
  QgsVectorLayer *vl = layer( model );
  if ( vl == NULL )
    return;

  int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
  QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
  QVariant oldValue = model->data( index, Qt::EditRole );

  QVariant newValue;
  QgsEditorWidgetWrapper* eww = QgsEditorWidgetWrapper::fromWidget( editor );
  if ( !eww )
    return;

  newValue = eww->value();

  if (( oldValue != newValue && newValue.isValid() ) || oldValue.isNull() != newValue.isNull() )
  {
    vl->beginEditCommand( tr( "Attribute changed" ) );
    vl->changeAttributeValue( fid, fieldIdx, newValue, oldValue );
    vl->endEditCommand();
  }
}
void QgsMapToolMoveFeature::canvasReleaseEvent( QgsMapMouseEvent* e )
{
  //QgsDebugMsg("entering.");
  if ( !mRubberBand )
  {
    return;
  }

  QgsVectorLayer* vlayer = currentVectorLayer();
  if ( !vlayer )
  {
    return;
  }

  QgsPoint startPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, mStartPointMapCoords );
  QgsPoint stopPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, e->pos() );

  double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
  double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
  vlayer->beginEditCommand( tr( "Feature moved" ) );
  Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
  {
    vlayer->translateFeature( id, dx, dy );
  }
Example #4
0
void QgsMapToolMoveLabel::canvasReleaseEvent( QgsMapMouseEvent* e )
{
  if ( !mLabelRubberBand )
  {
    return;
  }

  deleteRubberBands();

  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
  if ( !layer )
  {
    return;
  }

  QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer );
  if ( !vlayer )
  {
    return;
  }

  if ( !vlayer->isEditable() )
  {
    return;
  }

  QgsPoint releaseCoords = toMapCoordinates( e->pos() );
  double xdiff = releaseCoords.x() - mStartPointMapCoords.x();
  double ydiff = releaseCoords.y() - mStartPointMapCoords.y();

  int xCol, yCol;
  double xPosOrig, yPosOrig;
  bool xSuccess, ySuccess;

  if ( !dataDefinedPosition( vlayer, mCurrentLabelPos.featureId, xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) )
  {
    return;
  }

  double xPosNew, yPosNew;

  if ( !xSuccess || !ySuccess )
  {
    xPosNew = releaseCoords.x() - mClickOffsetX;
    yPosNew = releaseCoords.y() - mClickOffsetY;
  }
  else
  {
    //transform to map crs first, because xdiff,ydiff are in map coordinates
    const QgsMapSettings& ms = mCanvas->mapSettings();
    if ( ms.hasCrsTransformEnabled() )
    {
      QgsPoint transformedPoint = ms.layerToMapCoordinates( vlayer, QgsPoint( xPosOrig, yPosOrig ) );
      xPosOrig = transformedPoint.x();
      yPosOrig = transformedPoint.y();
    }
    xPosNew = xPosOrig + xdiff;
    yPosNew = yPosOrig + ydiff;
  }

  //transform back to layer crs
  if ( mCanvas )
  {
    const QgsMapSettings& s = mCanvas->mapSettings();
    if ( s.hasCrsTransformEnabled() )
    {
      QgsPoint transformedPoint = s.mapToLayerCoordinates( vlayer, QgsPoint( xPosNew, yPosNew ) );
      xPosNew = transformedPoint.x();
      yPosNew = transformedPoint.y();
    }
  }

  vlayer->beginEditCommand( tr( "Moved label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) );
  vlayer->changeAttributeValue( mCurrentLabelPos.featureId, xCol, xPosNew );
  vlayer->changeAttributeValue( mCurrentLabelPos.featureId, yCol, yPosNew );

  // set rotation to that of label, if data-defined and no rotation set yet
  // honor whether to preserve preexisting data on pin
  // must come after setting x and y positions
  int rCol;
  if ( !mCurrentLabelPos.isDiagram
       && !mCurrentLabelPos.isPinned
       && !preserveRotation()
       && layerIsRotatable( vlayer, rCol ) )
  {
    double defRot;
    bool rSuccess;
    if ( dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess ) )
    {
      double labelRot = mCurrentLabelPos.rotation * 180 / M_PI;
      vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rCol, labelRot );
    }
  }
  vlayer->endEditCommand();

  if ( mCanvas )
    mCanvas->refresh();
}
Example #5
0
void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->mapPoint() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    if ( !isCapturing() )
      return;

    deleteTempRubberBand();

    closePolygon();

    vlayer->beginEditCommand( tr( "Ring added and filled" ) );
    QList< QgsPoint > pointList = points();

    QgsFeatureId modifiedFid;
    int addRingReturnCode = vlayer->addRing( pointList, &modifiedFid );
    if ( addRingReturnCode != 0 )
    {
      QString errorMessage;
      //todo: open message box to communicate errors
      if ( addRingReturnCode == 1 )
      {
        errorMessage = tr( "a problem with geometry type occured" );
      }
      else if ( addRingReturnCode == 2 )
      {
        errorMessage = tr( "the inserted Ring is not closed" );
      }
      else if ( addRingReturnCode == 3 )
      {
        errorMessage = tr( "the inserted Ring is not a valid geometry" );
      }
      else if ( addRingReturnCode == 4 )
      {
        errorMessage = tr( "the inserted Ring crosses existing rings" );
      }
      else if ( addRingReturnCode == 5 )
      {
        errorMessage = tr( "the inserted Ring is not contained in a feature" );
      }
      else
      {
        errorMessage = tr( "an unknown error occured" );
      }
      emit messageEmitted( tr( "could not add ring since %1." ).arg( errorMessage ), QgsMessageBar::CRITICAL );
      vlayer->destroyEditCommand();
    }
    else
    {
      // find parent feature and get it attributes
      double xMin, xMax, yMin, yMax;
      QgsRectangle bBox;

      xMin = std::numeric_limits<double>::max();
      xMax = -std::numeric_limits<double>::max();
      yMin = std::numeric_limits<double>::max();
      yMax = -std::numeric_limits<double>::max();

      Q_FOREACH ( const QgsPoint& point, pointList )
      {
        xMin = qMin( xMin, point.x() );
        xMax = qMax( xMax, point.x() );
        yMin = qMin( yMin, point.y() );
        yMax = qMax( yMax, point.y() );
      }

      bBox.setXMinimum( xMin );
      bBox.setYMinimum( yMin );
      bBox.setXMaximum( xMax );
      bBox.setYMaximum( yMax );

      QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterFid( modifiedFid ) );

      QgsFeature f;
      bool res = false;
      if ( fit.nextFeature( f ) )
      {
        //create QgsFeature with wkb representation
        QgsFeature* ft = new QgsFeature( vlayer->fields(), 0 );

        ft->setGeometry( QgsGeometry::fromPolygon( QgsPolygon() << pointList.toVector() ) );
        ft->setAttributes( f.attributes() );

        if ( QApplication::keyboardModifiers() == Qt::ControlModifier )
        {
          res = vlayer->addFeature( *ft );
        }
        else
        {
          QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true );
          dialog->setIsAddDialog( true );
          res = dialog->exec(); // will also add the feature
        }

        if ( res )
        {
          vlayer->endEditCommand();
        }
        else
        {
          delete ft;
          vlayer->destroyEditCommand();
        }
        res = false;
      }
    }
    stopCapturing();
  }
void OptMapToolSplitLink::canvasReleaseEvent( QMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    QMessageBox::information( 0, tr( "Not a vector layer" ),
                              tr( "The current layer is not a vector layer" ) );
    return;
  }

  if ( !vlayer->isEditable() )
  {
    QMessageBox::information( 0, tr( "Layer not editable" ),
                              tr( "Cannot edit the vector layer. Use 'Toggle Editing' to make it editable." )
                            );
    return;
  }

  //add point to list and to rubber band
  int error = addVertex( e->pos() );
  if ( error == 1 )
  {
    //current layer is not a vector layer
    return;
  }
  else if ( error == 2 )
  {
    //problem with coordinate transformation
    QMessageBox::information( 0, tr( "Coordinate transform error" ),
                              tr( "Cannot transform the point to the layers coordinate system" ) );
    return;
  }

  if ( e->button() == Qt::LeftButton )
  {
    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    //bring up dialog if a split was not possible (polygon) or only done once (line)
    int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
    vlayer->beginEditCommand( tr( "Features split" ) );
    int returnCode = vlayer->splitFeatures( points(), topologicalEditing );
    vlayer->endEditCommand();
    if ( returnCode == 4 )
    {
      QMessageBox::warning( 0, tr( "No feature split done" ), tr( "If there are selected features, the split tool only applies to the selected ones. If you like to split all features under the split line, clear the selection" ) );
    }
    else if ( returnCode == 3 )
    {
      QMessageBox::warning( 0, tr( "No feature split done" ), tr( "Cut edges detected. Make sure the line splits features into multiple parts." ) );
    }
    else if ( returnCode == 7 )
    {
      QMessageBox::warning( 0, tr( "No feature split done" ), tr( "The geometry is invalid. Please repair before trying to split it." ) );
    }
    else if ( returnCode != 0 )
    {
      //several intersections but only one split (most likely line)
      QMessageBox::warning( 0, tr( "Split error" ), tr( "An error occured during feature splitting" ) );
    }

    stopCapturing();
  }
}
void QgsMapToolAddPart::canvasReleaseEvent( QMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //inform user at the begin of the digitising action that the island tool only works if exactly one feature is selected
  int nSelectedFeatures = vlayer->selectedFeatureCount();
  QString selectionErrorMsg;
  if ( nSelectedFeatures < 1 )
  {
    selectionErrorMsg = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" );
  }
  else if ( nSelectedFeatures > 1 )
  {
    selectionErrorMsg = tr( "Several features are selected. Please select only one feature to which an part should be added." );
  }

  if ( !selectionErrorMsg.isEmpty() )
  {
    QMessageBox::critical( 0, tr( "Error. Could not add part." ), selectionErrorMsg );
    stopCapturing();
    return;
  }

  int errorCode;
  switch ( mode() )
  {
    case CapturePoint:
    {
      QgsPoint layerPoint;
      QgsPoint mapPoint;

      if ( nextPoint( e->pos(), layerPoint, mapPoint ) != 0 )
      {
        QgsDebugMsg( "nextPoint failed" );
        return;
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      errorCode = vlayer->addPart( QList<QgsPoint>() << layerPoint );
    }
    break;

    case CaptureLine:
    case CapturePolygon:
    {
      //add point to list and to rubber band
      if ( e->button() == Qt::LeftButton )
      {
        int error = addVertex( e->pos() );
        if ( error == 1 )
        {
          QgsDebugMsg( "current layer is not a vector layer" );
          return;
        }
        else if ( error == 2 )
        {
          //problem with coordinate transformation
          QMessageBox::information( 0,
                                    tr( "Coordinate transform error" ),
                                    tr( "Cannot transform the point to the layers coordinate system" ) );
          return;
        }

        startCapturing();
        return;
      }
      else if ( e->button() != Qt::RightButton )
      {
        deleteTempRubberBand();

        return;
      }

      if ( mode() == CapturePolygon )
      {
        //close polygon
        closePolygon();
        //avoid intersections
        QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() );
        if ( geom )
        {
          geom->avoidIntersections();
          QgsPolygon poly = geom->asPolygon();
          if ( poly.size() < 1 )
          {
            stopCapturing();
            delete geom;
            vlayer->destroyEditCommand();
            return;
          }
          setPoints( geom->asPolygon()[0].toList() );
          delete geom;
        }
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      errorCode = vlayer->addPart( points() );

      stopCapturing();
    }
    break;
    default:
      Q_ASSERT( !"invalid capture mode" );
      errorCode = 6;
      break;
  }

  QString errorMessage;
  switch ( errorCode )
  {
    case 0:
    {
      //add points to other features to keep topology up-to-date
      int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
      if ( topologicalEditing )
      {
        addTopologicalPoints( points() );
      }

      vlayer->endEditCommand();

      mCanvas->refresh();
      return;
    }

    case 1:
      errorMessage = tr( "Selected feature is not multi part." );
      break;

    case 2:
      errorMessage = tr( "New part's geometry is not valid." );
      break;

    case 3:
      errorMessage = tr( "New polygon ring not disjoint with existing polygons." );
      break;

    case 4:
      errorMessage = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" );
      break;

    case 5:
      errorMessage = tr( "Several features are selected. Please select only one feature to which an island should be added." );
      break;

    case 6:
      errorMessage = tr( "Selected geometry could not be found" );
      break;
  }

  QMessageBox::critical( 0, tr( "Error, could not add part" ), errorMessage );
  vlayer->destroyEditCommand();
}
Example #8
0
void QgsMapToolAddRing::canvasReleaseEvent( QMouseEvent * e )
{

  emit messageDiscarded();

  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->pos() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    if ( !isCapturing() )
      return;

    deleteTempRubberBand();

    closePolygon();

    vlayer->beginEditCommand( tr( "Ring added" ) );
    int addRingReturnCode = vlayer->addRing( points() );
    if ( addRingReturnCode != 0 )
    {
      QString errorMessage;
      //todo: open message box to communicate errors
      if ( addRingReturnCode == 1 )
      {
        errorMessage = tr( "a problem with geometry type occured" );
      }
      else if ( addRingReturnCode == 2 )
      {
        errorMessage = tr( "the inserted ring is not closed" );
      }
      else if ( addRingReturnCode == 3 )
      {
        errorMessage = tr( "the inserted ring is not a valid geometry" );
      }
      else if ( addRingReturnCode == 4 )
      {
        errorMessage = tr( "the inserted ring crosses existing rings" );
      }
      else if ( addRingReturnCode == 5 )
      {
        errorMessage = tr( "the inserted ring is not contained in a feature" );
      }
      else
      {
        errorMessage = tr( "an unknown error occured" );
      }
      emit messageEmitted( tr( "could not add ring since %1." ).arg( errorMessage ), QgsMessageBar::CRITICAL );
      vlayer->destroyEditCommand();
    }
    else
    {
      vlayer->endEditCommand();
    }

    stopCapturing();
  }
}
Example #9
0
void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
{
  //check if we operate on a vector layer //todo: move this to a function in parent class to avoid duplication
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->mapPoint(), e->mapPointMatch() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    deleteTempRubberBand();

    //find out bounding box of mCaptureList
    if ( size() < 1 )
    {
      stopCapturing();
      return;
    }
    QgsPoint firstPoint = points().at( 0 );
    QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
    for ( int i = 1; i < size(); ++i )
    {
      bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
    }

    //query all the features that intersect bounding box of capture line
    QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
    QgsFeature f;
    int reshapeReturn;
    bool reshapeDone = false;

    vlayer->beginEditCommand( tr( "Reshape" ) );
    while ( fit.nextFeature( f ) )
    {
      //query geometry
      //call geometry->reshape(mCaptureList)
      //register changed geometry in vector layer
      QgsGeometry* geom = f.geometry();
      if ( geom )
      {
        reshapeReturn = geom->reshapeGeometry( points() );
        if ( reshapeReturn == 0 )
        {
          //avoid intersections on polygon layers
          if ( vlayer->geometryType() == QGis::Polygon )
          {
            //ignore all current layer features as they should be reshaped too
            QMap<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures;
            ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );

            if ( geom->avoidIntersections( ignoreFeatures ) != 0 )
            {
              emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
              vlayer->destroyEditCommand();
              stopCapturing();
              return;
            }

            if ( geom->isGeosEmpty() ) //intersection removal might have removed the whole geometry
            {
              emit messageEmitted( tr( "The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
              vlayer->destroyEditCommand();
              stopCapturing();
              return;
            }
          }

          vlayer->changeGeometry( f.id(), geom );
          reshapeDone = true;
        }
      }
    }

    if ( reshapeDone )
    {
      vlayer->endEditCommand();
    }
    else
    {
      vlayer->destroyEditCommand();
    }

    stopCapturing();
  }
}
Example #10
0
void QgsMapToolFillRing::canvasReleaseEvent( QMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->pos() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      QMessageBox::information( 0, tr( "Coordinate transform error" ),
                                tr( "Cannot transform the point to the layers coordinate system" ) );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    deleteTempRubberBand();

    closePolygon();

    vlayer->beginEditCommand( tr( "Ring added and filled" ) );
    int addRingReturnCode = vlayer->addRing( points() );
    if ( addRingReturnCode != 0 )
    {
      QString errorMessage;
      //todo: open message box to communicate errors
      if ( addRingReturnCode == 1 )
      {
        errorMessage = tr( "A problem with geometry type occured" );
      }
      else if ( addRingReturnCode == 2 )
      {
        errorMessage = tr( "The inserted Ring is not closed" );
      }
      else if ( addRingReturnCode == 3 )
      {
        errorMessage = tr( "The inserted Ring is not a valid geometry" );
      }
      else if ( addRingReturnCode == 4 )
      {
        errorMessage = tr( "The inserted Ring crosses existing rings" );
      }
      else if ( addRingReturnCode == 5 )
      {
        errorMessage = tr( "The inserted Ring is not contained in a feature" );
      }
      else
      {
        errorMessage = tr( "An unknown error occured" );
      }
      QMessageBox::critical( 0, tr( "Error, could not add ring" ), errorMessage );
      vlayer->destroyEditCommand();
    }
    else
    {
      // find parent feature and get it attributes
      double xMin, xMax, yMin, yMax;
      QgsRectangle bBox;

      xMin = std::numeric_limits<double>::max();
      xMax = -std::numeric_limits<double>::max();
      yMin = std::numeric_limits<double>::max();
      yMax = -std::numeric_limits<double>::max();

      for ( QList<QgsPoint>::const_iterator it = points().constBegin(); it != points().constEnd(); ++it )
      {
        if ( it->x() < xMin )
        {
          xMin = it->x();
        }
        if ( it->x() > xMax )
        {
          xMax = it->x();
        }
        if ( it->y() < yMin )
        {
          yMin = it->y();
        }
        if ( it->y() > yMax )
        {
          yMax = it->y();
        }
      }
      bBox.setXMinimum( xMin );
      bBox.setYMinimum( yMin );
      bBox.setXMaximum( xMax );
      bBox.setYMaximum( yMax );

      QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );

      QgsFeature f;
      bool res = false;
      while ( fit.nextFeature( f ) )
      {
        //create QgsFeature with wkb representation
        QgsFeature* ft = new QgsFeature( vlayer->pendingFields(),  0 );

        QgsGeometry *g;
        g = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() );
        ft->setGeometry( g );
        ft->setAttributes( f.attributes() );

        if ( QgsApplication::keyboardModifiers() == Qt::ControlModifier )
        {
          res = vlayer->addFeature( *ft );
        }
        else
        {
          QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true );
          dialog->setIsAddDialog( true );
          res = dialog->exec(); // will also add the feature
        }

        if ( res )
        {
          vlayer->endEditCommand();
        }
        else
        {
          delete ft;
          vlayer->destroyEditCommand();
        }
        res = false;
      }
    }
    stopCapturing();
  }
}
Example #11
0
void QgsMapToolAddRing::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
{

  emit messageDiscarded();

  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = currentVectorLayer();

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->mapPoint() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    if ( !isCapturing() )
      return;

    deleteTempRubberBand();

    closePolygon();

    vlayer->beginEditCommand( tr( "Ring added" ) );

    //does compoundcurve contain circular strings?
    //does provider support circular strings?
    bool hasCurvedSegments = captureCurve()->hasCurvedSegments();
    bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries;

    QgsCurveV2* curveToAdd = 0;
    if ( hasCurvedSegments && providerSupportsCurvedSegments )
    {
      curveToAdd = dynamic_cast<QgsCurveV2*>( captureCurve()->clone() );
    }
    else
    {
      curveToAdd = captureCurve()->curveToLine();
    }

    int addRingReturnCode = vlayer->addRing( curveToAdd );
    if ( addRingReturnCode != 0 )
    {
      QString errorMessage;
      //todo: open message box to communicate errors
      if ( addRingReturnCode == 1 )
      {
        errorMessage = tr( "a problem with geometry type occured" );
      }
      else if ( addRingReturnCode == 2 )
      {
        errorMessage = tr( "the inserted ring is not closed" );
      }
      else if ( addRingReturnCode == 3 )
      {
        errorMessage = tr( "the inserted ring is not a valid geometry" );
      }
      else if ( addRingReturnCode == 4 )
      {
        errorMessage = tr( "the inserted ring crosses existing rings" );
      }
      else if ( addRingReturnCode == 5 )
      {
        errorMessage = tr( "the inserted ring is not contained in a feature" );
      }
      else
      {
        errorMessage = tr( "an unknown error occured" );
      }
      emit messageEmitted( tr( "could not add ring since %1." ).arg( errorMessage ), QgsMessageBar::CRITICAL );
      vlayer->destroyEditCommand();
    }
    else
    {
      vlayer->endEditCommand();
    }

    stopCapturing();
  }
}
bool QgsMapToolPinLabels::pinUnpinCurrentLabel( bool pin )
{
  QgsVectorLayer *vlayer = mCurrentLabel.layer;
  const QgsLabelPosition &labelpos = mCurrentLabel.pos;

  // skip diagrams
  if ( labelpos.isDiagram )
  {
    QgsDebugMsg( QStringLiteral( "Label is diagram, skipping" ) );
    return false;
  }

  // verify attribute table has x, y fields mapped
  int xCol, yCol;
  double xPosOrig, yPosOrig;
  bool xSuccess, ySuccess;

  if ( !currentLabelDataDefinedPosition( xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) )
  {
    QgsDebugMsg( QStringLiteral( "Label X or Y column not mapped, skipping" ) );
    return false;
  }

  // rotation field is optional, but will be used if available, unless data exists
  int rCol;
  bool rSuccess = false;
  double defRot;

  bool hasRCol = currentLabelDataDefinedRotation( defRot, rSuccess, rCol, true );

  // get whether to preserve predefined rotation data during label pin/unpin operations
  bool preserveRot = currentLabelPreserveRotation();

  // edit attribute table
  int fid = labelpos.featureId;

  bool writeFailed = false;
  QString labelText = currentLabelText( 24 );

  if ( pin )
  {

//     QgsPointXY labelpoint = labelpos.cornerPoints.at( 0 );

    QgsPointXY referencePoint;
    if ( !currentLabelRotationPoint( referencePoint, !preserveRot, false ) )
    {
      referencePoint.setX( labelpos.labelRect.xMinimum() );
      referencePoint.setY( labelpos.labelRect.yMinimum() );
    }

    double labelX = referencePoint.x();
    double labelY = referencePoint.y();
    double labelR = labelpos.rotation * 180 / M_PI;

    // transform back to layer crs
    QgsPointXY transformedPoint = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, referencePoint );
    labelX = transformedPoint.x();
    labelY = transformedPoint.y();

    vlayer->beginEditCommand( tr( "Pinned label" ) + QStringLiteral( " '%1'" ).arg( labelText ) );
    writeFailed = !vlayer->changeAttributeValue( fid, xCol, labelX );
    if ( !vlayer->changeAttributeValue( fid, yCol, labelY ) )
      writeFailed = true;
    if ( hasRCol && !preserveRot )
    {
      if ( !vlayer->changeAttributeValue( fid, rCol, labelR ) )
        writeFailed = true;
    }
    vlayer->endEditCommand();
  }
  else
  {
    vlayer->beginEditCommand( tr( "Unpinned label" ) + QStringLiteral( " '%1'" ).arg( labelText ) );
    writeFailed = !vlayer->changeAttributeValue( fid, xCol, QVariant( QString() ) );
    if ( !vlayer->changeAttributeValue( fid, yCol, QVariant( QString() ) ) )
      writeFailed = true;
    if ( hasRCol && !preserveRot )
    {
      if ( !vlayer->changeAttributeValue( fid, rCol, QVariant( QString() ) ) )
        writeFailed = true;
    }
    vlayer->endEditCommand();
  }

  if ( writeFailed )
  {
    QgsDebugMsg( QStringLiteral( "Write to attribute table failed" ) );

#if 0
    QgsDebugMsg( QStringLiteral( "Undoing and removing failed command from layer's undo stack" ) );
    int lastCmdIndx = vlayer->undoStack()->count();
    const QgsUndoCommand *lastCmd = qobject_cast<const QgsUndoCommand *>( vlayer->undoStack()->command( lastCmdIndx ) );
    if ( lastCmd )
    {
      vlayer->undoEditCommand( lastCmd );
      delete vlayer->undoStack()->command( lastCmdIndx );
    }
#endif

    return false;
  }

  return true;
}
Example #13
0
void QgsMapToolShowHideLabels::showHideLabels( QMouseEvent * e )
{
  QgsMapLayer* layer = mCanvas->currentLayer();

  QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer );
  if ( !vlayer )
  {
    QgsDebugMsg( "Failed to cast label layer to vector layer" );
    return;
  }
  if ( !vlayer->isEditable() )
  {
    QgsDebugMsg( "Vector layer not editable, skipping label" );
    return;
  }

  bool doHide = e->modifiers() & Qt::ShiftModifier ? true : false;

  QgsFeatureIds selectedFeatIds;

  if ( !doHide )
  {
    QgsDebugMsg( "Showing labels operation" );

    if ( !selectedFeatures( vlayer, selectedFeatIds ) )
    {
      return;
    }
  }
  else
  {
    QgsDebugMsg( "Hiding labels operation" );

    if ( !selectedLabelFeatures( vlayer, selectedFeatIds ) )
    {
      return;
    }
  }

  QgsDebugMsg( "Number of selected labels or features: " + QString::number( selectedFeatIds.size() ) );

  if ( selectedFeatIds.isEmpty() )
  {
    return;
  }

  bool labelChanged = false;
  QString editTxt = doHide ? tr( "Hid labels" ) : tr( "Showed labels" );

  vlayer->beginEditCommand( editTxt );
  Q_FOREACH ( const QgsFeatureId &fid, selectedFeatIds )
  {
    if ( showHideLabel( vlayer, fid, doHide ) )
    {
      // TODO: highlight features (maybe with QTimer?)
      labelChanged = true;
    }
  }

  if ( labelChanged )
  {
    vlayer->endEditCommand();
    mCanvas->refresh();
  }
  else
  {
    vlayer->destroyEditCommand();
  }
}
void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
{
  QgsVectorLayer *vlayer = currentVectorLayer();
  if ( !vlayer || !vlayer->isEditable() )
  {
    delete mRubberBand;
    mRubberBand = nullptr;
    mSnapIndicator->setMatch( QgsPointLocator::Match() );
    cadDockWidget()->clear();
    notifyNotEditableLayer();
    return;
  }

  if ( !mRubberBand )
  {
    //find first geometry under mouse cursor and store iterator to it
    QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->mapPoint() );
    double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
    QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
                             layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );

    if ( vlayer->selectedFeatureCount() == 0 )
    {
      QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setNoAttributes() );

      //find the closest feature
      QgsGeometry pointGeometry = QgsGeometry::fromPointXY( layerCoords );
      if ( pointGeometry.isNull() )
      {
        cadDockWidget()->clear();
        return;
      }

      double minDistance = std::numeric_limits<double>::max();

      QgsFeature cf;
      QgsFeature f;
      while ( fit.nextFeature( f ) )
      {
        if ( f.hasGeometry() )
        {
          double currentDistance = pointGeometry.distance( f.geometry() );
          if ( currentDistance < minDistance )
          {
            minDistance = currentDistance;
            cf = f;
          }
        }
      }

      if ( minDistance == std::numeric_limits<double>::max() )
      {
        cadDockWidget()->clear();
        return;
      }

      mMovedFeatures.clear();
      mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one...

      mRubberBand = createRubberBand( vlayer->geometryType() );
      mRubberBand->setToGeometry( cf.geometry(), vlayer );
    }
    else
    {
      mMovedFeatures = vlayer->selectedFeatureIds();

      mRubberBand = createRubberBand( vlayer->geometryType() );
      QgsFeature feat;
      QgsFeatureIterator it = vlayer->getSelectedFeatures( QgsFeatureRequest().setNoAttributes() );

      bool allFeaturesInView = true;
      QgsRectangle viewRect = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, mCanvas->extent() );

      while ( it.nextFeature( feat ) )
      {
        mRubberBand->addGeometry( feat.geometry(), vlayer );

        if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) )
          allFeaturesInView = false;
      }

      if ( !allFeaturesInView )
      {
        // for extra safety to make sure we are not modifying geometries by accident

        int res = QMessageBox::warning( mCanvas, tr( "Move features" ),
                                        tr( "Some of the selected features are outside of the current map view. Would you still like to continue?" ),
                                        QMessageBox::Yes | QMessageBox::No );
        if ( res != QMessageBox::Yes )
        {
          mMovedFeatures.clear();
          delete mRubberBand;
          mRubberBand = nullptr;
          mSnapIndicator->setMatch( QgsPointLocator::Match() );
          return;
        }
      }
    }

    mStartPointMapCoords = e->mapPoint();
    mRubberBand->show();
  }
  else
  {
    // copy and move mode
    if ( e->button() != Qt::LeftButton )
    {
      cadDockWidget()->clear();
      delete mRubberBand;
      mRubberBand = nullptr;
      mSnapIndicator->setMatch( QgsPointLocator::Match() );
      return;
    }

    QgsPointXY startPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, mStartPointMapCoords );
    QgsPointXY stopPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, e->mapPoint() );

    double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
    double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();

    vlayer->beginEditCommand( mMode == Move ? tr( "Feature moved" ) : tr( "Feature copied and moved" ) );

    switch ( mMode )
    {
      case Move:
        Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
        {
          vlayer->translateFeature( id, dx, dy );
        }
        delete mRubberBand;
        mRubberBand = nullptr;
        mSnapIndicator->setMatch( QgsPointLocator::Match() );
        cadDockWidget()->clear();
        break;

      case CopyMove:
        QgsFeatureRequest request;
        request.setFilterFids( mMovedFeatures );
        QString *errorMsg = new QString();
        if ( !QgisApp::instance()->vectorLayerTools()->copyMoveFeatures( vlayer, request, dx, dy, errorMsg ) )
        {
          emit messageEmitted( *errorMsg, Qgis::Critical );
          delete mRubberBand;
          mRubberBand = nullptr;
          mSnapIndicator->setMatch( QgsPointLocator::Match() );
        }
        break;
    }

    vlayer->endEditCommand();
    vlayer->triggerRepaint();
  }
void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
{
  QgsDebugMsg( "entered." );

  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  QGis::WkbType layerWKBType = vlayer->wkbType();

  QgsVectorDataProvider* provider = vlayer->dataProvider();

  if ( !( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) )
  {
    QMessageBox::information( 0, tr( "Layer cannot be added to" ),
                              tr( "The data provider for this layer does not support the addition of features." ) );
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  // POINT CAPTURING
  if ( mode() == CapturePoint )
  {
    //check we only use this tool for point/multipoint layers
    if ( vlayer->geometryType() != QGis::Point )
    {
      QMessageBox::information( 0, tr( "Wrong editing tool" ),
                                tr( "Cannot apply the 'capture point' tool on this vector layer" ) );
      return;
    }


    QgsPoint idPoint; //point in map coordinates
    QList<QgsSnappingResult> snapResults;
    QgsPoint savePoint; //point in layer coordinates

    if ( mSnapper.snapToBackgroundLayers( e->pos(), snapResults ) == 0 )
    {
      idPoint = snapPointFromResults( snapResults, e->pos() );
      try
      {
        savePoint = toLayerCoordinates( vlayer, idPoint );
        QgsDebugMsg( "savePoint = " + savePoint.toString() );
      }
      catch ( QgsCsException &cse )
      {
        Q_UNUSED( cse );
        QMessageBox::information( 0, tr( "Coordinate transform error" ),
                                  tr( "Cannot transform the point to the layers coordinate system" ) );
        return;
      }
    }

    //only do the rest for provider with feature addition support
    //note that for the grass provider, this will return false since
    //grass provider has its own mechanism of feature addition
    if ( provider->capabilities() & QgsVectorDataProvider::AddFeatures )
    {
      QgsFeature* f = new QgsFeature( 0, "WKBPoint" );

      QgsGeometry *g = 0;
      if ( layerWKBType == QGis::WKBPoint || layerWKBType == QGis::WKBPoint25D )
      {
        g = QgsGeometry::fromPoint( savePoint );
      }
      else if ( layerWKBType == QGis::WKBMultiPoint || layerWKBType == QGis::WKBMultiPoint25D )
      {
        g = QgsGeometry::fromMultiPoint( QgsMultiPoint() << savePoint );
      }

      f->setGeometry( g );

      vlayer->beginEditCommand( tr( "Feature added" ) );

      if ( addFeature( vlayer, f ) )
      {
        vlayer->endEditCommand();
      }
      else
      {
        delete f;
        vlayer->destroyEditCommand();
      }

      mCanvas->refresh();
    }
  }
  else if ( mode() == CaptureLine || mode() == CapturePolygon )
  {
    //check we only use the line tool for line/multiline layers
    if ( mode() == CaptureLine && vlayer->geometryType() != QGis::Line )
    {
      QMessageBox::information( 0, tr( "Wrong editing tool" ),
                                tr( "Cannot apply the 'capture line' tool on this vector layer" ) );
      return;
    }

    //check we only use the polygon tool for polygon/multipolygon layers
    if ( mode() == CapturePolygon && vlayer->geometryType() != QGis::Polygon )
    {
      QMessageBox::information( 0, tr( "Wrong editing tool" ),
                                tr( "Cannot apply the 'capture polygon' tool on this vector layer" ) );
      return;
    }

    //add point to list and to rubber band
    int error = addVertex( e->pos() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      QMessageBox::information( 0, tr( "Coordinate transform error" ),
                                tr( "Cannot transform the point to the layers coordinate system" ) );
      return;
    }

    if ( e->button() == Qt::LeftButton )
    {
      startCapturing();
    }
    else if ( e->button() == Qt::RightButton )
    {
      // End of string

      //lines: bail out if there are not at least two vertices
      if ( mode() == CaptureLine && size() < 2 )
      {
        stopCapturing();
        return;
      }

      //polygons: bail out if there are not at least two vertices
      if ( mode() == CapturePolygon && size() < 3 )
      {
        stopCapturing();
        return;
      }

      //create QgsFeature with wkb representation
      QgsFeature* f = new QgsFeature( 0, "WKBLineString" );

      QgsGeometry *g;

      if ( mode() == CaptureLine )
      {
        if ( layerWKBType == QGis::WKBLineString || layerWKBType == QGis::WKBLineString25D )
        {
          g = QgsGeometry::fromPolyline( points().toVector() );
        }
        else if ( layerWKBType == QGis::WKBMultiLineString || layerWKBType == QGis::WKBMultiLineString25D )
        {
          g = QgsGeometry::fromMultiPolyline( QgsMultiPolyline() << points().toVector() );
        }
        else
        {
          QMessageBox::critical( 0, tr( "Error" ), tr( "Cannot add feature. Unknown WKB type" ) );
          stopCapturing();
          return; //unknown wkbtype
        }

        f->setGeometry( g );
      }
      else // polygon
      {
        if ( layerWKBType == QGis::WKBPolygon ||  layerWKBType == QGis::WKBPolygon25D )
        {
          g = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() );
        }
        else if ( layerWKBType == QGis::WKBMultiPolygon ||  layerWKBType == QGis::WKBMultiPolygon25D )
        {
          g = QgsGeometry::fromMultiPolygon( QgsMultiPolygon() << ( QgsPolygon() << points().toVector() ) );
        }
        else
        {
          QMessageBox::critical( 0, tr( "Error" ), tr( "Cannot add feature. Unknown WKB type" ) );
          stopCapturing();
          return; //unknown wkbtype
        }

        if ( !g )
        {
          stopCapturing();
          delete f;
          return; // invalid geometry; one possibility is from duplicate points
        }
        f->setGeometry( g );

        int avoidIntersectionsReturn = f->geometry()->avoidIntersections();
        if ( avoidIntersectionsReturn == 1 )
        {
          //not a polygon type. Impossible to get there
        }
#if 0
        else if ( avoidIntersectionsReturn == 2 ) //MH120131: disable this error message until there is a better way to cope with the single type / multi type problem
        {
          //bail out...
          QMessageBox::critical( 0, tr( "Error" ), tr( "The feature could not be added because removing the polygon intersections would change the geometry type" ) );
          delete f;
          stopCapturing();
          return;
        }
#endif
        else if ( avoidIntersectionsReturn == 3 )
        {
          QMessageBox::critical( 0, tr( "Error" ), tr( "An error was reported during intersection removal" ) );
        }
      }

      vlayer->beginEditCommand( tr( "Feature added" ) );

      if ( addFeature( vlayer, f ) )
      {
        //add points to other features to keep topology up-to-date
        int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
        if ( topologicalEditing )
        {
          vlayer->addTopologicalPoints( f->geometry() );
        }

        vlayer->endEditCommand();
      }
      else
      {
        delete f;
        vlayer->destroyEditCommand();
      }

      stopCapturing();
    }
  }
}
void QgsMapToolSplitFeatures::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  bool split = false;


  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    //If we snap the first point on a vertex of a line layer, we directly split the feature at this point
    if ( vlayer->geometryType() == QgsWkbTypes::LineGeometry && points().isEmpty() )
    {
      QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex );
      if ( m.isValid() )
      {
        split = true;
      }
    }

    int error = addVertex( e->mapPoint(), e->mapPointMatch() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "Coordinate transform error" ),
        tr( "Cannot transform the point to the layers coordinate system" ),
        QgsMessageBar::INFO,
        QgisApp::instance()->messageTimeout() );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    split = true;
  }

  if ( split )
  {
    deleteTempRubberBand();

    //bring up dialog if a split was not possible (polygon) or only done once (line)
    int topologicalEditing = QgsProject::instance()->topologicalEditing();
    vlayer->beginEditCommand( tr( "Features split" ) );
    int returnCode = vlayer->splitFeatures( points(), topologicalEditing );
    vlayer->endEditCommand();
    if ( returnCode == 4 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No features were split" ),
        tr( "If there are selected features, the split tool only applies to those. If you would like to split all features under the split line, clear the selection." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode == 3 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "Cut edges detected. Make sure the line splits features into multiple parts." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode == 7 )
    {
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "The geometry is invalid. Please repair before trying to split it." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }
    else if ( returnCode != 0 )
    {
      //several intersections but only one split (most likely line)
      QgisApp::instance()->messageBar()->pushMessage(
        tr( "No feature split done" ),
        tr( "An error occurred during splitting." ),
        QgsMessageBar::WARNING,
        QgisApp::instance()->messageTimeout() );
    }

    stopCapturing();
  }
}
void QgsMapToolReshape::canvasReleaseEvent( QMouseEvent * e )
{
  //check if we operate on a vector layer //todo: move this to a function in parent class to avoid duplication
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //add point to list and to rubber band
  if ( e->button() == Qt::LeftButton )
  {
    int error = addVertex( e->pos() );
    if ( error == 1 )
    {
      //current layer is not a vector layer
      return;
    }
    else if ( error == 2 )
    {
      //problem with coordinate transformation
      QMessageBox::information( 0, tr( "Coordinate transform error" ),
                                   tr( "Cannot transform the point to the layers coordinate system" ) );
      return;
    }

    startCapturing();
  }
  else if ( e->button() == Qt::RightButton )
  {
    deleteTempRubberBand();

    //find out bounding box of mCaptureList
    if ( size() < 1 )
    {
      stopCapturing();
      return;
    }
    QgsPoint firstPoint = points().at( 0 );
    QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
    for ( int i = 1; i < size(); ++i )
    {
      bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
    }

    //query all the features that intersect bounding box of capture line
    QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
    QgsFeature f;
    int reshapeReturn;
    bool reshapeDone = false;

    vlayer->beginEditCommand( tr( "Reshape" ) );
    while ( fit.nextFeature( f ) )
    {
      //query geometry
      //call geometry->reshape(mCaptureList)
      //register changed geometry in vector layer
      QgsGeometry* geom = f.geometry();
      if ( geom )
      {
        reshapeReturn = geom->reshapeGeometry( points() );
        if ( reshapeReturn == 0 )
        {
          vlayer->changeGeometry( f.id(), geom );
          reshapeDone = true;
        }
      }
    }

    if ( reshapeDone )
    {
      vlayer->endEditCommand();
    }
    else
    {
      vlayer->destroyEditCommand();
    }

    stopCapturing();
  }
}
Example #18
0
void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = currentVectorLayer();
  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  bool isGeometryEmpty = false;
  QgsFeatureList selectedFeatures = vlayer->selectedFeatures();
  if ( !selectedFeatures.isEmpty() && selectedFeatures.at( 0 ).geometry().isNull() )
    isGeometryEmpty = true;

  if ( !checkSelection() )
  {
    stopCapturing();
    return;
  }

  int errorCode = 0;
  switch ( mode() )
  {
    case CapturePoint:
    {
      QgsPoint layerPoint;
      QgsPointXY mapPoint = e->mapPoint();

      if ( nextPoint( QgsPoint( mapPoint ), layerPoint ) != 0 )
      {
        QgsDebugMsg( "nextPoint failed" );
        return;
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      errorCode = vlayer->addPart( QgsPointSequence() << layerPoint );
    }
    break;

    case CaptureLine:
    case CapturePolygon:
    {
      //add point to list and to rubber band
      if ( e->button() == Qt::LeftButton )
      {
        int error = addVertex( e->mapPoint(), e->mapPointMatch() );
        if ( error == 1 )
        {
          QgsDebugMsg( "current layer is not a vector layer" );
          return;
        }
        else if ( error == 2 )
        {
          //problem with coordinate transformation
          emit messageEmitted( tr( "Coordinate transform error. Cannot transform the point to the layers coordinate system" ), Qgis::Warning );
          return;
        }

        startCapturing();
        return;
      }
      else if ( e->button() != Qt::RightButton )
      {
        deleteTempRubberBand();

        return;
      }

      if ( !isCapturing() )
        return;

      if ( mode() == CapturePolygon )
      {
        closePolygon();
      }

      //does compoundcurve contain circular strings?
      //does provider support circular strings?
      bool hasCurvedSegments = captureCurve()->hasCurvedSegments();
      bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries;

      QgsCurve *curveToAdd = nullptr;
      if ( hasCurvedSegments && providerSupportsCurvedSegments )
      {
        curveToAdd = captureCurve()->clone();
      }
      else
      {
        curveToAdd = captureCurve()->curveToLine();
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      if ( mode() == CapturePolygon )
      {
        //avoid intersections
        QgsCurvePolygon *cp = new QgsCurvePolygon();
        cp->setExteriorRing( curveToAdd );
        QgsGeometry *geom = new QgsGeometry( cp );
        geom->avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );

        const QgsCurvePolygon *cpGeom = qgsgeometry_cast<const QgsCurvePolygon *>( geom->constGet() );
        if ( !cpGeom )
        {
          stopCapturing();
          delete geom;
          vlayer->destroyEditCommand();
          return;
        }

        errorCode = vlayer->addPart( cpGeom->exteriorRing()->clone() );
        delete geom;
      }
      else
      {
        errorCode = vlayer->addPart( curveToAdd );
      }
      stopCapturing();
    }
    break;
    default:
      Q_ASSERT( !"invalid capture mode" );
      errorCode = 6;
      break;
  }

  QString errorMessage;
  switch ( errorCode )
  {
    case 0:
    {
      // remove previous message
      emit messageDiscarded();

      //add points to other features to keep topology up-to-date
      bool topologicalEditing = QgsProject::instance()->topologicalEditing();
      if ( topologicalEditing )
      {
        addTopologicalPoints( points() );
      }

      vlayer->endEditCommand();

      vlayer->triggerRepaint();

      if ( ( !isGeometryEmpty ) && QgsWkbTypes::isSingleType( vlayer->wkbType() ) )
      {
        emit messageEmitted( tr( "Add part: Feature geom is single part and you've added more than one" ), Qgis::Warning );
      }

      return;
    }

    case 1:
      errorMessage = tr( "Selected feature is not multi part." );
      break;

    case 2:
      errorMessage = tr( "New part's geometry is not valid." );
      break;

    case 3:
      errorMessage = tr( "New polygon ring not disjoint with existing polygons." );
      break;

    case 4:
      errorMessage = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" );
      break;

    case 5:
      errorMessage = tr( "Several features are selected. Please select only one feature to which an island should be added." );
      break;

    case 6:
      errorMessage = tr( "Selected geometry could not be found" );
      break;
  }

  emit messageEmitted( errorMessage, Qgis::Warning );
  vlayer->destroyEditCommand();
}
Example #19
0
void QgsMapToolOffsetCurve::applyOffset()
{
  QgsVectorLayer* layer = currentVectorLayer();
  if ( !layer )
  {
    deleteRubberBandAndGeometry();
    notifyNotVectorLayer();
    return;
  }

  // no modification
  if ( !mGeometryModified )
  {
    deleteRubberBandAndGeometry();
    layer->destroyEditCommand();
    deleteDistanceWidget();
    return;
  }

  if ( mMultiPartGeometry )
  {
    mModifiedGeometry.convertToMultiType();
  }

  layer->beginEditCommand( tr( "Offset curve" ) );

  bool editOk;
  if ( mSourceLayerId == layer->id() && !mForceCopy )
  {
    editOk = layer->changeGeometry( mModifiedFeature, &mModifiedGeometry );
  }
  else
  {
    QgsFeature f;
    f.setGeometry( mModifiedGeometry );

    //add empty values for all fields (allows inserting attribute values via the feature form in the same session)
    QgsAttributes attrs( layer->fields().count() );
    const QgsFields& fields = layer->fields();
    for ( int idx = 0; idx < fields.count(); ++idx )
    {
      attrs[idx] = QVariant();
    }
    f.setAttributes( attrs );
    editOk = layer->addFeature( f );
  }

  if ( editOk )
  {
    layer->endEditCommand();
  }
  else
  {
    layer->destroyEditCommand();
  }

  deleteRubberBandAndGeometry();
  deleteDistanceWidget();
  delete mSnapVertexMarker;
  mSnapVertexMarker = nullptr;
  mForceCopy = false;
  mCanvas->refresh();
}