1 /***************************************************************************
2 qgslayoutapputils.cpp
3 ---------------------
4 Date : October 2017
5 Copyright : (C) 2017 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgslayoutguiutils.h"
17 #include "qgsgui.h"
18 #include "qgslayout.h"
19 #include "qgslayoutitemguiregistry.h"
20 #include "qgslayoutitemregistry.h"
21 #include "qgslayoutviewrubberband.h"
22 #include "qgslayoutitemshape.h"
23 #include "qgslayoutmapwidget.h"
24 #include "qgslayoutshapewidget.h"
25 #include "qgslayoutmarkerwidget.h"
26 #include "qgslayoutitemmap.h"
27 #include "qgslayoutitempolygon.h"
28 #include "qgslayoutitempolyline.h"
29 #include "qgslayoutitemmarker.h"
30 #include "qgslayoutpolygonwidget.h"
31 #include "qgslayoutpolylinewidget.h"
32 #include "qgslayoutpicturewidget.h"
33 #include "qgslayoutitempicture.h"
34 #include "qgslayoutitemlabel.h"
35 #include "qgslayoutlabelwidget.h"
36 #include "qgslayoutitemlegend.h"
37 #include "qgslayoutitemscalebar.h"
38 #include "qgslayoutlegendwidget.h"
39 #include "qgslayoutframe.h"
40 #include "qgslayoutitemhtml.h"
41 #include "qgslayouthtmlwidget.h"
42 #include "qgslayoutscalebarwidget.h"
43 #include "qgslayoutitemattributetable.h"
44 #include "qgslayoutattributetablewidget.h"
45 #include "qgslayoutitemmanualtable.h"
46 #include "qgslayoutmanualtablewidget.h"
47 #include "qgsmapcanvas.h"
48
49 /**
50 * Attempts to find the best guess at a map item to link \a referenceItem to,
51 * by:
52 *
53 * # Prioritizing a selected map
54 * # If no selection, prioritizing the topmost map the item was drawn over
55 * # If still none, use the layout's reference map (or biggest map)
56 */
findSensibleDefaultLinkedMapItem(QgsLayoutItem * referenceItem)57 QgsLayoutItemMap *findSensibleDefaultLinkedMapItem( QgsLayoutItem *referenceItem )
58 {
59 // start by trying to find a selected map
60 QList<QgsLayoutItemMap *> mapItems;
61 referenceItem->layout()->layoutItems( mapItems );
62
63 QgsLayoutItemMap *targetMap = nullptr;
64 for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
65 {
66 if ( map->isSelected() )
67 {
68 return map;
69 }
70 }
71
72 // nope, no selection... hm, was the item drawn over a map? If so, use the topmost intersecting one
73 double largestZValue = std::numeric_limits< double >::lowest();
74 for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
75 {
76 if ( map->collidesWithItem( referenceItem ) && map->zValue() > largestZValue )
77 {
78 targetMap = map;
79 largestZValue = map->zValue();
80 }
81 }
82 if ( targetMap )
83 return targetMap;
84
85 // ah frick it, just use the reference (or biggest!) map
86 return referenceItem->layout()->referenceMap();
87 }
88
registerGuiForKnownItemTypes(QgsMapCanvas * mapCanvas)89 void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
90 {
91 QgsLayoutItemGuiRegistry *registry = QgsGui::layoutItemGuiRegistry();
92
93 registry->addItemGroup( QgsLayoutItemGuiGroup( QStringLiteral( "shapes" ), QObject::tr( "Shape" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicShape.svg" ) ) ) );
94 registry->addItemGroup( QgsLayoutItemGuiGroup( QStringLiteral( "nodes" ), QObject::tr( "Node Item" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddNodesItem.svg" ) ) ) );
95
96 auto createRubberBand = ( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
97 {
98 return new QgsLayoutViewRectangularRubberBand( view );
99 } );
100 auto createEllipseBand = ( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
101 {
102 return new QgsLayoutViewEllipticalRubberBand( view );
103 } );
104 auto createTriangleBand = ( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
105 {
106 return new QgsLayoutViewTriangleRubberBand( view );
107 } );
108
109 #if 0
110 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutItem + 1002, QStringLiteral( "test" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), nullptr, createRubberBand ) );
111 #endif
112
113 // map item
114
115 auto mapItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutMap, QObject::tr( "Map" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddMap.svg" ) ),
116 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
117 {
118 return new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ), mapCanvas );
119 }, createRubberBand );
120 mapItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
121 {
122 QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( item );
123 Q_ASSERT( map );
124
125 //get the color for map canvas background and set map background color accordingly
126 map->setBackgroundColor( QgsProject::instance()->backgroundColor() );
127
128 if ( mapCanvas )
129 {
130 map->zoomToExtent( mapCanvas->mapSettings().visibleExtent() );
131 }
132
133 // auto assign a unique id to map items
134 QList<QgsLayoutItemMap *> mapsList;
135 if ( map->layout() )
136 map->layout()->layoutItems( mapsList );
137
138 int counter = mapsList.size() + 1;
139 bool existing = false;
140 while ( true )
141 {
142 existing = false;
143 for ( QgsLayoutItemMap *otherMap : qgis::as_const( mapsList ) )
144 {
145 if ( map == otherMap )
146 continue;
147
148 if ( otherMap->id() == QObject::tr( "Map %1" ).arg( counter ) )
149 {
150 existing = true;
151 break;
152 }
153 }
154 if ( existing )
155 counter++;
156 else
157 break;
158 }
159 map->setId( QObject::tr( "Map %1" ).arg( counter ) );
160 } );
161 registry->addLayoutItemGuiMetadata( mapItemMetadata.release() );
162
163 // picture item
164
165 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPicture, QObject::tr( "Picture" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ),
166 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
167 {
168 return new QgsLayoutPictureWidget( qobject_cast< QgsLayoutItemPicture * >( item ) );
169 }, createRubberBand ) );
170
171
172 // label item
173
174 auto labelItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutLabel, QObject::tr( "Label" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionLabel.svg" ) ),
175 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
176 {
177 return new QgsLayoutLabelWidget( qobject_cast< QgsLayoutItemLabel * >( item ) );
178 }, createRubberBand );
179 labelItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
180 {
181 QgsLayoutItemLabel *label = qobject_cast< QgsLayoutItemLabel * >( item );
182 Q_ASSERT( label );
183
184 label->setText( QObject::tr( "Lorem ipsum" ) );
185 if ( QApplication::isRightToLeft() )
186 {
187 label->setHAlign( Qt::AlignRight );
188 }
189 QSizeF minSize = label->sizeForText();
190 QSizeF currentSize = label->rect().size();
191
192 //make sure label size is sufficient to fit text
193 double labelWidth = std::max( minSize.width(), currentSize.width() );
194 double labelHeight = std::max( minSize.height(), currentSize.height() );
195 label->attemptSetSceneRect( QRectF( label->pos().x(), label->pos().y(), labelWidth, labelHeight ) );
196 } );
197
198 registry->addLayoutItemGuiMetadata( labelItemMetadata.release() );
199
200
201 // legend item
202
203 auto legendItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutLegend, QObject::tr( "Legend" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLegend.svg" ) ),
204 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
205 {
206 return new QgsLayoutLegendWidget( qobject_cast< QgsLayoutItemLegend * >( item ), mapCanvas );
207 }, createRubberBand );
208 legendItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
209 {
210 QgsLayoutItemLegend *legend = qobject_cast< QgsLayoutItemLegend * >( item );
211 Q_ASSERT( legend );
212
213 // try to find a good map to link the legend with by default
214 legend->setLinkedMap( findSensibleDefaultLinkedMapItem( legend ) );
215
216 if ( QApplication::isRightToLeft() )
217 {
218 // for right-to-left locales, use an appropriate default layout
219 legend->setSymbolAlignment( Qt::AlignRight );
220 legend->rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignRight );
221 legend->rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignRight );
222 legend->rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignRight );
223 legend->setTitleAlignment( Qt::AlignRight );
224 }
225
226 //set default legend font from settings
227 QgsSettings settings;
228 const QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
229 if ( !defaultFontString.isEmpty() )
230 {
231 legend->rstyle( QgsLegendStyle::Title ).rfont().setFamily( defaultFontString );
232 legend->rstyle( QgsLegendStyle::Group ).rfont().setFamily( defaultFontString );
233 legend->rstyle( QgsLegendStyle::Subgroup ).rfont().setFamily( defaultFontString );
234 legend->rstyle( QgsLegendStyle::SymbolLabel ).rfont().setFamily( defaultFontString );
235 }
236
237 legend->updateLegend();
238 } );
239
240 registry->addLayoutItemGuiMetadata( legendItemMetadata.release() );
241
242 // scalebar item
243
244 auto scalebarItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutScaleBar, QObject::tr( "Scale Bar" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionScaleBar.svg" ) ),
245 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
246 {
247 return new QgsLayoutScaleBarWidget( qobject_cast< QgsLayoutItemScaleBar * >( item ) );
248 }, createRubberBand );
249 scalebarItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
250 {
251 QgsLayoutItemScaleBar *scalebar = qobject_cast< QgsLayoutItemScaleBar * >( item );
252 Q_ASSERT( scalebar );
253
254 // try to find a good map to link the scalebar with by default
255 if ( QgsLayoutItemMap *targetMap = findSensibleDefaultLinkedMapItem( scalebar ) )
256 {
257 scalebar->setLinkedMap( targetMap );
258 scalebar->applyDefaultSize( scalebar->guessUnits() );
259 }
260 } );
261
262 registry->addLayoutItemGuiMetadata( scalebarItemMetadata.release() );
263
264
265 // north arrow
266 std::unique_ptr< QgsLayoutItemGuiMetadata > northArrowMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata>(
267 QgsLayoutItemRegistry::LayoutPicture, QObject::tr( "North Arrow" ), QgsApplication::getThemeIcon( QStringLiteral( "/north_arrow.svg" ) ),
268 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
269 {
270 return new QgsLayoutPictureWidget( qobject_cast< QgsLayoutItemPicture * >( item ) );
271 }, createRubberBand );
272 northArrowMetadata->setItemCreationFunction( []( QgsLayout * layout )->QgsLayoutItem *
273 {
274
275 // count how many existing north arrows are already in layout
276 QList< QgsLayoutItemPicture * > pictureItems;
277 layout->layoutItems( pictureItems );
278 int northArrowCount = 0;
279
280 QgsSettings settings;
281 const QString defaultPath = settings.value( QStringLiteral( "LayoutDesigner/defaultNorthArrow" ), QStringLiteral( ":/images/north_arrows/layout_default_north_arrow.svg" ), QgsSettings::Gui ).toString();
282
283 for ( QgsLayoutItemPicture *p : qgis::as_const( pictureItems ) )
284 {
285 // look for pictures which use the default north arrow svg
286 if ( p->picturePath() == defaultPath )
287 northArrowCount++;
288 }
289
290 std::unique_ptr< QgsLayoutItemPicture > picture = qgis::make_unique< QgsLayoutItemPicture >( layout );
291 picture->setNorthMode( QgsLayoutItemPicture::GridNorth );
292 picture->setPicturePath( defaultPath );
293 // set an id by default, so that north arrows are discernible in layout item lists
294 picture->setId( northArrowCount > 0 ? QObject::tr( "North Arrow %1" ).arg( northArrowCount + 1 ) : QObject::tr( "North Arrow" ) );
295 return picture.release();
296 } );
297 northArrowMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
298 {
299 QgsLayoutItemPicture *picture = qobject_cast< QgsLayoutItemPicture * >( item );
300 Q_ASSERT( picture );
301
302 QList<QgsLayoutItemMap *> mapItems;
303 picture->layout()->layoutItems( mapItems );
304
305 // try to find a good map to link the north arrow with by default
306 picture->setLinkedMap( findSensibleDefaultLinkedMapItem( picture ) );
307 } );
308 registry->addLayoutItemGuiMetadata( northArrowMetadata.release() );
309
310 // shape items
311
312 auto createShapeWidget =
313 []( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
314 {
315 return new QgsLayoutShapeWidget( qobject_cast< QgsLayoutItemShape * >( item ) );
316 };
317
318 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), createShapeWidget, createRubberBand, QStringLiteral( "shapes" ), false, QgsLayoutItemAbstractGuiMetadata::Flags(), []( QgsLayout * layout )->QgsLayoutItem*
319 {
320 std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
321 shape->setShapeType( QgsLayoutItemShape::Rectangle );
322 return shape.release();
323 } ) );
324 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), createShapeWidget, createEllipseBand, QStringLiteral( "shapes" ), false, QgsLayoutItemAbstractGuiMetadata::Flags(), []( QgsLayout * layout )->QgsLayoutItem*
325 {
326 std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
327 shape->setShapeType( QgsLayoutItemShape::Ellipse );
328 return shape.release();
329 } ) );
330 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), createShapeWidget, createTriangleBand, QStringLiteral( "shapes" ), false, QgsLayoutItemAbstractGuiMetadata::Flags(), []( QgsLayout * layout )->QgsLayoutItem*
331 {
332 std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
333 shape->setShapeType( QgsLayoutItemShape::Triangle );
334 return shape.release();
335 } ) );
336
337 // marker
338 registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutMarker, QObject::tr( "Marker" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddMarker.svg" ) ),
339 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
340 {
341 return new QgsLayoutMarkerWidget( qobject_cast< QgsLayoutItemMarker * >( item ) );
342 }, nullptr ) );
343
344 // arrow
345 std::unique_ptr< QgsLayoutItemGuiMetadata > arrowMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata>(
346 QgsLayoutItemRegistry::LayoutPolyline, QObject::tr( "Arrow" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddArrow.svg" ) ),
347 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
348 {
349 return new QgsLayoutPolylineWidget( qobject_cast< QgsLayoutItemPolyline * >( item ) );
350 }, createRubberBand, QString(), true );
351 arrowMetadata->setItemCreationFunction( []( QgsLayout * layout )->QgsLayoutItem *
352 {
353 std::unique_ptr< QgsLayoutItemPolyline > arrow = qgis::make_unique< QgsLayoutItemPolyline >( layout );
354 arrow->setEndMarker( QgsLayoutItemPolyline::ArrowHead );
355 return arrow.release();
356 } );
357 arrowMetadata->setNodeRubberBandCreationFunction( []( QgsLayoutView * )->QGraphicsPathItem*
358 {
359 std::unique_ptr< QGraphicsPathItem > band = qgis::make_unique< QGraphicsPathItem >();
360 band->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
361 band->setZValue( QgsLayout::ZViewTool );
362 return band.release();
363 } );
364 registry->addLayoutItemGuiMetadata( arrowMetadata.release() );
365
366 // node items
367
368 std::unique_ptr< QgsLayoutItemGuiMetadata > polygonMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >(
369 QgsLayoutItemRegistry::LayoutPolygon, QObject::tr( "Polygon" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolygon.svg" ) ),
370 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
371 {
372 return new QgsLayoutPolygonWidget( qobject_cast< QgsLayoutItemPolygon * >( item ) );
373 }, createRubberBand, QStringLiteral( "nodes" ), true );
374 polygonMetadata->setNodeRubberBandCreationFunction( []( QgsLayoutView * )->QGraphicsPolygonItem*
375 {
376 std::unique_ptr< QGraphicsPolygonItem > band = qgis::make_unique< QGraphicsPolygonItem >();
377 band->setBrush( Qt::NoBrush );
378 band->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
379 band->setZValue( QgsLayout::ZViewTool );
380 return band.release();
381 } );
382 registry->addLayoutItemGuiMetadata( polygonMetadata.release() );
383
384 std::unique_ptr< QgsLayoutItemGuiMetadata > polylineMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata>(
385 QgsLayoutItemRegistry::LayoutPolyline, QObject::tr( "Polyline" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ),
386 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
387 {
388 return new QgsLayoutPolylineWidget( qobject_cast< QgsLayoutItemPolyline * >( item ) );
389 }, createRubberBand, QStringLiteral( "nodes" ), true );
390 polylineMetadata->setNodeRubberBandCreationFunction( []( QgsLayoutView * )->QGraphicsPathItem*
391 {
392 std::unique_ptr< QGraphicsPathItem > band = qgis::make_unique< QGraphicsPathItem >();
393 band->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
394 band->setZValue( QgsLayout::ZViewTool );
395 return band.release();
396 } );
397 registry->addLayoutItemGuiMetadata( polylineMetadata.release() );
398
399
400 // html item
401
402 auto htmlItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutHtml, QObject::tr( "HTML" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddHtml.svg" ) ),
403 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
404 {
405 return new QgsLayoutHtmlWidget( qobject_cast< QgsLayoutFrame * >( item ) );
406 }, createRubberBand );
407 htmlItemMetadata->setItemCreationFunction( [ = ]( QgsLayout * layout )->QgsLayoutItem *
408 {
409 std::unique_ptr< QgsLayoutItemHtml > htmlMultiFrame = qgis::make_unique< QgsLayoutItemHtml >( layout );
410 QgsLayoutItemHtml *html = htmlMultiFrame.get();
411 layout->addMultiFrame( htmlMultiFrame.release() );
412 std::unique_ptr< QgsLayoutFrame > frame = qgis::make_unique< QgsLayoutFrame >( layout, html );
413 QgsLayoutFrame *f = frame.get();
414 html->addFrame( frame.release() );
415 return f;
416 } );
417 registry->addLayoutItemGuiMetadata( htmlItemMetadata.release() );
418
419 // attribute table item
420
421 auto attributeTableItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutAttributeTable, QObject::tr( "Attribute Table" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddTable.svg" ) ),
422 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
423 {
424 return new QgsLayoutAttributeTableWidget( qobject_cast< QgsLayoutFrame * >( item ) );
425 }, createRubberBand );
426 attributeTableItemMetadata->setItemCreationFunction( [ = ]( QgsLayout * layout )->QgsLayoutItem *
427 {
428 std::unique_ptr< QgsLayoutItemAttributeTable > tableMultiFrame = qgis::make_unique< QgsLayoutItemAttributeTable >( layout );
429 QgsLayoutItemAttributeTable *table = tableMultiFrame.get();
430
431 //set first vector layer from layer registry as table source
432 QMap<QString, QgsMapLayer *> layerMap = layout->project()->mapLayers();
433 for ( auto it = layerMap.constBegin() ; it != layerMap.constEnd(); ++it )
434 {
435 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
436 {
437 table->setVectorLayer( vl );
438 break;
439 }
440 }
441
442 //set default table fonts from settings
443 QgsSettings settings;
444 const QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
445 if ( !defaultFontString.isEmpty() )
446 {
447 QgsTextFormat format;
448 QFont f = format.font();
449 f.setFamily( defaultFontString );
450 format.setFont( f );
451 tableMultiFrame->setContentTextFormat( format );
452 f.setBold( true );
453 format.setFont( f );
454 tableMultiFrame->setHeaderTextFormat( format );
455 }
456
457 layout->addMultiFrame( tableMultiFrame.release() );
458 std::unique_ptr< QgsLayoutFrame > frame = qgis::make_unique< QgsLayoutFrame >( layout, table );
459 QgsLayoutFrame *f = frame.get();
460 table->addFrame( frame.release() );
461 return f;
462 } );
463 registry->addLayoutItemGuiMetadata( attributeTableItemMetadata.release() );
464
465 // manual table item
466
467 auto manualTableItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutManualTable, QObject::tr( "Fixed Table" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddManualTable.svg" ) ),
468 [ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
469 {
470 return new QgsLayoutManualTableWidget( qobject_cast< QgsLayoutFrame * >( item ) );
471 }, createRubberBand );
472 manualTableItemMetadata->setItemCreationFunction( [ = ]( QgsLayout * layout )->QgsLayoutItem *
473 {
474 std::unique_ptr< QgsLayoutItemManualTable > tableMultiFrame = qgis::make_unique< QgsLayoutItemManualTable >( layout );
475 QgsLayoutItemManualTable *table = tableMultiFrame.get();
476
477 // initially start with a 2x2 empty table
478 QgsTableContents contents;
479 contents << ( QgsTableRow() << QgsTableCell() << QgsTableCell() );
480 contents << ( QgsTableRow() << QgsTableCell() << QgsTableCell() );
481 table->setTableContents( contents );
482
483 //set default table fonts from settings
484 QgsSettings settings;
485 const QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
486 if ( !defaultFontString.isEmpty() )
487 {
488 QgsTextFormat format;
489 QFont f = format.font();
490 f.setFamily( defaultFontString );
491 format.setFont( f );
492 tableMultiFrame->setContentTextFormat( format );
493 f.setBold( true );
494 format.setFont( f );
495 tableMultiFrame->setHeaderTextFormat( format );
496 }
497
498 layout->addMultiFrame( tableMultiFrame.release() );
499
500 std::unique_ptr< QgsLayoutFrame > frame = qgis::make_unique< QgsLayoutFrame >( layout, table );
501 QgsLayoutFrame *f = frame.get();
502 table->addFrame( frame.release() );
503 return f;
504 } );
505 registry->addLayoutItemGuiMetadata( manualTableItemMetadata.release() );
506 }
507