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();
326 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
332void QgsAttributesFormProperties::storeAttributeTypeDialog()
384 cfg.mFieldConstraints = constraints;
397 QTreeWidgetItem *item = *itemIt;
398 if ( item->data( 0,
FieldNameRole ).toString() == fieldName )
399 item->setData( 0,
FieldConfigRole, QVariant::fromValue<FieldConfig>( cfg ) );
403void QgsAttributesFormProperties::storeAttributeWidgetEdit()
411void QgsAttributesFormProperties::loadAttributeWidgetEdit()
416 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().at( 0 );
418 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
422void QgsAttributesFormProperties::loadInfoWidget(
const QString &infoText )
425 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
429void QgsAttributesFormProperties::storeAttributeContainerEdit()
437void QgsAttributesFormProperties::loadAttributeContainerEdit()
442 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().at( 0 );
446 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
453 auto setCommonProperties = [widgetDef]( DnDTreeItemData & itemData )
455 itemData.setShowLabel( widgetDef->
showLabel() );
456 itemData.setLabelStyle( widgetDef->
labelStyle() );
461 QTreeWidgetItem *newWidget =
nullptr;
462 switch ( widgetDef->
type() )
467 setCommonProperties( itemData );
468 newWidget = tree->
addItem( parent, itemData );
476 if ( action.isValid() )
478 DnDTreeItemData itemData = DnDTreeItemData(
DnDTreeItemData::Action, action.id().toString(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
479 setCommonProperties( itemData );
480 newWidget = tree->
addItem( parent, itemData );
493 setCommonProperties( itemData );
495 RelationEditorConfiguration relEdConfig;
499 relEdConfig.nmRelationId = relationEditor->
nmRelationId();
501 relEdConfig.label = relationEditor->
label();
502 itemData.setRelationEditorConfiguration( relEdConfig );
503 newWidget = tree->
addItem( parent, itemData );
516 itemData.setContainerType( container->
type() );
520 itemData.setCollapsed( container->
collapsed() );
522 setCommonProperties( itemData );
524 newWidget = tree->
addItem( parent, itemData );
526 const QList<QgsAttributeEditorElement *> children = container->
children();
529 loadAttributeEditorTreeItem( wdg, newWidget, tree );
538 QmlElementEditorConfiguration qmlEdConfig;
539 qmlEdConfig.qmlCode = qmlElementEditor->
qmlCode();
540 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
541 setCommonProperties( itemData );
542 newWidget = tree->
addItem( parent, itemData );
550 HtmlElementEditorConfiguration htmlEdConfig;
551 htmlEdConfig.htmlCode = htmlElementEditor->
htmlCode();
552 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
553 setCommonProperties( itemData );
554 newWidget = tree->
addItem( parent, itemData );
562 TextElementEditorConfiguration textEdConfig;
563 textEdConfig.text = textElementEditor->
text();
564 itemData.setTextElementEditorConfiguration( textEdConfig );
565 setCommonProperties( itemData );
566 newWidget = tree->
addItem( parent, itemData );
574 SpacerElementEditorConfiguration spacerEdConfig;
575 spacerEdConfig.drawLine = spacerElementEditor->
drawLine();
576 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
577 setCommonProperties( itemData );
578 itemData.setShowLabel(
false );
579 newWidget = tree->
addItem( parent, itemData );
585 QgsDebugError( QStringLiteral(
"Not loading invalid attribute editor type..." ) );
591 newWidget->setExpanded(
true );
597void QgsAttributesFormProperties::onAttributeSelectionChanged()
599 disconnect(
mFormLayoutTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
601 connect(
mFormLayoutTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
604void QgsAttributesFormProperties::onFormLayoutSelectionChanged()
607 disconnect(
mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
609 connect(
mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged,
this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
617 storeAttributeWidgetEdit();
618 storeAttributeTypeDialog();
619 storeAttributeContainerEdit();
621 clearAttributeTypeFrame();
623 if ( emitter->selectedItems().count() != 1 )
625 receiver->clearSelection();
629 const DnDTreeItemData itemData = emitter->selectedItems().at( 0 )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
630 switch ( itemData.type() )
637 loadAttributeWidgetEdit();
641 loadInfoWidget( tr(
"This configuration is available in the Drag and Drop Designer" ) );
649 loadAttributeWidgetEdit();
650 loadAttributeTypeDialog();
655 receiver->clearSelection();
656 loadAttributeContainerEdit();
663 loadInfoWidget( action.html() );
673 loadInfoWidget( tr(
"This configuration is available with double-click in the Drag and Drop Designer" ) );
677 loadInfoWidget( tr(
"This configuration is available with double-click" ) );
679 receiver->clearSelection();
684 receiver->clearSelection();
691void QgsAttributesFormProperties::clearAttributeTypeFrame()
719void QgsAttributesFormProperties::onInvertSelectionButtonClicked(
bool checked )
724 for (
int i = 0; i < rootItem->childCount(); ++i )
726 rootItem->child( i )->setSelected( ! selectedItemList.contains( rootItem->child( i ) ) );
730void QgsAttributesFormProperties::addContainer()
732 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList;
736 const DnDTreeItemData itemData = ( *it )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
742 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().value( 0 );
745 if ( !dialog.exec() )
748 const QString name = dialog.name();
749 QTreeWidgetItem *parentContainerItem = dialog.parentContainerItem();
752 dialog.columnCount(),
753 dialog.containerType() );
756void QgsAttributesFormProperties::removeTabOrGroupButton()
762 const QList<QTreeWidgetItem *> items =
mFormLayoutTree->selectedItems();
766 delete items.at( 0 );
777 switch ( itemData.
type() )
825 for (
int t = 0; t < item->childCount(); t++ )
832 widgetDef = container;
884void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged(
int )
890 mFormLayoutWidget->setVisible(
false );
891 mUiFileFrame->setVisible(
false );
892 mAddTabOrGroupButton->setVisible(
false );
893 mRemoveTabOrGroupButton->setVisible(
false );
894 mInvertSelectionButton->setVisible(
false );
898 mFormLayoutWidget->setVisible(
true );
899 mUiFileFrame->setVisible(
false );
900 mAddTabOrGroupButton->setVisible(
true );
901 mRemoveTabOrGroupButton->setVisible(
true );
902 mInvertSelectionButton->setVisible(
true );
907 mFormLayoutWidget->setVisible(
false );
908 mUiFileFrame->setVisible(
true );
909 mAddTabOrGroupButton->setVisible(
false );
910 mRemoveTabOrGroupButton->setVisible(
false );
911 mInvertSelectionButton->setVisible(
false );
916void QgsAttributesFormProperties::mTbInitCode_clicked()
925 if ( !attributesFormInitCode.exec() )
928 mInitCodeSource = attributesFormInitCode.
codeSource();
929 mInitCode = attributesFormInitCode.
initCode();
935void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
938 const QString lastUsedDir = myQSettings.
value( QStringLiteral(
"style/lastUIDir" ), QDir::homePath() ).toString();
939 const QString uifilename = QFileDialog::getOpenFileName(
this, tr(
"Select edit form" ), lastUsedDir, tr(
"UI file" ) +
" (*.ui)" );
941 if ( uifilename.isNull() )
944 const QFileInfo fi( uifilename );
945 myQSettings.
setValue( QStringLiteral(
"style/lastUIDir" ), fi.path() );
946 mEditFormLineEdit->setText( uifilename );
951 storeAttributeWidgetEdit();
952 storeAttributeContainerEdit();
953 storeAttributeTypeDialog();
959 storeAttributeWidgetEdit();
960 storeAttributeContainerEdit();
961 storeAttributeTypeDialog();
967 for (
int i = 0; i < fieldContainer->childCount(); i++ )
969 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
972 const QString fieldName { fieldItem->data( 0,
FieldNameRole ).toString() };
1024 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1026 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1028 if ( editorElement )
1029 editFormConfig.
addTab( editorElement );
1032 editFormConfig.
setUiForm( mEditFormLineEdit->text() );
1046 for (
int i = 0; i < relationContainer->childCount(); i++ )
1048 QTreeWidgetItem *relationItem = relationContainer->child( i );
1051 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1053 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1056 if ( tabItemData.
type() == itemData.
type() && tabItemData.
name() == itemData.
name() )
1093QgsAttributesFormProperties::FieldConfig::operator QVariant()
1095 return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *
this );
1102QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
1104 return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *
this );
1113 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << title );
1114 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1115 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1120 parent->addChild( newItem );
1121 newItem->setExpanded(
true );
1126 : QTreeWidget( parent )
1129 connect(
this, &QTreeWidget::itemDoubleClicked,
this, &QgsAttributesDnDTree::onItemDoubleClicked );
1134 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << data.
name() );
1136 switch ( data.
type() )
1145 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1151 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1152 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1159 newItem->setIcon( 0, icon );
1162 parent->addChild( newItem );
1164 parent->insertChild( index, newItem );
1176 const QMimeData *data =
event->mimeData();
1178 if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1182 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1183 QDataStream stream( &itemData, QIODevice::ReadOnly );
1184 stream >> itemElement;
1187 if ( event->source() ==
this )
1189 event->setDropAction( Qt::MoveAction );
1197 QTreeWidget::dragMoveEvent( event );
1203 bool bDropSuccessful =
false;
1205 if ( action == Qt::IgnoreAction )
1207 bDropSuccessful =
true;
1209 else if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1211 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1212 QDataStream stream( &itemData, QIODevice::ReadOnly );
1215 while ( !stream.atEnd() )
1217 stream >> itemElement;
1219 QTreeWidgetItem *newItem;
1223 newItem =
addItem( parent, itemElement, index++ );
1224 bDropSuccessful =
true;
1228 newItem =
addItem( invisibleRootItem(), itemElement, index++ );
1229 bDropSuccessful =
true;
1234 onItemDoubleClicked( newItem, 0 );
1239 onItemDoubleClicked( newItem, 0 );
1244 onItemDoubleClicked( newItem, 0 );
1249 onItemDoubleClicked( newItem, 0 );
1253 newItem->setSelected(
true );
1257 return bDropSuccessful;
1262 if ( !event->mimeData()->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1265 if ( event->source() ==
this )
1267 event->setDropAction( Qt::MoveAction );
1270 QTreeWidget::dropEvent( event );
1275 return QStringList() << QStringLiteral(
"application/x-qgsattributetabledesignerelement" );
1278#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1284 if ( items.count() <= 0 )
1287 const QStringList types = mimeTypes();
1289 if ( types.isEmpty() )
1292 QMimeData *data =
new QMimeData();
1293 const QString format = types.at( 0 );
1295 QDataStream stream( &encoded, QIODevice::WriteOnly );
1297 const auto constItems = items;
1298 for (
const QTreeWidgetItem *item : constItems )
1308 data->setData( format, encoded );
1313void QgsAttributesDnDTree::onItemDoubleClicked( QTreeWidgetItem *item,
int column )
1319 QGroupBox *baseData =
new QGroupBox( tr(
"Base configuration" ) );
1321 QFormLayout *baseLayout =
new QFormLayout();
1322 baseData->setLayout( baseLayout );
1323 QCheckBox *showLabelCheckbox =
new QCheckBox( QStringLiteral(
"Show label" ) );
1324 showLabelCheckbox->setChecked( itemData.
showLabel() );
1325 baseLayout->addRow( showLabelCheckbox );
1326 QWidget *baseWidget =
new QWidget();
1327 baseWidget->setLayout( baseLayout );
1329 switch ( itemData.
type() )
1344 dlg.setWindowTitle( tr(
"Configure QML Widget" ) );
1346 QVBoxLayout *mainLayout =
new QVBoxLayout();
1347 QHBoxLayout *qmlLayout =
new QHBoxLayout();
1348 QVBoxLayout *layout =
new QVBoxLayout();
1349 mainLayout->addLayout( qmlLayout );
1350 qmlLayout->addLayout( layout );
1351 dlg.setLayout( mainLayout );
1352 layout->addWidget( baseWidget );
1354 QLineEdit *title =
new QLineEdit( itemData.
name() );
1365 connect( qmlCode, &QsciScintilla::textChanged,
this, [ = ]
1373 QComboBox *qmlObjectTemplate =
new QComboBox();
1374 qmlObjectTemplate->addItem( tr(
"Free Text…" ) );
1375 qmlObjectTemplate->addItem( tr(
"Rectangle" ) );
1376 qmlObjectTemplate->addItem( tr(
"Pie Chart" ) );
1377 qmlObjectTemplate->addItem( tr(
"Bar Chart" ) );
1378 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [ = ](
int index )
1385 qmlCode->setText( QString() );
1390 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1395 " color: \"steelblue\"\n"
1396 " Text{ text: \"A rectangle\" }\n"
1402 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1403 "import QtCharts 2.0\n"
1411 " PieSlice { label: \"First slice\"; value: 25 }\n"
1412 " PieSlice { label: \"Second slice\"; value: 45 }\n"
1413 " PieSlice { label: \"Third slice\"; value: 30 }\n"
1420 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1421 "import QtCharts 2.0\n"
1424 " title: \"Bar series\"\n"
1427 " legend.alignment: Qt.AlignBottom\n"
1428 " antialiasing: true\n"
1437 " axisY: valueAxisY\n"
1438 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1439 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1440 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1441 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1453 expressionWidget->registerExpressionContextGenerator(
this );
1454 expressionWidget->setLayer( mLayer );
1455 QToolButton *addFieldButton =
new QToolButton();
1458 QToolButton *editExpressionButton =
new QToolButton();
1460 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1462 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1464 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1465 if ( !expression.isEmpty() )
1466 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1469 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1472 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1476 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1477 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1479 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1480 if ( !expression.isEmpty() )
1481 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1485 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1486 layout->addWidget( title );
1487 QGroupBox *qmlCodeBox =
new QGroupBox( tr(
"QML Code" ) );
1488 qmlCodeBox->setLayout(
new QVBoxLayout );
1489 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1490 QWidget *expressionWidgetBox =
new QWidget();
1491 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1492 expressionWidgetBox->setLayout(
new QHBoxLayout );
1493 expressionWidgetBox->layout()->setContentsMargins( 0, 0, 0, 0 );
1494 expressionWidgetBox->layout()->addWidget( expressionWidget );
1495 expressionWidgetBox->layout()->addWidget( addFieldButton );
1496 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1497 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1498 layout->addWidget( qmlCodeBox );
1499 layout->addWidget( qmlCode );
1501 qmlPreviewBox->setLayout(
new QGridLayout );
1502 qmlPreviewBox->setMinimumWidth( 400 );
1503 qmlPreviewBox->layout()->addWidget( qmlWrapper->
widget() );
1505 emit qmlCode->textChanged();
1506 qmlLayout->addWidget( qmlPreviewBox );
1508 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1510 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1511 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1513 mainLayout->addWidget( buttonBox );
1518 qmlEdCfg.
qmlCode = qmlCode->text();
1519 itemData.
setName( title->text() );
1521 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1524 item->setText( 0, title->text() );
1534 dlg.setWindowTitle( tr(
"Configure HTML Widget" ) );
1536 QVBoxLayout *mainLayout =
new QVBoxLayout();
1537 QHBoxLayout *htmlLayout =
new QHBoxLayout();
1538 QVBoxLayout *layout =
new QVBoxLayout();
1539 mainLayout->addLayout( htmlLayout );
1540 htmlLayout->addLayout( layout );
1541 dlg.setLayout( mainLayout );
1542 layout->addWidget( baseWidget );
1544 QLineEdit *title =
new QLineEdit( itemData.
name() );
1548 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1556 connect( htmlCode, &QgsCodeEditorHTML::textChanged,
this, [ = ]
1565 expressionWidget->registerExpressionContextGenerator(
this );
1566 expressionWidget->setLayer( mLayer );
1567 QToolButton *addFieldButton =
new QToolButton();
1570 QToolButton *editExpressionButton =
new QToolButton();
1572 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1574 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1576 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1577 if ( !expression.isEmpty() )
1578 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1581 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1584 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1588 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1589 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1591 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1592 if ( !expression.isEmpty() )
1593 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1597 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1598 layout->addWidget( title );
1599 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"HTML Code" ) );
1600 layout->addWidget( expressionWidgetBox );
1601 expressionWidgetBox->setLayout(
new QHBoxLayout );
1602 expressionWidgetBox->layout()->addWidget( expressionWidget );
1603 expressionWidgetBox->layout()->addWidget( addFieldButton );
1604 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1605 layout->addWidget( htmlCode );
1607 htmlPreviewBox->setLayout(
new QGridLayout );
1608 htmlPreviewBox->setMinimumWidth( 400 );
1609 htmlPreviewBox->layout()->addWidget( htmlWrapper->
widget() );
1611 emit htmlCode->textChanged();
1612 htmlLayout->addWidget( htmlPreviewBox );
1614 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1616 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1617 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1619 mainLayout->addWidget( buttonBox );
1624 htmlEdCfg.
htmlCode = htmlCode->text();
1625 itemData.
setName( title->text() );
1627 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1630 item->setText( 0, title->text() );
1640 dlg.setWindowTitle( tr(
"Configure Text Widget" ) );
1642 QVBoxLayout *mainLayout =
new QVBoxLayout();
1643 QHBoxLayout *textLayout =
new QHBoxLayout();
1644 QVBoxLayout *layout =
new QVBoxLayout();
1645 mainLayout->addLayout( textLayout );
1646 textLayout->addLayout( layout );
1647 dlg.setLayout( mainLayout );
1648 layout->addWidget( baseWidget );
1650 QLineEdit *title =
new QLineEdit( itemData.
name() );
1653 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1661 connect( text, &QgsCodeEditorExpression::textChanged,
this, [ = ]
1663 textWrapper->
setText( text->text( ) );
1670 expressionWidget->registerExpressionContextGenerator(
this );
1671 expressionWidget->setLayer( mLayer );
1672 QToolButton *addFieldButton =
new QToolButton();
1675 QToolButton *editExpressionButton =
new QToolButton();
1677 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1679 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1681 QString expression = expressionWidget->expression().trimmed();
1682 if ( !expression.isEmpty() )
1683 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1685 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1692 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1693 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1695 QString expression = exprDlg.expressionText().trimmed();
1696 if ( !expression.isEmpty() )
1697 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1701 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1702 layout->addWidget( title );
1703 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"Text" ) );
1704 layout->addWidget( expressionWidgetBox );
1705 expressionWidgetBox->setLayout(
new QHBoxLayout );
1706 expressionWidgetBox->layout()->addWidget( expressionWidget );
1707 expressionWidgetBox->layout()->addWidget( addFieldButton );
1708 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1709 layout->addWidget( text );
1711 textPreviewBox->setLayout(
new QGridLayout );
1712 textPreviewBox->setMinimumWidth( 400 );
1713 textPreviewBox->layout()->addWidget( textWrapper->
widget() );
1715 emit text->textChanged();
1716 textLayout->addWidget( textPreviewBox );
1718 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1720 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1721 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1723 mainLayout->addWidget( buttonBox );
1728 textEdCfg.
text = text->text();
1729 itemData.
setName( title->text() );
1731 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1734 item->setText( 0, title->text() );
1744 dlg.setWindowTitle( tr(
"Configure Spacer Widget" ) );
1746 QVBoxLayout *mainLayout =
new QVBoxLayout();
1747 mainLayout->addWidget(
new QLabel( tr(
"Title" ) ) );
1748 QLineEdit *title =
new QLineEdit( itemData.
name() );
1749 mainLayout->addWidget( title );
1751 QHBoxLayout *cbLayout =
new QHBoxLayout( );
1752 mainLayout->addLayout( cbLayout );
1753 dlg.setLayout( mainLayout );
1754 QCheckBox *cb =
new QCheckBox { &dlg };
1756 cbLayout->addWidget(
new QLabel( tr(
"Draw horizontal line" ), &dlg ) );
1757 cbLayout->addWidget( cb );
1760 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1762 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1763 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1765 mainLayout->addWidget( buttonBox );
1770 spacerEdCfg.
drawLine = cb->isChecked();
1773 itemData.
setName( title->text() );
1775 item->setText( 0, title->text() );
1808 QTreeWidgetItemIterator it(
this );
1814 if ( selectedItems().count() == 1 && ( *it )->isSelected() == true )
1821 ( *it )->setSelected(
true );
1844 QString displayName;
1847 stream >> type >> name >> displayName;
1858 return mContainerType;
1863 mContainerType = type;
1873 mLabelStyle = labelStyle;
1883 mShowLabel = showLabel;
1888 return mVisibilityExpression;
1893 mVisibilityExpression = visibilityExpression;
1898 return mCollapsedExpression;
1903 mCollapsedExpression = collapsedExpression;
1908 return mRelationEditorConfiguration;
1913 mRelationEditorConfiguration = relationEditorConfiguration;
1918 return mQmlElementEditorConfiguration;
1923 mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
1929 return mHtmlElementEditorConfiguration;
1934 mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
1939 return mSpacerElementEditorConfiguration;
1944 mSpacerElementEditorConfiguration = spacerElementEditorConfiguration;
1949 return mBackgroundColor;
1954 mBackgroundColor = backgroundColor;
1959 return mTextElementEditorConfiguration;
1964 mTextElementEditorConfiguration = textElementEditorConfiguration;
1967void QgsAttributesFormProperties::updatedFields()
1970 QMap<QString, FieldConfig> fieldConfigs;
1972 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1974 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1975 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1977 fieldConfigs[fieldName] = cfg;
1983 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1985 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1986 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1987 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.
QFlags< Constraint > Constraints
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...
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
QgsFieldConstraints constraints
Container of fields for a vector layer.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
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).
Q_INVOKABLE 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.
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.
void setFieldDuplicatePolicy(int index, Qgis::FieldDuplicatePolicy policy)
Sets a duplicate policy for the field with the specified 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.