bool QgsMapToolLabel::dataDefinedRotation( QgsVectorLayer* vlayer, const QgsFeatureId &featureId, double& rotation, bool& rotationSuccess, bool ignoreXY ) const { rotationSuccess = false; if ( !vlayer ) { return false; } int rotationCol; if ( !layerIsRotatable( vlayer, rotationCol ) ) { return false; } QgsFeature f; if ( !vlayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) ) { return false; } //test, if data defined x- and y- values are not null. Otherwise, the position is determined by PAL and the rotation cannot be fixed if ( !ignoreXY ) { int xCol, yCol; double x, y; bool xSuccess, ySuccess; if ( !dataDefinedPosition( vlayer, featureId, x, xSuccess, y, ySuccess, xCol, yCol ) || !xSuccess || !ySuccess ) { return false; } } rotation = f.attribute( rotationCol ).toDouble( &rotationSuccess ); return true; }
bool QgsMapToolLabel::isPinned() { bool rc = false; if ( ! mCurrentLabelPos.isDiagram ) { rc = mCurrentLabelPos.isPinned; } else { // for diagrams, the isPinned attribute is not set. So we check directly if // there's data defined. int xCol, yCol; double x, y; bool xSuccess, ySuccess; if ( dataDefinedPosition( currentLayer(), mCurrentLabelPos.featureId, x, xSuccess, y, ySuccess, xCol, yCol ) && xSuccess && ySuccess ) rc = true; } return rc; }
bool QgsMapToolLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess, bool ignoreXY ) { rotationSuccess = false; if ( !vlayer ) { return false; } int rotationCol; if ( !layerIsRotatable( vlayer, rotationCol ) ) { return false; } QgsFeature f; if ( !vlayer->featureAtId( featureId, f, false, true ) ) { return false; } QgsAttributeMap attributes = f.attributeMap(); //test, if data defined x- and y- values are not null. Otherwise, the position is determined by PAL and the rotation cannot be fixed if ( !ignoreXY ) { int xCol, yCol; double x, y; bool xSuccess, ySuccess; if ( !dataDefinedPosition( vlayer, featureId, x, xSuccess, y, ySuccess, xCol, yCol ) || !xSuccess || !ySuccess ) { return false; } } rotation = attributes[rotationCol].toDouble( &rotationSuccess ); return true; }
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(); }
bool QgsMapToolPinLabels::pinUnpinLabel( QgsVectorLayer* vlayer, const QgsLabelPosition& labelpos, bool pin ) { // skip diagrams if ( labelpos.isDiagram ) { QgsDebugMsg( QString( "Label is diagram, skipping" ) ); return false; } // verify attribute table has x, y fields mapped int xCol, yCol; double xPosOrig, yPosOrig; bool xSuccess, ySuccess; if ( !dataDefinedPosition( vlayer, mCurrentLabelPos.featureId, xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) ) { QgsDebugMsg( QString( "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 = ( layerIsRotatable( vlayer, rCol ) && dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess, true ) ); // get whether to preserve predefined rotation data during label pin/unpin operations bool preserveRot = preserveRotation(); // edit attribute table int fid = labelpos.featureId; bool writeFailed = false; QString labelText = currentLabelText( 24 ); if ( pin ) { // QgsPoint labelpoint = labelpos.cornerPoints.at( 0 ); QgsPoint referencePoint; if ( !rotationPoint( referencePoint, !preserveRot, false ) ) { referencePoint.setX( mCurrentLabelPos.labelRect.xMinimum() ); referencePoint.setY( mCurrentLabelPos.labelRect.yMinimum() ); } double labelX = referencePoint.x(); double labelY = referencePoint.y(); double labelR = labelpos.rotation * 180 / M_PI; // transform back to layer crs, if on-fly on if ( mCanvas->mapSettings().hasCrsTransformEnabled() ) { QgsPoint transformedPoint = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, referencePoint ); labelX = transformedPoint.x(); labelY = transformedPoint.y(); } vlayer->beginEditCommand( tr( "Pinned label" ) + QString( " '%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" ) + QString( " '%1'" ).arg( labelText ) ); writeFailed = !vlayer->changeAttributeValue( fid, xCol, QVariant( QString::null ) ); if ( !vlayer->changeAttributeValue( fid, yCol, QVariant( QString::null ) ) ) writeFailed = true; if ( hasRCol && !preserveRot ) { if ( !vlayer->changeAttributeValue( fid, rCol, QVariant( QString::null ) ) ) writeFailed = true; } vlayer->endEditCommand(); } if ( writeFailed ) { QgsDebugMsg( QString( "Write to attribute table failed" ) ); #if 0 QgsDebugMsg( QString( "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; }