bool QgsMapToolPinLabels::pinUnpinCurrentDiagram( bool pin ) { // skip diagrams if ( ! mCurrentLabel.pos.isDiagram ) 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 ) ) return false; // edit attribute table QgsVectorLayer *vlayer = mCurrentLabel.layer; int fid = mCurrentLabel.pos.featureId; bool writeFailed = false; QString labelText = currentLabelText( 24 ); if ( pin ) { QgsPointXY referencePoint = mCurrentLabel.pos.labelRect.center(); double labelX = referencePoint.x(); double labelY = referencePoint.y(); // transform back to layer crs QgsPointXY transformedPoint = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, referencePoint ); labelX = transformedPoint.x(); labelY = transformedPoint.y(); vlayer->beginEditCommand( tr( "Pinned diagram" ) + QStringLiteral( " '%1'" ).arg( labelText ) ); writeFailed = !vlayer->changeAttributeValue( fid, xCol, labelX ); if ( !vlayer->changeAttributeValue( fid, yCol, labelY ) ) writeFailed = true; vlayer->endEditCommand(); } else { vlayer->beginEditCommand( tr( "Unpinned diagram" ) + QStringLiteral( " '%1'" ).arg( labelText ) ); writeFailed = !vlayer->changeAttributeValue( fid, xCol, QVariant( QString() ) ); if ( !vlayer->changeAttributeValue( fid, yCol, QVariant( QString() ) ) ) writeFailed = true; vlayer->endEditCommand(); } return !writeFailed; }
bool QgsMapToolShowHideLabels::showHideLabel( QgsVectorLayer* vlayer, int fid, bool hide ) { // verify attribute table has proper field setup bool showSuccess; int showCol; int show; if ( !dataDefinedShowHide( vlayer, fid, show, showSuccess, showCol ) ) { return false; } // check if attribute value is already the same QgsFeature f; if ( !vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) ) { return false; } int colVal = hide ? 0 : 1; QVariant fQVal = f.attributes()[showCol]; bool convToInt; int fVal = fQVal.toInt( &convToInt ); if ( !convToInt || fVal == colVal ) { return false; } // different attribute value, edit table QString labelText = currentLabelText( 24 ); QString editTxt = hide ? tr( "Hid label" ) : tr( "Showed label" ); vlayer->beginEditCommand( editTxt + QString( " '%1'" ).arg( labelText ) ); if ( !vlayer->changeAttributeValue( fid, showCol, colVal, true ) ) { QgsDebugMsg( "Failed write to attribute table" ); vlayer->endEditCommand(); return false; } vlayer->endEditCommand(); return true; }
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 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(); }
void QgsMapToolChangeLabelProperties::canvasReleaseEvent( QMouseEvent *e ) { Q_UNUSED( e ); QgsVectorLayer* vlayer = currentLayer(); if ( mLabelRubberBand && mCanvas && vlayer ) { QString labeltext = QString(); // NULL QString signifies no expression bool settingsOk; QgsPalLayerSettings& labelSettings = currentLabelSettings( &settingsOk ); if ( settingsOk && labelSettings.isExpression ) { labeltext = mCurrentLabelPos.labelText; } QgsLabelPropertyDialog d( mCurrentLabelPos.layerID, mCurrentLabelPos.featureId, mCurrentLabelPos.labelFont, labeltext, 0 ); if ( d.exec() == QDialog::Accepted ) { const QgsAttributeMap& changes = d.changedProperties(); if ( changes.size() > 0 ) { vlayer->beginEditCommand( tr( "Changed properties for label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) ); QgsAttributeMap::const_iterator changeIt = changes.constBegin(); for ( ; changeIt != changes.constEnd(); ++changeIt ) { vlayer->changeAttributeValue( mCurrentLabelPos.featureId, changeIt.key(), changeIt.value() ); } vlayer->endEditCommand(); mCanvas->refresh(); } } deleteRubberBands(); } }
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; }
void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle& ext, QMouseEvent * e ) { bool doUnpin = e->modifiers() & Qt::ShiftModifier ? true : false; bool toggleUnpinOrPin = e->modifiers() & Qt::ControlModifier ? true : false; // get list of all drawn labels from all layers within, or touching, chosen extent bool labelChanged = false; const QgsLabelingResults* labelingResults = mCanvas->labelingResults(); if ( !labelingResults ) { QgsDebugMsg( QString( "No labeling engine" ) ); return; } QList<QgsLabelPosition> labelPosList = labelingResults->labelsWithinRect( ext ); QList<QgsLabelPosition>::const_iterator it; for ( it = labelPosList.constBegin() ; it != labelPosList.constEnd(); ++it ) { mCurrentLabelPos = *it; #ifdef QGISDEBUG QString labellyr = currentLayer()->name(); QString labeltxt = currentLabelText(); #endif QgsDebugMsg( QString( "Layer: %0" ).arg( labellyr ) ); QgsDebugMsg( QString( "Label: %0" ).arg( labeltxt ) ); QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID ); if ( !layer ) { QgsDebugMsg( QString( "Failed to get label layer" ) ); continue; } QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer ); if ( !vlayer ) { QgsDebugMsg( QString( "Failed to cast label layer to vector layer" ) ); continue; } if ( !vlayer->isEditable() ) { QgsDebugMsg( QString( "Vector layer not editable, skipping label" ) ); continue; } QString labelStringID = QString( "%0|%1" ).arg( mCurrentLabelPos.layerID, QString::number( mCurrentLabelPos.featureId ) ); // unpin label if ( mCurrentLabelPos.isPinned && ( doUnpin || toggleUnpinOrPin ) ) { // unpin previously pinned label (set attribute table fields to NULL) if ( pinUnpinLabel( vlayer, mCurrentLabelPos, false ) ) { labelChanged = true; } else { QgsDebugMsg( QString( "Unpin failed for layer, label: %0, %1" ).arg( labellyr, labeltxt ) ); } } // pin label if ( !mCurrentLabelPos.isPinned && ( !doUnpin || toggleUnpinOrPin ) ) { // pin label's location, and optionally rotation, to attribute table if ( pinUnpinLabel( vlayer, mCurrentLabelPos, true ) ) { labelChanged = true; } else { QgsDebugMsg( QString( "Pin failed for layer, label: %0, %1" ).arg( labellyr, labeltxt ) ); } } } if ( labelChanged ) { mCanvas->refresh(); if ( !mShowPinned ) { // toggle it on (pin-unpin tool doesn't work well without it) QgisApp::instance()->actionShowPinnedLabels()->setChecked( true ); } } }
bool QgsMapToolLabel::rotationPoint( QgsPoint& pos, bool ignoreUpsideDown ) { QVector<QgsPoint> cornerPoints = mCurrentLabelPos.cornerPoints; if ( cornerPoints.size() < 4 ) { return false; } if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos = mCurrentLabelPos.cornerPoints.at( 2 ); } else { pos = mCurrentLabelPos.cornerPoints.at( 0 ); } //alignment always center/center and rotation 0 for diagrams if ( mCurrentLabelPos.isDiagram ) { pos.setX( pos.x() + mCurrentLabelPos.labelRect.width() / 2.0 ); pos.setY( pos.y() + mCurrentLabelPos.labelRect.height() / 2.0 ); return true; } //adapt pos depending on data defined alignment QString haliString, valiString; currentAlignment( haliString, valiString ); if ( !mCurrentLabelPos.isPinned ) { haliString = "Center"; valiString = "Half"; } QFont labelFont = labelFontCurrentFeature(); QFontMetricsF labelFontMetrics( labelFont ); //label text? QString labelText = currentLabelText(); bool labelSettingsOk; QgsPalLayerSettings& labelSettings = currentLabelSettings( &labelSettingsOk ); if ( !labelSettingsOk ) { return false; } double labelSizeX, labelSizeY; labelSettings.calculateLabelSize( &labelFontMetrics, labelText, labelSizeX, labelSizeY ); double xdiff = 0; double ydiff = 0; if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX / 2.0; } else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX; } if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY; } else { double descentRatio = 1 / labelFontMetrics.ascent() / labelFontMetrics.height(); if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * descentRatio; } else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * descentRatio; ydiff = labelSizeY * 0.5 * ( 1 - descentRatio ); } } double angle = mCurrentLabelPos.rotation; double xd = xdiff * cos( angle ) - ydiff * sin( angle ); double yd = xdiff * sin( angle ) + ydiff * cos( angle ); if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos.setX( pos.x() - xd ); pos.setY( pos.y() - yd ); } else { pos.setX( pos.x() + xd ); pos.setY( pos.y() + yd ); } return true; }
void QgsMapToolChangeLabelProperties::applyChanges( const QgsAttributeMap& changes ) { QgsVectorLayer* vlayer = mCurrentLabel.layer; if ( !vlayer ) return; if ( !changes.isEmpty() ) { vlayer->beginEditCommand( tr( "Changed properties for label" ) + QStringLiteral( " '%1'" ).arg( currentLabelText( 24 ) ) ); QgsAttributeMap::const_iterator changeIt = changes.constBegin(); for ( ; changeIt != changes.constEnd(); ++changeIt ) { vlayer->changeAttributeValue( mCurrentLabel.pos.featureId, changeIt.key(), changeIt.value() ); } vlayer->endEditCommand(); vlayer->triggerRepaint(); } }