29#include <qgraphicssceneevent.h>
31#include "moc_qgsmaptoolextraitem.cpp"
85 QPointer<QgsVectorLayer> mLayer;
118 QgsSymbolLayerUtils::ExtraItems extraItems = QgsSymbolLayerUtils::parseExtraItems( currentExtraItems, error );
119 if ( !error.isEmpty() )
127 for ( std::pair<QPointF, double> extraItem : extraItems )
139 QStringList strExtraItems;
146 QString strNewExtraItems = strExtraItems.join(
"," );
148 mLayer->beginEditCommand( tr(
"Set extra item list" ) );
156 mLayer->destroyEditCommand();
170 messageEmitted( tr(
"No feature was detected at the clicked position. Please click closer to the feature or enhance the search tolerance under Settings->Options->Digitizing->Search radius for vertex edits" ),
Qgis::MessageLevel::Critical );
183 if ( !
mLayer->auxiliaryLayer() )
189 if ( !
mLayer->auxiliaryLayer() )
195 emit
messageEmitted( tr(
"Failed to create extra item auxiliary field for layer '%1'" ).arg(
mLayer->name() ) );
210 if ( !usesAuxFields && !
mLayer->isEditable() )
212 if (
mLayer->startEditing() )
218 emit
messageEmitted( tr(
"Cannot modify extra items — the layer “%1” could not be made editable" ).arg(
mLayer->name() ) );
239 if ( !
mLayer || e->button() != Qt::LeftButton )
268 if ( event->matches( QKeySequence::StandardKey::Cancel ) )
282 : QgsGraphicsViewMouseHandles( canvas )
283 , mMapTool( mapTool )
289 mCanvas->scene()->addItem(
this );
291 setRotationEnabled(
true );
292 setResizeEnabled(
false );
295void QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::paint( QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget )
297 paintInternal( painter,
true,
true,
true, option, widget );
300void QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::setViewportCursor( Qt::CursorShape cursor )
304 mCanvas->viewport()->setCursor( cursor );
308QList<QGraphicsItem *> QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::sceneItemsAtPoint( QPointF scenePoint )
310 QList<QGraphicsItem *> graphicsItems;
311 const QList<QGraphicsItem *> items = mMapTool->selectedItems();
312 for (
auto item : items )
314 if ( item->sceneBoundingRect().contains( scenePoint ) )
316 graphicsItems << item;
319 return graphicsItems;
322QList<QGraphicsItem *> QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::selectedSceneItems(
bool )
const
324 return mMapTool->selectedItems();
327QRectF QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::itemRect( QGraphicsItem *item )
const
329 return item->boundingRect();
332void QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::moveItem( QGraphicsItem *item,
double deltaX,
double deltaY )
334 mMapTool->attemptMoveBy( item, deltaX, deltaY );
337void QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::rotateItem( QGraphicsItem *item,
double deltaDegree,
double deltaCenterX,
double deltaCenterY )
339 mMapTool->attemptRotateBy( item, deltaDegree, deltaCenterX, deltaCenterY );
342void QgsMapToolModifyExtraItems::QgsMapToolModifyExtraItemMouseHandles::setItemRect( QGraphicsItem *, QRectF )
354 , mSymbolLayer( symbolLayer )
356 setFlags( flags() | QGraphicsItem::ItemIsSelectable );
358 setWidth( mapCanvas->fontMetrics().xHeight() * .2 );
409 const double length = renderContext.
convertToPainterUnits( slHashedLine->hashLength(), slHashedLine->hashLengthUnit() );
410 const double width =
symbol->width( renderContext );
419 QTransform t = QTransform().translate( canvasPoint.x(), canvasPoint.y() ).rotate( mRotation ).translate( -canvasPoint.x(), -canvasPoint.y() );
422 bool selected = isSelected();
425 for (
int i = 0; i < bounds.count(); i++ )
427 QPointF canvasPt = bounds.at( i );
429 addPoint( mapPt, i == bounds.count() - 1 );
433 setSelected( selected );
442 mToolName = tr(
"Extra item modify tool" );
461 return mSelectedItems;
466 if ( !
mLayer || e->button() != Qt::LeftButton )
473 mMouseHandles.reset(
new QgsMapToolModifyExtraItemMouseHandles(
this,
mCanvas ) );
478 const bool toggleSelection = e->modifiers() & Qt::ShiftModifier;
479 QPointF scenePos =
mCanvas->mapToScene( e->pos() );
480 if ( !toggleSelection && !mSelectedItems.empty() && mMouseHandles->sceneBoundingRect().contains( scenePos ) )
482 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMousePress );
483 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
484 forwardedEvent.setScenePos( scenePos );
485 forwardedEvent.setLastScenePos(
mCanvas->mapToScene( mLastPos ) );
486 forwardedEvent.setButton( Qt::LeftButton );
487 mMouseHandles->mousePressEvent( &forwardedEvent );
491 mSelectionRect.setTopLeft( e->pos() );
492 mSelectionRect.setBottomRight( e->pos() );
514 const QPointF scenePos =
mCanvas->mapToScene( event->pos() );
515 if ( event->buttons() == Qt::NoButton )
517 if ( mMouseHandles->sceneBoundingRect().contains( scenePos ) )
519 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverMove );
520 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
521 forwardedEvent.setScenePos( scenePos );
522 mMouseHandles->hoverMoveEvent( &forwardedEvent );
523 mHoveringMouseHandles =
true;
525 else if ( mHoveringMouseHandles )
527 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverLeave );
528 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
529 forwardedEvent.setScenePos( scenePos );
530 mMouseHandles->hoverMoveEvent( &forwardedEvent );
531 mHoveringMouseHandles =
false;
534 else if ( event->buttons() == Qt::LeftButton )
536 if ( mMouseHandles->shouldBlockEvent( event ) )
538 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
539 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
540 forwardedEvent.setScenePos( scenePos );
541 forwardedEvent.setLastScenePos(
mCanvas->mapToScene( mLastPos ) );
542 forwardedEvent.setButton( Qt::LeftButton );
543 mMouseHandles->mouseMoveEvent( &forwardedEvent );
551 QColor color( Qt::blue );
552 color.setAlpha( 63 );
553 mSelectionRubberBand->setColor( color );
554 mSelectionRect.setTopLeft( event->pos() );
557 mSelectionRect.setBottomRight( event->pos() );
558 if ( mSelectionRubberBand )
560 mSelectionRubberBand->setToCanvasRectangle( mSelectionRect );
561 mSelectionRubberBand->show();
565 mLastPos =
event->pos();
573 if ( !
mLayer || event->button() != Qt::LeftButton )
582 if ( mMouseHandles && mMouseHandles->shouldBlockEvent( event ) )
584 const QPointF scenePos =
mCanvas->mapToScene( event->pos() );
585 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseRelease );
586 forwardedEvent.setPos( event->pos() );
587 forwardedEvent.setScenePos( scenePos );
588 forwardedEvent.setLastScenePos(
mCanvas->mapToScene( mLastPos ) );
589 forwardedEvent.setButton( Qt::LeftButton );
590 mMouseHandles->mouseReleaseEvent( &forwardedEvent );
604 mSelectionRubberBand.reset();
607 bool selectedItemsHasChanged =
false;
608 if ( !( event->modifiers() & Qt::ShiftModifier ) )
610 selectedItemsHasChanged =
true;
611 mSelectedItems.clear();
614 extraItem->setSelected(
false );
620 QRectF rect = extraItem->boundingRect();
621 rect.translate( extraItem->pos().x(), extraItem->pos().y() );
622 const bool isSelected = rect.intersects( mSelectionRect );
623 selectedItemsHasChanged |= ( isSelected != extraItem->isSelected() );
624 extraItem->setSelected( isSelected );
628 mSelectedItems << extraItem;
632 if ( selectedItemsHasChanged )
635 mMouseHandles->setSelected( !mSelectedItems.empty() );
649 if ( event->matches( QKeySequence::StandardKey::Cancel ) )
651 if ( !mSelectedItems.empty() )
653 mSelectedItems.clear();
654 mMouseHandles->updateHandles();
668 if ( event->key() == Qt::Key_V )
670 const QPointF delta = mLastPos - mCopiedItemsTopLeft;
671 mSelectedItems.clear();
672 for (
const std::tuple<double, double, double> &extraItem : std::as_const( mCopiedItems ) )
675 newRubberBand->setSelected(
true );
677 mSelectedItems << newRubberBand;
681 mMouseHandles->updateHandles();
686 if ( mSelectedItems.empty() )
689 if ( event->key() == Qt::Key_C || event->key() == Qt::Key_X )
691 mCopiedItems.clear();
692 for ( QGraphicsItem *extraItem : std::as_const( mSelectedItems ) )
697 mCopiedItemsTopLeft = mMouseHandles->sceneBoundingRect().topLeft();
700 else if ( event->key() == Qt::Key_Left || event->key() == Qt::Key_Right || event->key() == Qt::Key_Up || event->key() == Qt::Key_Down )
702 const int pixels = (
event->modifiers() & Qt::ShiftModifier ) ? 1 : 50;
705 if ( event->key() == Qt::Key_Up )
709 else if ( event->key() == Qt::Key_Down )
713 else if ( event->key() == Qt::Key_Left )
717 else if ( event->key() == Qt::Key_Right )
722 for ( QGraphicsItem *extraItem : mSelectedItems )
726 mMouseHandles->updateHandles();
731 if ( event->matches( QKeySequence::StandardKey::Delete ) || event->key() == Qt::Key_X )
733 for ( QGraphicsItem *extraItem : mSelectedItems )
739 mSelectedItems.clear();
741 mMouseHandles->updateHandles();
747QgsPointXY QgsMapToolModifyExtraItems::movePosition(
const QgsPointXY &position,
double deltaX,
double deltaY )
const
750 QgsVector translation( deltaX * mupp, -deltaY * mupp );
753 mapPoint += translation;
768 rubberBand->
setPosition( movePosition( rubberBand->
position(), deltaCenterX, deltaCenterY ) );
769 rubberBand->
setRotation( std::fmod( rubberBand->
rotation() + deltaDegree + 360., 360.0 ) );
773void QgsMapToolModifyExtraItems::onMapCanvasExtentsChanged()
781 mMouseHandles->updateHandles();
Keeps a pointer to a QObject and deletes it whenever this object is deleted.
@ Critical
Critical/error message.
@ Join
Field originates from a joined layer.
static int createProperty(QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer, bool overwriteExisting=true)
Creates if necessary a new auxiliary field for a PAL property and activates this property in settings...
Rubber band for one extra item.
double rotation() const
Returns rotation angle in degree between 0 and 360.
void setPosition(QgsPointXY position)
Set extra item position in layer coordinates.
const QgsPointXY & position() const
Returns position in layer CRS.
void setRotation(double rotation)
Set extra item rotation around its center.
QgsExtraItemRubberBand(QgsPointXY position, double rotation, QgsMapCanvas *mapCanvas, QgsVectorLayer *layer, QgsTemplatedLineSymbolLayerBase *symbolLayer)
Constructor.
void update()
Update item according to its current rotation angle and position.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Line symbol layer type which draws repeating line sections along a line feature.
A line symbol type, for rendering LineString and MultiLineString geometries.
QRectF boundingRect() const override
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
QgsMapCanvas * mMapCanvas
pointer to map canvas
Map canvas is a class for displaying all GIS data types on a canvas.
void extentsChanged()
Emitted when the extents of the map change.
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer's CRS to output CRS
double mapUnitsPerPixel() const
Returns the distance in geographical coordinates that equals to one pixel in the map.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
Perform transforms between map coordinates and device coordinates.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
A marker symbol type, for rendering Point and MultiPoint geometries.
A dialog to create a new auxiliary layer.
@ Edge
Snapped to an edge.
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
A store for object properties.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Responsible for drawing transient features (e.g.
QgsRubberBand(QgsMapCanvas *mapCanvas, Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Creates a new RubberBand.
void setWidth(double width)
Sets the width of the line.
void reset(Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Clears all the geometries in this rubberband.
void setStrokeColor(const QColor &color)
Sets the stroke color for the rubberband.
QgsSymbol * symbol() const
Returns the symbol used for rendering the rubberband, if set.
void setFillColor(const QColor &color)
Sets the fill color for the rubberband.
void addPoint(const QgsPointXY &p, bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Adds a vertex to the rubberband and update canvas.
@ ExtraItems
String list of tuple (x, y and rotation angle) to define extra items to be rendered for templated lin...
Base class for templated line symbols, e.g.
Represents a vector layer which manages a vector based dataset.
Represent a 2-dimensional vector.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
#define QgsDebugError(str)
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.