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();
622 storeAttributeTypeDialog();
623 storeAttributeContainerEdit();
626 clearAttributeTypeFrame();
628 if ( emitter->selectedItems().count() != 1 )
630 receiver->clearSelection();
634 const DnDTreeItemData itemData = emitter->selectedItems().at( 0 )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
635 switch ( itemData.type() )
642 loadAttributeWidgetEdit();
646 loadInfoWidget( tr(
"This configuration is available in the Drag and Drop Designer" ) );
654 loadAttributeWidgetEdit();
655 loadAttributeTypeDialog();
660 receiver->clearSelection();
661 loadAttributeContainerEdit();
668 loadInfoWidget( action.html() );
678 loadInfoWidget( tr(
"This configuration is available with double-click in the Drag and Drop Designer" ) );
682 loadInfoWidget( tr(
"This configuration is available with double-click" ) );
684 receiver->clearSelection();
689 receiver->clearSelection();
696void QgsAttributesFormProperties::clearAttributeTypeFrame()
724void QgsAttributesFormProperties::onInvertSelectionButtonClicked(
bool checked )
729 for (
int i = 0; i < rootItem->childCount(); ++i )
731 rootItem->child( i )->setSelected( ! selectedItemList.contains( rootItem->child( i ) ) );
735void QgsAttributesFormProperties::addContainer()
737 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList;
741 const DnDTreeItemData itemData = ( *it )->data( 0,
DnDTreeRole ).value<DnDTreeItemData>();
747 QTreeWidgetItem *currentItem =
mFormLayoutTree->selectedItems().value( 0 );
750 if ( !dialog.exec() )
753 const QString name = dialog.name();
754 QTreeWidgetItem *parentContainerItem = dialog.parentContainerItem();
757 dialog.columnCount(),
758 dialog.containerType() );
761void QgsAttributesFormProperties::removeTabOrGroupButton()
767 const QList<QTreeWidgetItem *> items =
mFormLayoutTree->selectedItems();
771 delete items.at( 0 );
782 switch ( itemData.
type() )
830 for (
int t = 0; t < item->childCount(); t++ )
837 widgetDef = container;
889void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged(
int )
895 mFormLayoutWidget->setVisible(
false );
896 mUiFileFrame->setVisible(
false );
897 mAddTabOrGroupButton->setVisible(
false );
898 mRemoveTabOrGroupButton->setVisible(
false );
899 mInvertSelectionButton->setVisible(
false );
903 mFormLayoutWidget->setVisible(
true );
904 mUiFileFrame->setVisible(
false );
905 mAddTabOrGroupButton->setVisible(
true );
906 mRemoveTabOrGroupButton->setVisible(
true );
907 mInvertSelectionButton->setVisible(
true );
912 mFormLayoutWidget->setVisible(
false );
913 mUiFileFrame->setVisible(
true );
914 mAddTabOrGroupButton->setVisible(
false );
915 mRemoveTabOrGroupButton->setVisible(
false );
916 mInvertSelectionButton->setVisible(
false );
921void QgsAttributesFormProperties::mTbInitCode_clicked()
930 if ( !attributesFormInitCode.exec() )
933 mInitCodeSource = attributesFormInitCode.
codeSource();
934 mInitCode = attributesFormInitCode.
initCode();
940void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
943 const QString lastUsedDir = myQSettings.
value( QStringLiteral(
"style/lastUIDir" ), QDir::homePath() ).toString();
944 const QString uifilename = QFileDialog::getOpenFileName(
this, tr(
"Select edit form" ), lastUsedDir, tr(
"UI file" ) +
" (*.ui)" );
946 if ( uifilename.isNull() )
949 const QFileInfo fi( uifilename );
950 myQSettings.
setValue( QStringLiteral(
"style/lastUIDir" ), fi.path() );
951 mEditFormLineEdit->setText( uifilename );
956 storeAttributeWidgetEdit();
957 storeAttributeContainerEdit();
958 storeAttributeTypeDialog();
964 storeAttributeWidgetEdit();
965 storeAttributeContainerEdit();
966 storeAttributeTypeDialog();
972 for (
int i = 0; i < fieldContainer->childCount(); i++ )
974 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
977 const QString fieldName { fieldItem->data( 0,
FieldNameRole ).toString() };
1029 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1031 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1033 if ( editorElement )
1034 editFormConfig.
addTab( editorElement );
1037 editFormConfig.
setUiForm( mEditFormLineEdit->text() );
1051 for (
int i = 0; i < relationContainer->childCount(); i++ )
1053 QTreeWidgetItem *relationItem = relationContainer->child( i );
1056 for (
int t = 0; t <
mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
1058 QTreeWidgetItem *tabItem =
mFormLayoutTree->invisibleRootItem()->child( t );
1061 if ( tabItemData.
type() == itemData.
type() && tabItemData.
name() == itemData.
name() )
1098QgsAttributesFormProperties::FieldConfig::operator QVariant()
1100 return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *
this );
1107QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
1109 return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *
this );
1118 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << title );
1119 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1120 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1125 parent->addChild( newItem );
1126 newItem->setExpanded(
true );
1131 : QTreeWidget( parent )
1134 connect(
this, &QTreeWidget::itemDoubleClicked,
this, &QgsAttributesDnDTree::onItemDoubleClicked );
1139 QTreeWidgetItem *newItem =
new QTreeWidgetItem( QStringList() << data.
name() );
1141 switch ( data.
type() )
1150 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1156 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1157 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1164 newItem->setIcon( 0, icon );
1167 parent->addChild( newItem );
1169 parent->insertChild( index, newItem );
1181 const QMimeData *data =
event->mimeData();
1183 if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1187 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1188 QDataStream stream( &itemData, QIODevice::ReadOnly );
1189 stream >> itemElement;
1192 if ( event->source() ==
this )
1194 event->setDropAction( Qt::MoveAction );
1202 QTreeWidget::dragMoveEvent( event );
1208 bool bDropSuccessful =
false;
1210 if ( action == Qt::IgnoreAction )
1212 bDropSuccessful =
true;
1214 else if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1216 QByteArray itemData = data->data( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) );
1217 QDataStream stream( &itemData, QIODevice::ReadOnly );
1220 while ( !stream.atEnd() )
1222 stream >> itemElement;
1224 QTreeWidgetItem *newItem;
1228 newItem =
addItem( parent, itemElement, index++ );
1229 bDropSuccessful =
true;
1233 newItem =
addItem( invisibleRootItem(), itemElement, index++ );
1234 bDropSuccessful =
true;
1239 onItemDoubleClicked( newItem, 0 );
1244 onItemDoubleClicked( newItem, 0 );
1249 onItemDoubleClicked( newItem, 0 );
1254 onItemDoubleClicked( newItem, 0 );
1258 newItem->setSelected(
true );
1262 return bDropSuccessful;
1267 if ( !event->mimeData()->hasFormat( QStringLiteral(
"application/x-qgsattributetabledesignerelement" ) ) )
1270 if ( event->source() ==
this )
1272 event->setDropAction( Qt::MoveAction );
1275 QTreeWidget::dropEvent( event );
1280 return QStringList() << QStringLiteral(
"application/x-qgsattributetabledesignerelement" );
1283#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1289 if ( items.count() <= 0 )
1292 const QStringList types = mimeTypes();
1294 if ( types.isEmpty() )
1297 QMimeData *data =
new QMimeData();
1298 const QString format = types.at( 0 );
1300 QDataStream stream( &encoded, QIODevice::WriteOnly );
1302 const auto constItems = items;
1303 for (
const QTreeWidgetItem *item : constItems )
1313 data->setData( format, encoded );
1318void QgsAttributesDnDTree::onItemDoubleClicked( QTreeWidgetItem *item,
int column )
1324 QGroupBox *baseData =
new QGroupBox( tr(
"Base configuration" ) );
1326 QFormLayout *baseLayout =
new QFormLayout();
1327 baseData->setLayout( baseLayout );
1328 QCheckBox *showLabelCheckbox =
new QCheckBox( QStringLiteral(
"Show label" ) );
1329 showLabelCheckbox->setChecked( itemData.
showLabel() );
1330 baseLayout->addRow( showLabelCheckbox );
1331 QWidget *baseWidget =
new QWidget();
1332 baseWidget->setLayout( baseLayout );
1334 switch ( itemData.
type() )
1349 dlg.setWindowTitle( tr(
"Configure QML Widget" ) );
1351 QVBoxLayout *mainLayout =
new QVBoxLayout();
1352 QHBoxLayout *qmlLayout =
new QHBoxLayout();
1353 QVBoxLayout *layout =
new QVBoxLayout();
1354 mainLayout->addLayout( qmlLayout );
1355 qmlLayout->addLayout( layout );
1356 dlg.setLayout( mainLayout );
1357 layout->addWidget( baseWidget );
1359 QLineEdit *title =
new QLineEdit( itemData.
name() );
1370 connect( qmlCode, &QsciScintilla::textChanged,
this, [ = ]
1378 QComboBox *qmlObjectTemplate =
new QComboBox();
1379 qmlObjectTemplate->addItem( tr(
"Free Text…" ) );
1380 qmlObjectTemplate->addItem( tr(
"Rectangle" ) );
1381 qmlObjectTemplate->addItem( tr(
"Pie Chart" ) );
1382 qmlObjectTemplate->addItem( tr(
"Bar Chart" ) );
1383 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [ = ](
int index )
1390 qmlCode->setText( QString() );
1395 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1400 " color: \"steelblue\"\n"
1401 " Text{ text: \"A rectangle\" }\n"
1407 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1408 "import QtCharts 2.0\n"
1416 " PieSlice { label: \"First slice\"; value: 25 }\n"
1417 " PieSlice { label: \"Second slice\"; value: 45 }\n"
1418 " PieSlice { label: \"Third slice\"; value: 30 }\n"
1425 qmlCode->setText( QStringLiteral(
"import QtQuick 2.0\n"
1426 "import QtCharts 2.0\n"
1429 " title: \"Bar series\"\n"
1432 " legend.alignment: Qt.AlignBottom\n"
1433 " antialiasing: true\n"
1442 " axisY: valueAxisY\n"
1443 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1444 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1445 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1446 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1458 expressionWidget->registerExpressionContextGenerator(
this );
1459 expressionWidget->setLayer( mLayer );
1460 QToolButton *addFieldButton =
new QToolButton();
1463 QToolButton *editExpressionButton =
new QToolButton();
1465 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1467 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1469 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1470 if ( !expression.isEmpty() )
1471 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1474 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1477 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1481 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1482 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1484 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1485 if ( !expression.isEmpty() )
1486 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
1490 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1491 layout->addWidget( title );
1492 QGroupBox *qmlCodeBox =
new QGroupBox( tr(
"QML Code" ) );
1493 qmlCodeBox->setLayout(
new QVBoxLayout );
1494 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1495 QWidget *expressionWidgetBox =
new QWidget();
1496 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1497 expressionWidgetBox->setLayout(
new QHBoxLayout );
1498 expressionWidgetBox->layout()->setContentsMargins( 0, 0, 0, 0 );
1499 expressionWidgetBox->layout()->addWidget( expressionWidget );
1500 expressionWidgetBox->layout()->addWidget( addFieldButton );
1501 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1502 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1503 layout->addWidget( qmlCodeBox );
1504 layout->addWidget( qmlCode );
1506 qmlPreviewBox->setLayout(
new QGridLayout );
1507 qmlPreviewBox->setMinimumWidth( 400 );
1508 qmlPreviewBox->layout()->addWidget( qmlWrapper->
widget() );
1510 emit qmlCode->textChanged();
1511 qmlLayout->addWidget( qmlPreviewBox );
1513 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1515 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1516 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1518 mainLayout->addWidget( buttonBox );
1523 qmlEdCfg.
qmlCode = qmlCode->text();
1524 itemData.
setName( title->text() );
1526 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1529 item->setText( 0, title->text() );
1539 dlg.setWindowTitle( tr(
"Configure HTML Widget" ) );
1541 QVBoxLayout *mainLayout =
new QVBoxLayout();
1542 QHBoxLayout *htmlLayout =
new QHBoxLayout();
1543 QVBoxLayout *layout =
new QVBoxLayout();
1544 mainLayout->addLayout( htmlLayout );
1545 htmlLayout->addLayout( layout );
1546 dlg.setLayout( mainLayout );
1547 layout->addWidget( baseWidget );
1549 QLineEdit *title =
new QLineEdit( itemData.
name() );
1553 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1561 connect( htmlCode, &QgsCodeEditorHTML::textChanged,
this, [ = ]
1570 expressionWidget->registerExpressionContextGenerator(
this );
1571 expressionWidget->setLayer( mLayer );
1572 QToolButton *addFieldButton =
new QToolButton();
1575 QToolButton *editExpressionButton =
new QToolButton();
1577 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1579 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1581 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1582 if ( !expression.isEmpty() )
1583 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1586 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1589 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
1593 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1594 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1596 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
1597 if ( !expression.isEmpty() )
1598 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1602 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1603 layout->addWidget( title );
1604 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"HTML Code" ) );
1605 layout->addWidget( expressionWidgetBox );
1606 expressionWidgetBox->setLayout(
new QHBoxLayout );
1607 expressionWidgetBox->layout()->addWidget( expressionWidget );
1608 expressionWidgetBox->layout()->addWidget( addFieldButton );
1609 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1610 layout->addWidget( htmlCode );
1612 htmlPreviewBox->setLayout(
new QGridLayout );
1613 htmlPreviewBox->setMinimumWidth( 400 );
1614 htmlPreviewBox->layout()->addWidget( htmlWrapper->
widget() );
1616 emit htmlCode->textChanged();
1617 htmlLayout->addWidget( htmlPreviewBox );
1619 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1621 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1622 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1624 mainLayout->addWidget( buttonBox );
1629 htmlEdCfg.
htmlCode = htmlCode->text();
1630 itemData.
setName( title->text() );
1632 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1635 item->setText( 0, title->text() );
1645 dlg.setWindowTitle( tr(
"Configure Text Widget" ) );
1647 QVBoxLayout *mainLayout =
new QVBoxLayout();
1648 QHBoxLayout *textLayout =
new QHBoxLayout();
1649 QVBoxLayout *layout =
new QVBoxLayout();
1650 mainLayout->addLayout( textLayout );
1651 textLayout->addLayout( layout );
1652 dlg.setLayout( mainLayout );
1653 layout->addWidget( baseWidget );
1655 QLineEdit *title =
new QLineEdit( itemData.
name() );
1658 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1666 connect( text, &QgsCodeEditorExpression::textChanged,
this, [ = ]
1668 textWrapper->
setText( text->text( ) );
1675 expressionWidget->registerExpressionContextGenerator(
this );
1676 expressionWidget->setLayer( mLayer );
1677 QToolButton *addFieldButton =
new QToolButton();
1680 QToolButton *editExpressionButton =
new QToolButton();
1682 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
1684 connect( addFieldButton, &QAbstractButton::clicked,
this, [ = ]
1686 QString expression = expressionWidget->expression().trimmed();
1687 if ( !expression.isEmpty() )
1688 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1690 connect( editExpressionButton, &QAbstractButton::clicked,
this, [ = ]
1697 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
1698 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1700 QString expression = exprDlg.expressionText().trimmed();
1701 if ( !expression.isEmpty() )
1702 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
1706 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
1707 layout->addWidget( title );
1708 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"Text" ) );
1709 layout->addWidget( expressionWidgetBox );
1710 expressionWidgetBox->setLayout(
new QHBoxLayout );
1711 expressionWidgetBox->layout()->addWidget( expressionWidget );
1712 expressionWidgetBox->layout()->addWidget( addFieldButton );
1713 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1714 layout->addWidget( text );
1716 textPreviewBox->setLayout(
new QGridLayout );
1717 textPreviewBox->setMinimumWidth( 400 );
1718 textPreviewBox->layout()->addWidget( textWrapper->
widget() );
1720 emit text->textChanged();
1721 textLayout->addWidget( textPreviewBox );
1723 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1725 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1726 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1728 mainLayout->addWidget( buttonBox );
1733 textEdCfg.
text = text->text();
1734 itemData.
setName( title->text() );
1736 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
1739 item->setText( 0, title->text() );
1749 dlg.setWindowTitle( tr(
"Configure Spacer Widget" ) );
1751 QVBoxLayout *mainLayout =
new QVBoxLayout();
1752 mainLayout->addWidget(
new QLabel( tr(
"Title" ) ) );
1753 QLineEdit *title =
new QLineEdit( itemData.
name() );
1754 mainLayout->addWidget( title );
1756 QHBoxLayout *cbLayout =
new QHBoxLayout( );
1757 mainLayout->addLayout( cbLayout );
1758 dlg.setLayout( mainLayout );
1759 QCheckBox *cb =
new QCheckBox { &dlg };
1761 cbLayout->addWidget(
new QLabel( tr(
"Draw horizontal line" ), &dlg ) );
1762 cbLayout->addWidget( cb );
1765 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1767 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1768 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1770 mainLayout->addWidget( buttonBox );
1775 spacerEdCfg.
drawLine = cb->isChecked();
1778 itemData.
setName( title->text() );
1780 item->setText( 0, title->text() );
1813 QTreeWidgetItemIterator it(
this );
1819 if ( selectedItems().count() == 1 && ( *it )->isSelected() == true )
1826 ( *it )->setSelected(
true );
1849 QString displayName;
1852 stream >> type >> name >> displayName;
1863 return mContainerType;
1868 mContainerType = type;
1878 mLabelStyle = labelStyle;
1888 mShowLabel = showLabel;
1893 return mVisibilityExpression;
1898 mVisibilityExpression = visibilityExpression;
1903 return mCollapsedExpression;
1908 mCollapsedExpression = collapsedExpression;
1913 return mRelationEditorConfiguration;
1918 mRelationEditorConfiguration = relationEditorConfiguration;
1923 return mQmlElementEditorConfiguration;
1928 mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
1934 return mHtmlElementEditorConfiguration;
1939 mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
1944 return mSpacerElementEditorConfiguration;
1949 mSpacerElementEditorConfiguration = spacerElementEditorConfiguration;
1954 return mBackgroundColor;
1959 mBackgroundColor = backgroundColor;
1964 return mTextElementEditorConfiguration;
1969 mTextElementEditorConfiguration = textElementEditorConfiguration;
1972void QgsAttributesFormProperties::updatedFields()
1975 QMap<QString, FieldConfig> fieldConfigs;
1977 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1979 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1980 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1982 fieldConfigs[fieldName] = cfg;
1988 for (
int i = 0; i < fieldContainer->childCount(); i++ )
1990 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
1991 const QString fieldName = fieldItem->data( 0,
FieldNameRole ).toString();
1992 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.
@ QmlElement
A QML element.
@ HtmlElement
A HTML element.
@ TextElement
A text element.
@ SpacerElement
A spacer element.
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.
Represents a relationship between two vector layers.
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)
Sets the editor widget setup for the field at the specified index.
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.