20#include "qgsattributetypedialog.h"
41#include <QPlainTextEdit>
48#include "moc_qgsattributesformview.cpp"
50using namespace Qt::StringLiterals;
59 if ( selectionModel()->selectedRows( 0 ).count() == 0 )
62 return mModel->mapToSource( selectionModel()->selectedRows( 0 ).at( 0 ) );
81 QModelIndex index =
mModel->mapFromSource( model->firstRecursiveMatchingModelIndex( itemType, itemId ) );
83 if ( index.isValid() )
87 const QModelIndexList selectedIndexes = selectionModel()->selectedRows( 0 );
88 if ( !( selectedIndexes.count() == 1 && selectedIndexes.at( 0 ) == index ) )
90 selectionModel()->setCurrentIndex( index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
95 selectionModel()->clearSelection();
101 mModel->setFilterText( text );
122 viewport()->repaint();
125 viewport()->repaint();
137 const QList<QgsAttributesFormItem *> keys =
mIndicators.keys();
149 return mModel->sourceAttributesFormModel();
159 mModel = qobject_cast<QgsAttributesFormProxyModel *>( model );
163 QTreeView::setModel(
mModel );
175 connect(
this, &QTreeView::doubleClicked,
this, &QgsAttributesFormLayoutView::onItemDoubleClicked );
180 mModel = qobject_cast<QgsAttributesFormProxyModel *>( model );
184 QTreeView::setModel(
mModel );
192void QgsAttributesFormLayoutView::handleExternalDroppedItem( QModelIndex &index )
194 selectionModel()->setCurrentIndex(
mModel->mapFromSource( index ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
200 onItemDoubleClicked(
mModel->mapFromSource( index ) );
204void QgsAttributesFormLayoutView::handleInternalDroppedItem( QModelIndex &index )
206 selectionModel()->clearCurrentIndex();
210 expandRecursively(
mModel->mapFromSource( index ) );
216 const QMimeData *data =
event->mimeData();
218 if ( data->hasFormat( u
"application/x-qgsattributesformavailablewidgetsrelement"_s ) || data->hasFormat( u
"application/x-qgsattributesformlayoutelement"_s ) )
221 if ( event->source() ==
this )
223 event->setDropAction( Qt::MoveAction );
231 QTreeView::dragEnterEvent( event );
240 const QMimeData *data =
event->mimeData();
242 if ( data->hasFormat( u
"application/x-qgsattributesformavailablewidgetsrelement"_s ) || data->hasFormat( u
"application/x-qgsattributesformlayoutelement"_s ) )
245 if ( event->source() ==
this )
247 event->setDropAction( Qt::MoveAction );
255 QTreeView::dragMoveEvent( event );
260 if ( !( event->mimeData()->hasFormat( u
"application/x-qgsattributesformavailablewidgetsrelement"_s ) || event->mimeData()->hasFormat( u
"application/x-qgsattributesformlayoutelement"_s ) ) )
263 if ( event->source() ==
this )
265 event->setDropAction( Qt::MoveAction );
268 QTreeView::dropEvent( event );
271void QgsAttributesFormLayoutView::onItemDoubleClicked(
const QModelIndex &index )
273 QModelIndex sourceIndex =
mModel->mapToSource( index );
278 QGroupBox *baseData =
new QGroupBox( tr(
"Base configuration" ) );
280 QFormLayout *baseLayout =
new QFormLayout();
281 baseData->setLayout( baseLayout );
282 QCheckBox *showLabelCheckbox =
new QCheckBox( u
"Show label"_s );
283 showLabelCheckbox->setChecked( itemData.
showLabel() );
284 baseLayout->addRow( showLabelCheckbox );
285 QWidget *baseWidget =
new QWidget();
286 baseWidget->setLayout( baseLayout );
300 dlg.setObjectName(
"QML Form Configuration Widget" );
302 dlg.setWindowTitle( tr(
"Configure QML Widget" ) );
304 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
305 QSplitter *qmlSplitter =
new QSplitter();
306 QWidget *qmlConfigWiget =
new QWidget();
307 QVBoxLayout *layout =
new QVBoxLayout( qmlConfigWiget );
308 layout->setContentsMargins( 0, 0, 0, 0 );
309 mainLayout->addWidget( qmlSplitter );
310 qmlSplitter->addWidget( qmlConfigWiget );
311 layout->addWidget( baseWidget );
313 QLineEdit *title =
new QLineEdit( itemName );
332 QComboBox *qmlObjectTemplate =
new QComboBox();
333 qmlObjectTemplate->addItem( tr(
"Free Text…" ) );
334 qmlObjectTemplate->addItem( tr(
"Rectangle" ) );
335 qmlObjectTemplate->addItem( tr(
"Pie Chart" ) );
336 qmlObjectTemplate->addItem( tr(
"Bar Chart" ) );
337 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [qmlCode](
int index ) {
348 qmlCode->
setText( QStringLiteral(
349 "import QtQuick 2.0\n"
354 " color: \"steelblue\"\n"
355 " Text{ text: \"A rectangle\" }\n"
362 qmlCode->
setText( QStringLiteral(
363 "import QtQuick 2.0\n"
364 "import QtCharts 2.0\n"
372 " PieSlice { label: \"First slice\"; value: 25 }\n"
373 " PieSlice { label: \"Second slice\"; value: 45 }\n"
374 " PieSlice { label: \"Third slice\"; value: 30 }\n"
382 qmlCode->
setText( QStringLiteral(
383 "import QtQuick 2.0\n"
384 "import QtCharts 2.0\n"
387 " title: \"Bar series\"\n"
390 " legend.alignment: Qt.AlignBottom\n"
391 " antialiasing: true\n"
400 " axisY: valueAxisY\n"
401 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
402 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
403 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
404 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
415 QgsFieldExpressionWidget *expressionWidget =
new QgsFieldExpressionWidget;
416 expressionWidget->setButtonVisible(
false );
417 expressionWidget->registerExpressionContextGenerator(
this );
418 expressionWidget->setLayer(
mLayer );
419 QToolButton *addFieldButton =
new QToolButton();
422 QToolButton *editExpressionButton =
new QToolButton();
424 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
426 connect( addFieldButton, &QAbstractButton::clicked,
this, [expressionWidget, qmlCode] {
427 QString expression = expressionWidget->expression().trimmed().replace(
'"',
"\\\""_L1 );
428 if ( !expression.isEmpty() )
429 qmlCode->
insertText( u
"expression.evaluate(\"%1\")"_s.arg( expression ) );
432 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, qmlCode] {
434 expression.replace(
"\\\""_L1,
"\""_L1 );
436 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, u
"generic"_s, context );
438 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
439 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
441 QString expression = exprDlg.expressionText().trimmed().replace(
'"',
"\\\""_L1 );
442 if ( !expression.isEmpty() )
443 qmlCode->
insertText( u
"expression.evaluate(\"%1\")"_s.arg( expression ) );
447 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
448 layout->addWidget( title );
449 QGroupBox *qmlCodeBox =
new QGroupBox( tr(
"QML Code" ) );
450 qmlCodeBox->setLayout(
new QVBoxLayout );
451 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
452 QWidget *expressionWidgetBox =
new QWidget();
453 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
454 expressionWidgetBox->setLayout(
new QHBoxLayout );
455 expressionWidgetBox->layout()->setContentsMargins( 0, 0, 0, 0 );
456 expressionWidgetBox->layout()->addWidget( expressionWidget );
457 expressionWidgetBox->layout()->addWidget( addFieldButton );
458 expressionWidgetBox->layout()->addWidget( editExpressionButton );
459 expressionWidgetBox->layout()->addWidget( editExpressionButton );
460 layout->addWidget( qmlCodeBox );
461 layout->addWidget( qmlCode );
462 QScrollArea *qmlPreviewBox =
new QgsScrollArea();
463 qmlPreviewBox->setMinimumWidth( 200 );
464 qmlPreviewBox->setWidget( qmlWrapper->
widget() );
467 qmlSplitter->addWidget( qmlPreviewBox );
468 qmlSplitter->setChildrenCollapsible(
false );
469 qmlSplitter->setHandleWidth( 6 );
470 qmlSplitter->setSizes( QList<int>() << 1 << 1 );
472 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
474 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
475 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
476 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#other-widgets"_s ); } );
478 mainLayout->addWidget( buttonBox );
482 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdCfg;
483 qmlEdCfg.
qmlCode = qmlCode->text();
485 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
496 dlg.setObjectName(
"HTML Form Configuration Widget" );
498 dlg.setWindowTitle( tr(
"Configure HTML Widget" ) );
500 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
501 QSplitter *htmlSplitter =
new QSplitter();
502 QWidget *htmlConfigWiget =
new QWidget();
503 QVBoxLayout *layout =
new QVBoxLayout( htmlConfigWiget );
504 layout->setContentsMargins( 0, 0, 0, 0 );
505 mainLayout->addWidget( htmlSplitter );
506 htmlSplitter->addWidget( htmlConfigWiget );
507 htmlSplitter->setChildrenCollapsible(
false );
508 htmlSplitter->setHandleWidth( 6 );
509 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
510 layout->addWidget( baseWidget );
512 QLineEdit *title =
new QLineEdit( itemName );
515 QgsCodeEditorHTML *htmlCode =
new QgsCodeEditorHTML();
516 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
519 QgsHtmlWidgetWrapper *htmlWrapper =
new QgsHtmlWidgetWrapper(
mLayer,
nullptr,
this );
520 QgsFeature previewFeature;
521 mLayer->getFeatures().nextFeature( previewFeature );
524 connect( htmlCode, &QgsCodeEditorHTML::textChanged,
this, [htmlWrapper, htmlCode, previewFeature] {
530 QgsFieldExpressionWidget *expressionWidget =
new QgsFieldExpressionWidget;
531 expressionWidget->setButtonVisible(
false );
532 expressionWidget->registerExpressionContextGenerator(
this );
533 expressionWidget->setLayer(
mLayer );
534 QToolButton *addFieldButton =
new QToolButton();
537 QToolButton *editExpressionButton =
new QToolButton();
539 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
541 connect( addFieldButton, &QAbstractButton::clicked,
this, [expressionWidget, htmlCode] {
542 QString expression = expressionWidget->expression().trimmed().replace(
'"',
"\\\""_L1 );
543 if ( !expression.isEmpty() )
544 htmlCode->
insertText( u
"<script>document.write(expression.evaluate(\"%1\"));</script>"_s.arg( expression ) );
547 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, htmlCode] {
550 expression.replace(
"\\\""_L1,
"\""_L1 );
552 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, u
"generic"_s, context );
554 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
555 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
557 QString expression = exprDlg.expressionText().trimmed().replace(
'"',
"\\\""_L1 );
558 if ( !expression.isEmpty() )
559 htmlCode->
insertText( u
"<script>document.write(expression.evaluate(\"%1\"));</script>"_s.arg( expression ) );
563 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
564 layout->addWidget( title );
565 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"HTML Code" ) );
566 layout->addWidget( expressionWidgetBox );
567 expressionWidgetBox->setLayout(
new QHBoxLayout );
568 expressionWidgetBox->layout()->addWidget( expressionWidget );
569 expressionWidgetBox->layout()->addWidget( addFieldButton );
570 expressionWidgetBox->layout()->addWidget( editExpressionButton );
571 layout->addWidget( htmlCode );
572 QScrollArea *htmlPreviewBox =
new QgsScrollArea();
573 htmlPreviewBox->setLayout(
new QGridLayout );
574 htmlPreviewBox->setMinimumWidth( 200 );
575 htmlPreviewBox->layout()->addWidget( htmlWrapper->
widget() );
577 emit htmlCode->textChanged();
578 htmlSplitter->addWidget( htmlPreviewBox );
579 htmlSplitter->setChildrenCollapsible(
false );
580 htmlSplitter->setHandleWidth( 6 );
581 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
583 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
585 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
586 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
587 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#other-widgets"_s ); } );
589 mainLayout->addWidget( buttonBox );
593 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdCfg;
594 htmlEdCfg.
htmlCode = htmlCode->text();
596 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
607 dlg.setObjectName(
"Text Form Configuration Widget" );
609 dlg.setWindowTitle( tr(
"Configure Text Widget" ) );
611 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
612 QSplitter *textSplitter =
new QSplitter();
613 QWidget *textConfigWiget =
new QWidget();
614 QVBoxLayout *layout =
new QVBoxLayout( textConfigWiget );
615 layout->setContentsMargins( 0, 0, 0, 0 );
616 mainLayout->addWidget( textSplitter );
617 textSplitter->addWidget( textConfigWiget );
618 layout->addWidget( baseWidget );
620 QLineEdit *title =
new QLineEdit( itemName );
622 QgsCodeEditorHTML *text =
new QgsCodeEditorHTML();
623 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
626 QgsTextWidgetWrapper *textWrapper =
new QgsTextWidgetWrapper(
mLayer,
nullptr,
this );
627 QgsFeature previewFeature;
628 ( void )
mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( previewFeature );
631 connect( text, &QgsCodeEditorExpression::textChanged,
this, [textWrapper, previewFeature, text] {
632 textWrapper->
setText( text->text() );
637 QgsFieldExpressionWidget *expressionWidget =
new QgsFieldExpressionWidget;
638 expressionWidget->setButtonVisible(
false );
639 expressionWidget->registerExpressionContextGenerator(
this );
640 expressionWidget->setLayer(
mLayer );
641 QToolButton *addFieldButton =
new QToolButton();
644 QToolButton *editExpressionButton =
new QToolButton();
646 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
648 connect( addFieldButton, &QAbstractButton::clicked,
this, [expressionWidget, text] {
649 QString expression = expressionWidget->expression().trimmed();
650 if ( !expression.isEmpty() )
651 text->
insertText( u
"[%%1%]"_s.arg( expression ) );
653 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, text] {
657 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, u
"generic"_s, context );
659 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
660 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
662 QString expression = exprDlg.expressionText().trimmed();
663 if ( !expression.isEmpty() )
664 text->
insertText( u
"[%%1%]"_s.arg( expression ) );
668 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
669 layout->addWidget( title );
670 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"Text" ) );
671 layout->addWidget( expressionWidgetBox );
672 expressionWidgetBox->setLayout(
new QHBoxLayout );
673 expressionWidgetBox->layout()->addWidget( expressionWidget );
674 expressionWidgetBox->layout()->addWidget( addFieldButton );
675 expressionWidgetBox->layout()->addWidget( editExpressionButton );
676 layout->addWidget( text );
677 QScrollArea *textPreviewBox =
new QgsScrollArea();
678 textPreviewBox->setWidgetResizable(
true );
679 textPreviewBox->setMinimumWidth( 200 );
680 textPreviewBox->setWidget( textWrapper->
widget() );
682 emit text->textChanged();
683 textSplitter->addWidget( textPreviewBox );
684 textSplitter->setChildrenCollapsible(
false );
685 textSplitter->setHandleWidth( 6 );
686 textSplitter->setSizes( QList<int>() << 1 << 1 );
688 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
690 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
691 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
692 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#other-widgets"_s ); } );
694 mainLayout->addWidget( buttonBox );
698 QgsAttributesFormData::TextElementEditorConfiguration textEdCfg;
699 textEdCfg.
text = text->text();
701 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
712 dlg.setObjectName(
"Spacer Form Configuration Widget" );
714 dlg.setWindowTitle( tr(
"Configure Spacer Widget" ) );
716 QVBoxLayout *mainLayout =
new QVBoxLayout();
717 mainLayout->addWidget(
new QLabel( tr(
"Title" ) ) );
718 QLineEdit *title =
new QLineEdit( itemName );
719 mainLayout->addWidget( title );
721 QHBoxLayout *cbLayout =
new QHBoxLayout();
722 mainLayout->addLayout( cbLayout );
723 dlg.setLayout( mainLayout );
724 QCheckBox *cb =
new QCheckBox { &dlg };
726 cbLayout->addWidget(
new QLabel( tr(
"Draw horizontal line" ), &dlg ) );
727 cbLayout->addWidget( cb );
729 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
731 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
732 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
733 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#other-widgets"_s ); } );
735 mainLayout->addWidget( buttonBox );
739 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdCfg;
740 spacerEdCfg.
drawLine = cb->isChecked();
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A text editor based on QScintilla2.
void setText(const QString &text) override
void setEditingTimeoutInterval(int timeout)
Sets the timeout (in milliseconds) threshold for the editingTimeout() signal to be emitted after an e...
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
void editingTimeout()
Emitted when either:
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 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.
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...
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
static QgsProject * instance()
Returns the QgsProject singleton instance.
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 dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.