QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsformannotation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsformannotation.cpp
3  ------------------------
4  begin : February 26, 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco dot hugentobler at hugis dot net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsformannotation.h"
21 #include "qgseditorwidgetwrapper.h"
22 #include "qgsfeature.h"
23 #include "qgsfeatureiterator.h"
24 #include "qgslogger.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsproject.h"
27 #include "qgsmaptool.h"
28 #include "qgsvectorlayer.h"
29 #include "qgsgui.h"
30 #include <QDomElement>
31 #include <QDir>
32 #include <QFile>
33 #include <QFileInfo>
34 #include <QGraphicsProxyWidget>
35 #include <QPainter>
36 #include <QSettings>
37 #include <QUiLoader>
38 #include <QWidget>
39 
41  : QgsAnnotation( parent )
42 {}
43 
45 {
46  std::unique_ptr< QgsFormAnnotation > c( new QgsFormAnnotation() );
47  copyCommonProperties( c.get() );
48  c->setDesignerForm( mDesignerForm );
49  return c.release();
50 }
51 
52 void QgsFormAnnotation::setDesignerForm( const QString &uiFile )
53 {
54  mDesignerForm = uiFile;
55  mDesignerWidget.reset( createDesignerWidget( uiFile ) );
56  if ( mDesignerWidget )
57  {
58  mMinimumSize = mDesignerWidget->minimumSize();
59  if ( auto *lFillSymbol = fillSymbol() )
60  {
61  QgsFillSymbol *newFill = lFillSymbol->clone();
62  newFill->setColor( mDesignerWidget->palette().color( QPalette::Window ) );
63  setFillSymbol( newFill );
64  }
65  // convert from size in pixels at 96 dpi to mm
66  setFrameSizeMm( preferredFrameSize() / 3.7795275 );
67  }
68  emit appearanceChanged();
69 }
70 
71 QWidget *QgsFormAnnotation::createDesignerWidget( const QString &filePath )
72 {
73  QFile file( filePath );
74  if ( !file.open( QFile::ReadOnly ) )
75  {
76  return nullptr;
77  }
78 
79  QUiLoader loader;
80  QFileInfo fi( file );
81  loader.setWorkingDirectory( fi.dir() );
82  QWidget *widget = loader.load( &file, nullptr );
83  file.close();
84 
85  //get feature and set attribute information
87  QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer * >( mapLayer() );
88  if ( vectorLayer && associatedFeature().isValid() )
89  {
90  QgsFields fields = vectorLayer->fields();
92  for ( int i = 0; i < attrs.count(); ++i )
93  {
94  if ( i < fields.count() )
95  {
96  QWidget *attWidget = widget->findChild<QWidget *>( fields.at( i ).name() );
97  if ( attWidget )
98  {
99  QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vectorLayer, i, attWidget, widget, context );
100  if ( eww )
101  {
102  const QStringList additionalFields = eww->additionalFields();
103  QVariantList additionalFieldValues;
104  for ( const QString &additionalField : additionalFields )
105  {
106  int index = vectorLayer->fields().indexFromName( additionalField );
107  additionalFieldValues.insert( index, attrs.at( index ) );
108  }
109  eww->setValues( attrs.at( i ), additionalFieldValues );
110  }
111  }
112  }
113  }
114  }
115  return widget;
116 }
117 
118 void QgsFormAnnotation::renderAnnotation( QgsRenderContext &context, QSizeF size ) const
119 {
120  if ( !mDesignerWidget )
121  return;
122 
123  // scale painter back to 96 dpi, so that forms look good even in layout prints
124  QgsScopedQPainterState painterState( context.painter() );
125  const double scaleFactor = context.painter()->device()->logicalDpiX() / 96.0;
126  context.painter()->scale( scaleFactor, scaleFactor );
127  size /= scaleFactor;
128 
129  mDesignerWidget->setFixedSize( size.toSize() );
130  context.painter()->setBrush( Qt::NoBrush );
131  context.painter()->setPen( Qt::NoPen );
132  mDesignerWidget->render( context.painter(), QPoint( 0, 0 ) );
133 }
134 
136 {
137  if ( mDesignerWidget )
138  {
139  QSizeF widgetMinSize = mMinimumSize;
140  return QSizeF( contentsMargin().left() + contentsMargin().right() + widgetMinSize.width(),
141  contentsMargin().top() + contentsMargin().bottom() + widgetMinSize.height() );
142  }
143  else
144  {
145  return QSizeF( 0, 0 );
146  }
147 }
148 
150 {
151  if ( mDesignerWidget )
152  {
153  return mDesignerWidget->sizeHint();
154  }
155  else
156  {
157  return QSizeF( 0, 0 );
158  }
159 }
160 
161 void QgsFormAnnotation::writeXml( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const
162 {
163  QDomElement formAnnotationElem = doc.createElement( QStringLiteral( "FormAnnotationItem" ) );
164  formAnnotationElem.setAttribute( QStringLiteral( "designerForm" ), mDesignerForm );
165  _writeXml( formAnnotationElem, doc, context );
166  elem.appendChild( formAnnotationElem );
167 }
168 
169 void QgsFormAnnotation::readXml( const QDomElement &itemElem, const QgsReadWriteContext &context )
170 {
171  mDesignerForm = itemElem.attribute( QStringLiteral( "designerForm" ), QString() );
172  QDomElement annotationElem = itemElem.firstChildElement( QStringLiteral( "AnnotationItem" ) );
173  if ( !annotationElem.isNull() )
174  {
175  _readXml( annotationElem, context );
176  }
177  // upgrade old layer
178  if ( !mapLayer() && itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
179  {
180  setMapLayer( QgsProject::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ) ) ) );
181  }
182 
183  mDesignerWidget.reset( createDesignerWidget( mDesignerForm ) );
184  if ( mDesignerWidget && fillSymbol() )
185  {
186  QgsFillSymbol *newFill = fillSymbol()->clone();
187  newFill->setColor( mDesignerWidget->palette().color( QPalette::Window ) );
188  setFillSymbol( newFill );
189  }
190 }
191 
193 {
195 
196  //create new embedded widget
197  mDesignerWidget.reset( createDesignerWidget( mDesignerForm ) );
198  if ( mDesignerWidget && fillSymbol() )
199  {
200  QgsFillSymbol *newFill = fillSymbol()->clone();
201  newFill->setColor( mDesignerWidget->palette().color( QPalette::Window ) );
202  setFillSymbol( newFill );
203  }
204  emit appearanceChanged();
205 }
206 
207 
208 
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:52
void appearanceChanged()
Emitted whenever the annotation's appearance changes.
void setFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for rendering the annotation frame.
QgsMapLayer * mapLayer() const
Returns the map layer associated with the annotation.
QgsMargins contentsMargin() const
Returns the margins (in millimeters) between the outside of the frame and the annotation content.
QgsFillSymbol * fillSymbol() const
Returns the symbol that is used for rendering the annotation frame.
void _writeXml(QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes common annotation properties to a DOM element.
void setFrameSizeMm(QSizeF size)
Sets the size (in millimeters) of the annotation's frame (the main area in which the annotation's con...
virtual void setAssociatedFeature(const QgsFeature &feature)
Sets the feature associated with the annotation.
QgsFeature associatedFeature() const
Returns the feature associated with the annotation, or an invalid feature if none has been set.
void _readXml(const QDomElement &annotationElem, const QgsReadWriteContext &context)
Reads common annotation properties from a DOM element.
void copyCommonProperties(QgsAnnotation *target) const
Copies common annotation properties to the targe annotation.
void setMapLayer(QgsMapLayer *layer)
Sets the map layer associated with the annotation.
This class contains context information for attribute editor widgets.
A vector of attributes.
Definition: qgsattributes.h:58
QgsEditorWidgetWrapper * create(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Create an attribute editor widget wrapper of a given type for a given field.
Manages an editor widget Widget and wrapper share the same parent.
virtual QStringList additionalFields() const
Returns the list of additional fields which the editor handles.
void setValues(const QVariant &value, const QVariantList &additionalValues)
Is called when the value of the widget or additional field values needs to be changed.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1307
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2422
An annotation item that embeds a designer form showing the feature attribute.
QgsFormAnnotation * clone() const override
Clones the annotation, returning a new copy of the annotation reflecting the annotation's current sta...
void renderAnnotation(QgsRenderContext &context, QSizeF size) const override
Renders the annotation's contents to a target /a context at the specified /a size.
QgsFormAnnotation(QObject *parent=nullptr)
Constructor for QgsFormAnnotation.
void setAssociatedFeature(const QgsFeature &feature) override
Sets the feature associated with the annotation.
void writeXml(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes the annotation state to a DOM element.
void readXml(const QDomElement &itemElem, const QgsReadWriteContext &context) override
Restores the annotation's state from a DOM element.
QSizeF minimumFrameSize() const override
Returns the minimum frame size for the annotation.
void setDesignerForm(const QString &uiFile)
Sets the path to the Qt Designer UI file to show in the annotation.
QSizeF preferredFrameSize() const
Returns the optimal frame size.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition: qgsgui.cpp:76
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
Scoped object for saving and restoring a QPainter object's state.
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:532
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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