21#include "qgsattributetypedialog.h"
22#include "qgsattributeformcontaineredit.h"
23#include "qgsattributewidgetedit.h"
60 QGridLayout *availableWidgetsWidgetLayout =
new QGridLayout;
63 availableWidgetsWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
64 mAvailableWidgetsWidget->setLayout( availableWidgetsWidgetLayout );
70 QGridLayout *formLayoutWidgetLayout =
new QGridLayout;
72 mFormLayoutWidget->setLayout( formLayoutWidgetLayout );
74 formLayoutWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
75 mFormLayoutTree->setHeaderLabels( QStringList() << tr(
"Form Layout" ) );
78 connect(
mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
79 connect(
mFormLayoutTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
80 connect( mAddTabOrGroupButton, &QAbstractButton::clicked,
this, &QgsAttributesFormProperties::addContainer );
81 connect( mRemoveTabOrGroupButton, &QAbstractButton::clicked,
this, &QgsAttributesFormProperties::removeTabOrGroupButton );
82 connect( mInvertSelectionButton, &QAbstractButton::clicked,
this, &QgsAttributesFormProperties::onInvertSelectionButtonClicked );
83 connect( mEditorLayoutComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged );
84 connect( pbnSelectEditForm, &QToolButton::clicked,
this, &QgsAttributesFormProperties::pbnSelectEditForm_clicked );
85 connect( mTbInitCode, &QPushButton::clicked,
this, &QgsAttributesFormProperties::mTbInitCode_clicked );
118 for (
int i = 0; i < fields.
size(); ++i )
132 if ( !field.
alias().isEmpty() )
133 tooltip = tr(
"%1 (%2)" ).arg( field.
name(), field.
alias() );
135 tooltip = field.
name();
136 item->setToolTip( 0, tooltip );
138 catitem->setExpanded(
true );
153 catitem->setExpanded(
true );
161 for (
const auto &action : std::as_const( actions ) )
163 if ( action.isValid() && action.runable() &&
164 ( action.actionScopes().contains( QStringLiteral(
"Feature" ) ) ||
165 action.actionScopes().contains( QStringLiteral(
"Layer" ) ) ) )
167 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
194 catitem ->setExpanded(
true );
202 mFormLayoutTree->setSelectionBehavior( QAbstractItemView::SelectRows );
203 mFormLayoutTree->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
240 mEditorLayoutComboBox->setCurrentIndex( mEditorLayoutComboBox->findData( QVariant::fromValue(
mLayer->
editFormConfig().
layout() ) ) );
242 mEditorLayoutComboBox_currentIndexChanged( mEditorLayoutComboBox->currentIndex() );
245 mEditFormLineEdit->setText( cfg.
uiForm() );
257 if ( mInitCode.isEmpty() )
259 mInitCode.append( tr(
"# -*- coding: utf-8 -*-\n\"\"\"\n"
260 "QGIS forms can have a Python function that is called when the form is\n"
263 "Use this function to add extra logic to your forms.\n"
265 "Enter the name of the function in the \"Python Init function\"\n"
267 "An example follows:\n"
269 "from qgis.PyQt.QtWidgets import QWidget\n\n"
270 "def my_form_open(dialog, layer, feature):\n"
271 " geom = feature.geometry()\n"
272 " control = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
276void QgsAttributesFormProperties::loadAttributeTypeDialog()
283 const FieldConfig cfg = item->data( 0,
FieldConfigRole ).value<FieldConfig>();
284 const QString fieldName = item->data( 0,
FieldNameRole ).toString();
306 QgsFieldConstraints::Constraints providerConstraints = QgsFieldConstraints::Constraints();
325 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
331void QgsAttributesFormProperties::storeAttributeTypeDialog()
381 cfg.mFieldConstraints = constraints;
394 QTreeWidgetItem *item = *itemIt;
395 if ( item->data( 0,
FieldNameRole ).toString() == fieldName )
396 item->setData( 0,
FieldConfigRole, QVariant::fromValue<FieldConfig>( cfg ) );
400void QgsAttributesFormProperties::storeAttributeWidgetEdit()
408void QgsAttributesFormProperties::loadAttributeWidgetEdit()
413 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().at( 0 );
415 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
419void QgsAttributesFormProperties::loadInfoWidget(
const QString &infoText )
422 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
426void QgsAttributesFormProperties::storeAttributeContainerEdit()
434void QgsAttributesFormProperties::loadAttributeContainerEdit()
439 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().at( 0 );
443 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
450 auto setCommonProperties = [widgetDef]( DnDTreeItemData & itemData )
452 itemData.setShowLabel( widgetDef->
showLabel() );
453 itemData.setLabelStyle( widgetDef->
labelStyle() );
458 QTreeWidgetItem *newWidget =
nullptr;
459 switch ( widgetDef->
type() )
464 setCommonProperties( itemData );
465 newWidget = tree->
addItem( parent, itemData );
473 if ( action.isValid() )
475 DnDTreeItemData itemData = DnDTreeItemData(
DnDTreeItemData::Action, action.id().toString(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
476 setCommonProperties( itemData );
477 newWidget = tree->
addItem( parent, itemData );
490 setCommonProperties( itemData );
492 RelationEditorConfiguration relEdConfig;
496 relEdConfig.nmRelationId = relationEditor->
nmRelationId();
498 relEdConfig.label = relationEditor->
label();
499 itemData.setRelationEditorConfiguration( relEdConfig );
500 newWidget = tree->
addItem( parent, itemData );
513 itemData.setContainerType( container->
type() );
517 itemData.setCollapsed( container->
collapsed() );
519 setCommonProperties( itemData );
521 newWidget = tree->
addItem( parent, itemData );
523 const QList<QgsAttributeEditorElement *> children = container->
children();
526 loadAttributeEditorTreeItem( wdg, newWidget, tree );
535 QmlElementEditorConfiguration qmlEdConfig;
536 qmlEdConfig.qmlCode = qmlElementEditor->
qmlCode();
537 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
538 setCommonProperties( itemData );
539 newWidget = tree->
addItem( parent, itemData );
547 HtmlElementEditorConfiguration htmlEdConfig;
548 htmlEdConfig.htmlCode = htmlElementEditor->
htmlCode();
549 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
550 setCommonProperties( itemData );
551 newWidget = tree->
addItem( parent, itemData );
559 TextElementEditorConfiguration textEdConfig;
560 textEdConfig.text = textElementEditor->
text();
561 itemData.setTextElementEditorConfiguration( textEdConfig );
562 setCommonProperties( itemData );
563 newWidget = tree->
addItem( parent, itemData );
571 SpacerElementEditorConfiguration spacerEdConfig;
572 spacerEdConfig.drawLine = spacerElementEditor->
drawLine();
573 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
574 setCommonProperties( itemData );
575 itemData.setShowLabel(
false );
576 newWidget = tree->
addItem( parent, itemData );
582 QgsDebugError( QStringLiteral(
"Not loading invalid attribute editor type..." ) );
588 newWidget->setExpanded(
true );
594void QgsAttributesFormProperties::onAttributeSelectionChanged()
596 disconnect(
mFormLayoutTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
598 connect(
mFormLayoutTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
601void QgsAttributesFormProperties::onFormLayoutSelectionChanged()
604 disconnect(
mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
606 connect(
mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
614 storeAttributeWidgetEdit();
615 storeAttributeTypeDialog();
616 storeAttributeContainerEdit();
618 clearAttributeTypeFrame();
620 if ( emitter->selectedItems().count() != 1 )
622 receiver->clearSelection();
626 const DnDTreeItemData itemData = emitter->selectedItems().at( 0 )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
627 switch ( itemData.type() )
634 loadAttributeWidgetEdit();
638 loadInfoWidget( tr(
"This configuration is available in the Drag and Drop Designer" ) );
646 loadAttributeWidgetEdit();
647 loadAttributeTypeDialog();
652 receiver->clearSelection();
653 loadAttributeContainerEdit();
660 loadInfoWidget( action.html() );
670 loadInfoWidget( tr(
"This configuration is available with double-click in the Drag and Drop Designer" ) );
674 loadInfoWidget( tr(
"This configuration is available with double-click" ) );
676 receiver->clearSelection();
681 receiver->clearSelection();
688void QgsAttributesFormProperties::clearAttributeTypeFrame()
716void QgsAttributesFormProperties::onInvertSelectionButtonClicked(
bool checked )
721 for (
int i = 0; i < rootItem->childCount(); ++i )
723 rootItem->child( i )->setSelected( ! selectedItemList.contains( rootItem->child( i ) ) );
727void QgsAttributesFormProperties::addContainer()
729 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList;
733 const DnDTreeItemData itemData = ( *it )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
739 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().value( 0 );
742 if ( !dialog.exec() )
745 const QString name = dialog.name();
746 QTreeWidgetItem *parentContainerItem = dialog.parentContainerItem();
749 dialog.columnCount(),
750 dialog.containerType() );
753void QgsAttributesFormProperties::removeTabOrGroupButton()
759 const QList<QTreeWidgetItem *> items =
mFormLayoutTree->selectedItems();
763 delete items.at( 0 );
774 switch ( itemData.
type() )
822 for (
int t = 0; t < item->childCount(); t++ )
829 widgetDef = container;
881void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged(
int )
887 mFormLayoutWidget->setVisible(
false );
888 mUiFileFrame->setVisible(
false );
889 mAddTabOrGroupButton->setVisible(
false );
890 mRemoveTabOrGroupButton->setVisible(
false );
891 mInvertSelectionButton->setVisible(
false );
895 mFormLayoutWidget->setVisible(
true );
896 mUiFileFrame->setVisible(
false );
897 mAddTabOrGroupButton->setVisible(
true );
898 mRemoveTabOrGroupButton->setVisible(
true );
899 mInvertSelectionButton->setVisible(
true );
904 mFormLayoutWidget->setVisible(
false );
905 mUiFileFrame->setVisible(
true );
906 mAddTabOrGroupButton->setVisible(
false );
907 mRemoveTabOrGroupButton->setVisible(
false );
908 mInvertSelectionButton->setVisible(
false );
913void QgsAttributesFormProperties::mTbInitCode_clicked()
922 if ( !attributesFormInitCode.exec() )
925 mInitCodeSource = attributesFormInitCode.
codeSource();
926 mInitCode = attributesFormInitCode.
initCode();
932void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
935 const QString lastUsedDir = myQSettings.
value( QStringLiteral(
"style/lastUIDir" ), QDir::homePath() ).toString();
936 const QString uifilename = QFileDialog::getOpenFileName(
this, tr(
"Select edit form" ), lastUsedDir, tr(
"UI file" ) +
" (*.ui)" );
938 if ( uifilename.isNull() )
941 const QFileInfo fi( uifilename );
942 myQSettings.
setValue( QStringLiteral(
"style/lastUIDir" ), fi.path() );
943 mEditFormLineEdit->setText( uifilename );
948 storeAttributeWidgetEdit();
949 storeAttributeContainerEdit();
950 storeAttributeTypeDialog();
956 storeAttributeWidgetEdit();
957 storeAttributeContainerEdit();
958 storeAttributeTypeDialog();
964 for (
int i = 0; i < fieldContainer->childCount(); i++ )
966 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
969 const QString fieldName { fieldItem->data( 0,
FieldNameRole ).toString() };
1020 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1022 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1024 if ( editorElement )
1025 editFormConfig.
addTab( editorElement );
1028 editFormConfig.
setUiForm( mEditFormLineEdit->text() );
1042 for (
int i = 0; i < relationContainer->childCount(); i++ )
1044 QTreeWidgetItem *relationItem = relationContainer->child( i );
1047 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1049 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1052 if ( tabItemData.
type() == itemData.
type() && tabItemData.
name() == itemData.
name() )
1090QgsAttributesFormProperties::FieldConfig::operator QVariant()
1092 return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *
this );
1099QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
1101 return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *
this );
1110 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << title );
1111 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1112 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1117 parent->addChild( newItem );
1118 newItem->setExpanded(
true );
1123 : QTreeWidget( parent )
1126 connect(
this, &QTreeWidget::itemDoubleClicked,
this, &QgsAttributesDnDTree::onItemDoubleClicked );
1131 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << data.
name() );
1133 switch ( data.
type() )
1142 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1148 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1149 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1156 newItem->setIcon( 0, icon );
1159 parent->addChild( newItem );
1161 parent->insertChild( index, newItem );
1173 const QMimeData *data =
event->mimeData();
1175 if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1179 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1180 QDataStream stream( &itemData, QIODevice::ReadOnly );
1181 stream >> itemElement;
1184 if ( event->source() ==
this )
1186 event->setDropAction( Qt::MoveAction );
1194 QTreeWidget::dragMoveEvent( event );
1200 bool bDropSuccessful =
false;
1202 if ( action == Qt::IgnoreAction )
1204 bDropSuccessful =
true;
1206 else if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1208 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1209 QDataStream stream( &itemData, QIODevice::ReadOnly );
1212 while ( !stream.atEnd() )
1214 stream >> itemElement;
1216 QTreeWidgetItem *newItem;
1220 newItem =
addItem( parent, itemElement, index++ );
1221 bDropSuccessful =
true;
1225 newItem =
addItem( invisibleRootItem(), itemElement, index++ );
1226 bDropSuccessful =
true;
1231 onItemDoubleClicked( newItem, 0 );
1236 onItemDoubleClicked( newItem, 0 );
1241 onItemDoubleClicked( newItem, 0 );
1246 onItemDoubleClicked( newItem, 0 );
1250 newItem->setSelected(
true );
1254 return bDropSuccessful;
1259 if ( !event->mimeData()->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1262 if ( event->source() ==
this )
1264 event->setDropAction( Qt::MoveAction );
1267 QTreeWidget::dropEvent( event );
1272 return QStringList() << QStringLiteral(
"application/x-qgsattributetabledesignerelement" );
1275#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1281 if ( items.count() <= 0 )
1284 const QStringList types = mimeTypes();
1286 if ( types.isEmpty() )
1289 QMimeData *data =
new QMimeData();
1290 const QString format = types.at( 0 );
1292 QDataStream stream( &encoded, QIODevice::WriteOnly );
1294 const auto constItems = items;
1295 for (
const QTreeWidgetItem *item : constItems )
1305 data->setData( format, encoded );
1310void QgsAttributesDnDTree::onItemDoubleClicked( QTreeWidgetItem *item,
int column )
1316 QGroupBox *baseData =
new QGroupBox( tr(
"Base configuration" ) );
1318 QFormLayout *baseLayout =
new QFormLayout();
1319 baseData->setLayout( baseLayout );
1320 QCheckBox *showLabelCheckbox =
new QCheckBox( QStringLiteral(
"Show label" ) );
1321 showLabelCheckbox->setChecked( itemData.
showLabel() );
1322 baseLayout->addRow( showLabelCheckbox );
1323 QWidget *baseWidget =
new QWidget();
1324 baseWidget->setLayout( baseLayout );
1326 switch ( itemData.
type() )
1341 dlg.setWindowTitle( tr(
"Configure QML Widget" ) );
1343 QVBoxLayout *mainLayout =
new QVBoxLayout();
1344 QHBoxLayout *qmlLayout =
new QHBoxLayout();
1345 QVBoxLayout *layout =
new QVBoxLayout();
1346 mainLayout->addLayout( qmlLayout );
1347 qmlLayout->addLayout( layout );
1348 dlg.setLayout( mainLayout );
1349 layout->addWidget( baseWidget );
1351 QLineEdit *title =
new QLineEdit( itemData.
name() );
1362 connect( qmlCode, &QsciScintilla::textChanged,
this, [ = ]
1370 QComboBox *qmlObjectTemplate =
new QComboBox();
1371 qmlObjectTemplate->addItem( tr(
"Free Text…" ) );
1372 qmlObjectTemplate->addItem( tr(
"Rectangle" ) );
1373 qmlObjectTemplate->addItem( tr(
"Pie Chart" ) );
1374 qmlObjectTemplate->addItem( tr(
"Bar Chart" ) );
1375 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [ = ](
int index )
1382 qmlCode->setText( QString() );
1387 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1392 " color: \"steelblue\"\n"
1393 " Text{ text: \"A rectangle\" }\n"
1399 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1400 "import QtCharts 2.0\n"
1408 " PieSlice { label: \"First slice\"; value: 25 }\n"
1409 " PieSlice { label: \"Second slice\"; value: 45 }\n"
1410 " PieSlice { label: \"Third slice\"; value: 30 }\n"
1417 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1418 "import QtCharts 2.0\n"
1421 " title: \"Bar series\"\n"
1424 " legend.alignment: Qt.AlignBottom\n"
1425 " antialiasing: true\n"
1434 " axisY: valueAxisY\n"
1435 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1436 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1437 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1438 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1450 expressionWidget->registerExpressionContextGenerator(
this );
1451 expressionWidget->setLayer( mLayer );
1452 QToolButton *addFieldButton =
new QToolButton();
1455 QToolButton *editExpressionButton =
new QToolButton();
1457 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1459 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1461 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1462 if ( !expression.isEmpty() )
1463 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1466 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1469 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1473 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1474 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1476 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1477 if ( !expression.isEmpty() )
1478 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1482 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1483 layout->addWidget( title );
1484 QGroupBox *qmlCodeBox =
new QGroupBox( tr(
"QML Code" ) );
1485 qmlCodeBox->setLayout(
new QVBoxLayout );
1486 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1487 QWidget *expressionWidgetBox =
new QWidget();
1488 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1489 expressionWidgetBox->setLayout(
new QHBoxLayout );
1490 expressionWidgetBox->layout()->setContentsMargins( 0, 0, 0, 0 );
1491 expressionWidgetBox->layout()->addWidget( expressionWidget );
1492 expressionWidgetBox->layout()->addWidget( addFieldButton );
1493 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1494 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1495 layout->addWidget( qmlCodeBox );
1496 layout->addWidget( qmlCode );
1498 qmlPreviewBox->setLayout(
new QGridLayout );
1499 qmlPreviewBox->setMinimumWidth( 400 );
1500 qmlPreviewBox->layout()->addWidget( qmlWrapper->
widget() );
1502 emit qmlCode->textChanged();
1503 qmlLayout->addWidget( qmlPreviewBox );
1505 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1507 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1508 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1510 mainLayout->addWidget( buttonBox );
1515 qmlEdCfg.
qmlCode = qmlCode->text();
1516 itemData.
setName( title->text() );
1518 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1521 item->setText( 0, title->text() );
1531 dlg.setWindowTitle( tr(
"Configure HTML Widget" ) );
1533 QVBoxLayout *mainLayout =
new QVBoxLayout();
1534 QHBoxLayout *htmlLayout =
new QHBoxLayout();
1535 QVBoxLayout *layout =
new QVBoxLayout();
1536 mainLayout->addLayout( htmlLayout );
1537 htmlLayout->addLayout( layout );
1538 dlg.setLayout( mainLayout );
1539 layout->addWidget( baseWidget );
1541 QLineEdit *title =
new QLineEdit( itemData.
name() );
1545 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1553 connect( htmlCode, &QgsCodeEditorHTML::textChanged,
this, [ = ]
1562 expressionWidget->registerExpressionContextGenerator(
this );
1563 expressionWidget->setLayer( mLayer );
1564 QToolButton *addFieldButton =
new QToolButton();
1567 QToolButton *editExpressionButton =
new QToolButton();
1569 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1571 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1573 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1574 if ( !expression.isEmpty() )
1575 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1578 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1581 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1585 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1586 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1588 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1589 if ( !expression.isEmpty() )
1590 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1594 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1595 layout->addWidget( title );
1596 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"HTML Code" ) );
1597 layout->addWidget( expressionWidgetBox );
1598 expressionWidgetBox->setLayout(
new QHBoxLayout );
1599 expressionWidgetBox->layout()->addWidget( expressionWidget );
1600 expressionWidgetBox->layout()->addWidget( addFieldButton );
1601 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1602 layout->addWidget( htmlCode );
1604 htmlPreviewBox->setLayout(
new QGridLayout );
1605 htmlPreviewBox->setMinimumWidth( 400 );
1606 htmlPreviewBox->layout()->addWidget( htmlWrapper->
widget() );
1608 emit htmlCode->textChanged();
1609 htmlLayout->addWidget( htmlPreviewBox );
1611 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1613 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1614 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1616 mainLayout->addWidget( buttonBox );
1621 htmlEdCfg.
htmlCode = htmlCode->text();
1622 itemData.
setName( title->text() );
1624 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1627 item->setText( 0, title->text() );
1637 dlg.setWindowTitle( tr(
"Configure Text Widget" ) );
1639 QVBoxLayout *mainLayout =
new QVBoxLayout();
1640 QHBoxLayout *textLayout =
new QHBoxLayout();
1641 QVBoxLayout *layout =
new QVBoxLayout();
1642 mainLayout->addLayout( textLayout );
1643 textLayout->addLayout( layout );
1644 dlg.setLayout( mainLayout );
1645 layout->addWidget( baseWidget );
1647 QLineEdit *title =
new QLineEdit( itemData.
name() );
1650 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1658 connect( text, &QgsCodeEditorExpression::textChanged,
this, [ = ]
1660 textWrapper->
setText( text->text( ) );
1667 expressionWidget->registerExpressionContextGenerator(
this );
1668 expressionWidget->setLayer( mLayer );
1669 QToolButton *addFieldButton =
new QToolButton();
1672 QToolButton *editExpressionButton =
new QToolButton();
1674 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1676 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1678 QString expression = expressionWidget->expression().trimmed();
1679 if ( !expression.isEmpty() )
1680 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1682 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1689 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1690 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1692 QString expression = exprDlg.expressionText().trimmed();
1693 if ( !expression.isEmpty() )
1694 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1698 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1699 layout->addWidget( title );
1700 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"Text" ) );
1701 layout->addWidget( expressionWidgetBox );
1702 expressionWidgetBox->setLayout(
new QHBoxLayout );
1703 expressionWidgetBox->layout()->addWidget( expressionWidget );
1704 expressionWidgetBox->layout()->addWidget( addFieldButton );
1705 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1706 layout->addWidget( text );
1708 textPreviewBox->setLayout(
new QGridLayout );
1709 textPreviewBox->setMinimumWidth( 400 );
1710 textPreviewBox->layout()->addWidget( textWrapper->
widget() );
1712 emit text->textChanged();
1713 textLayout->addWidget( textPreviewBox );
1715 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1717 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1718 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1720 mainLayout->addWidget( buttonBox );
1725 textEdCfg.
text = text->text();
1726 itemData.
setName( title->text() );
1728 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1731 item->setText( 0, title->text() );
1741 dlg.setWindowTitle( tr(
"Configure Spacer Widget" ) );
1743 QVBoxLayout *mainLayout =
new QVBoxLayout();
1744 mainLayout->addWidget(
new QLabel( tr(
"Title" ) ) );
1745 QLineEdit *title =
new QLineEdit( itemData.
name() );
1746 mainLayout->addWidget( title );
1748 QHBoxLayout *cbLayout =
new QHBoxLayout( );
1749 mainLayout->addLayout( cbLayout );
1750 dlg.setLayout( mainLayout );
1751 QCheckBox *cb =
new QCheckBox { &dlg };
1753 cbLayout->addWidget(
new QLabel( tr(
"Draw horizontal line" ), &dlg ) );
1754 cbLayout->addWidget( cb );
1757 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1759 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1760 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1762 mainLayout->addWidget( buttonBox );
1767 spacerEdCfg.
drawLine = cb->isChecked();
1770 itemData.
setName( title->text() );
1772 item->setText( 0, title->text() );
1805 QTreeWidgetItemIterator it(
this );
1811 if ( selectedItems().count() == 1 && ( *it )->isSelected() == true )
1818 ( *it )->setSelected(
true );
1841 QString displayName;
1844 stream >> type >> name >> displayName;
1855 return mContainerType;
1860 mContainerType = type;
1870 mLabelStyle = labelStyle;
1880 mShowLabel = showLabel;
1885 return mVisibilityExpression;
1890 mVisibilityExpression = visibilityExpression;
1895 return mCollapsedExpression;
1900 mCollapsedExpression = collapsedExpression;
1905 return mRelationEditorConfiguration;
1910 mRelationEditorConfiguration = relationEditorConfiguration;
1915 return mQmlElementEditorConfiguration;
1920 mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
1926 return mHtmlElementEditorConfiguration;
1931 mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
1936 return mSpacerElementEditorConfiguration;
1941 mSpacerElementEditorConfiguration = spacerElementEditorConfiguration;
1946 return mBackgroundColor;
1951 mBackgroundColor = backgroundColor;
1956 return mTextElementEditorConfiguration;
1961 mTextElementEditorConfiguration = textElementEditorConfiguration;
1964void QgsAttributesFormProperties::updatedFields()
1967 QMap<QString, FieldConfig> fieldConfigs;
1969 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1971 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1972 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1974 fieldConfigs[fieldName] = cfg;
1980 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1982 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1983 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1984 if ( fieldConfigs.contains( fieldName ) )
AttributeEditorContainerType
Attribute editor container types.
AttributeFormSuppression
Available form types for layout of the attribute form editor.
@ On
Always suppress feature form.
@ Default
Use the application-wide setting.
@ Off
Never suppress feature form.
AttributeFormLayout
Available form types for layout of the attribute form editor.
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
@ UiFile
Load a .ui file for the layout. Needs to be configured.
@ Action
A layer action element (since QGIS 3.22)
@ QmlElement
A QML element.
@ HtmlElement
A HTML element.
@ TextElement
A text element (since QGIS 3.30)
@ SpacerElement
A spacer element (since QGIS 3.30)
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QgsAction action(QUuid id) const
Gets an action by its id.
Utility class that encapsulates an action based on vector attributes.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
This element will load a layer action onto the form.
const QgsAction & action(const QgsVectorLayer *layer) const
Returns the (possibly lazy loaded) action for the given layer.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
virtual void addChildElement(QgsAttributeEditorElement *element)
Add a child element to this container.
QgsOptionalExpression visibilityExpression() const
The visibility expression is used in the attribute form to show or hide this container based on an ex...
void setColumnCount(int columnCount)
Set the number of columns in this group.
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
The visibility expression is used in the attribute form to show or hide this container based on an ex...
QgsOptionalExpression collapsedExpression() const
The collapsed expression is used in the attribute form to set the collapsed status of the group box c...
bool collapsed() const
For group box containers returns true if this group box is collapsed.
Qgis::AttributeEditorContainerType type() const
Returns the container type.
void setType(Qgis::AttributeEditorContainerType type)
Sets the container type.
void setCollapsedExpression(const QgsOptionalExpression &collapsedExpression)
The collapsed expression is used in the attribute form to set the collapsed status of the group box o...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
QColor backgroundColor() const
Returns the background color of the container.
void setCollapsed(bool collapsed)
For group box containers sets if this group box is collapsed.
int columnCount() const
Gets the number of columns in this group.
void setBackgroundColor(const QColor &backgroundColor)
Sets the background color to backgroundColor.
This is an abstract base class for any elements of a drag and drop form.
void setHorizontalStretch(int stretch)
Sets the horizontal stretch factor for the element.
LabelStyle labelStyle() const
Returns the label style.
void setLabelStyle(const LabelStyle &labelStyle)
Sets the labelStyle.
Qgis::AttributeEditorType type() const
The type of this element.
int verticalStretch() const
Returns the vertical stretch factor for the element.
bool showLabel() const
Controls if this element should be labeled with a title (field, relation or groupname).
QString name() const
Returns the name of this element.
void setVerticalStretch(int stretch)
Sets the vertical stretch factor for the element.
void setShowLabel(bool showLabel)
Controls if this element should be labeled with a title (field, relation or groupname).
int horizontalStretch() const
Returns the horizontal stretch factor for the element.
This element will load a field's widget onto the form.
An attribute editor widget that will represent arbitrary HTML code.
QString htmlCode() const
The Html code that will be represented within this widget.
void setHtmlCode(const QString &htmlCode)
Sets the HTML code that will be represented within this widget to htmlCode.
An attribute editor widget that will represent arbitrary QML code.
QString qmlCode() const
The QML code that will be represented within this widget.
void setQmlCode(const QString &qmlCode)
Sets the QML code that will be represented within this widget to qmlCode.
This element will load a relation editor onto the form.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
void setRelationWidgetTypeId(const QString &relationWidgetTypeId)
Sets the relation widget type.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
QVariantMap relationEditorConfiguration() const
Returns the relation editor widget configuration.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status.
QString relationWidgetTypeId() const
Returns the current relation widget type id.
void setRelationEditorConfiguration(const QVariantMap &config)
Sets the relation editor configuration.
void setLabel(const QString &label=QString())
Sets label for this element If it's empty it takes the relation id as label.
QString label() const
Determines the label of this element.
An attribute editor widget that will represent a spacer.
void setDrawLine(bool drawLine)
Sets a flag to define if the spacer element will contain an horizontal line.
bool drawLine() const
Returns true if the spacer element will contain an horizontal line.
An attribute editor widget that will represent arbitrary text code.
void setText(const QString &text)
Sets the text that will be represented within this widget to text.
QString text() const
The Text that will be represented within this widget.
This class overrides mime type handling to be able to work with the drag and drop attribute editor.
void setType(QgsAttributesDnDTree::Type value)
QTreeWidgetItem * addItem(QTreeWidgetItem *parent, QgsAttributesFormProperties::DnDTreeItemData data, int index=-1, const QIcon &icon=QIcon())
Adds a new item to a parent.
void dropEvent(QDropEvent *event) override
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QTreeWidgetItem * addContainer(QTreeWidgetItem *parent, const QString &title, int columnCount, Qgis::AttributeEditorContainerType type)
Adds a new container to parent.
QStringList mimeTypes() const override
QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)
QMimeData * mimeData(const QList< QTreeWidgetItem * > &items) const override
bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) override
void dragMoveEvent(QDragMoveEvent *event) override
Is called when mouse is moved over attributes tree before a drop event.
void selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)
A HTML editor based on QScintilla2.
A text editor based on QScintilla2.
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
The QgsDefaultValue class provides a container for managing client side default values for fields.
A generic dialog for building expression strings.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
static QString findAndSelectActiveExpression(QgsCodeEditor *editor, const QString &pattern=QString())
Find the expression under the cursor in the given editor and select it.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Stores information about constraints which may be present on a field.
@ ConstraintStrengthHard
Constraint must be honored before feature can be accepted.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
Encapsulate a field in an attribute table or data source.
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the field's split policy, which indicates how field values should be handled during a split o...
QgsFieldConstraints constraints
Container of fields for a vector layer.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
@ OriginExpression
Field is calculated from an expression.
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
int count() const
Returns number of items.
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QIcon iconForField(int fieldIdx, bool considerOrigin=false) const
Returns an icon corresponding to a field index, based on the field's type and source.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
An expression with an additional enabled flag.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
int count() const
Returns the number of properties contained within the collection.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
static const QgsSettingsEntryBool * settingsDigitizingDisableEnterAttributeValuesDialog
Settings entry digitizing disable enter attribute values dialog.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Wraps a label widget to display text.
void setText(const QString &text)
Sets the text code to htmlCode.
void reinitWidget()
Clears the content and makes new initialization.
void setFeature(const QgsFeature &feature) override
Represents a vector layer which manages a vector based data sets.
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
void setDefaultValueDefinition(int index, const QgsDefaultValue &definition)
Sets the definition of the expression to use when calculating the default value for a field.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field index.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QgsEditFormConfig editFormConfig
void setFieldSplitPolicy(int index, Qgis::FieldDomainSplitPolicy policy)
Sets a split policy for the field with the specified index.
#define QgsDebugError(str)
The TabStyle struct defines color and font overrides for form fields, tabs and groups labels.