20#include "qgsattributetypedialog.h"
41#include <QPlainTextEdit>
47#include "moc_qgsattributesformview.cpp"
57 if ( selectionModel()->selectedRows( 0 ).count() == 0 )
60 return mModel->mapToSource( selectionModel()->selectedRows( 0 ).at( 0 ) );
80 QModelIndex index =
mModel->mapFromSource( model->firstRecursiveMatchingModelIndex( itemType, itemId ) );
82 if ( index.isValid() )
86 const QModelIndexList selectedIndexes = selectionModel()->selectedRows( 0 );
87 if ( !( selectedIndexes.count() == 1 && selectedIndexes.at( 0 ) == index ) )
89 selectionModel()->setCurrentIndex( index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
94 selectionModel()->clearSelection();
100 mModel->setFilterText( text );
121 viewport()->repaint();
124 viewport()->repaint();
136 const QList<QgsAttributesFormItem *> keys =
mIndicators.keys();
148 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 );
203 onItemDoubleClicked(
mModel->mapFromSource( index ) );
207void QgsAttributesFormLayoutView::handleInternalDroppedItem( QModelIndex &index )
209 selectionModel()->clearCurrentIndex();
213 expandRecursively(
mModel->mapFromSource( index ) );
219 const QMimeData *data =
event->mimeData();
221 if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" ) )
222 || data->hasFormat( QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) ) )
225 if ( event->source() ==
this )
227 event->setDropAction( Qt::MoveAction );
235 QTreeView::dragEnterEvent( event );
244 const QMimeData *data =
event->mimeData();
246 if ( data->hasFormat( QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" ) )
247 || data->hasFormat( QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) ) )
250 if ( event->source() ==
this )
252 event->setDropAction( Qt::MoveAction );
260 QTreeView::dragMoveEvent( event );
265 if ( !( event->mimeData()->hasFormat( QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" ) )
266 || event->mimeData()->hasFormat( QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) ) ) )
269 if ( event->source() ==
this )
271 event->setDropAction( Qt::MoveAction );
274 QTreeView::dropEvent( event );
277void QgsAttributesFormLayoutView::onItemDoubleClicked(
const QModelIndex &index )
279 QModelIndex sourceIndex =
mModel->mapToSource( index );
284 QGroupBox *baseData =
new QGroupBox( tr(
"Base configuration" ) );
286 QFormLayout *baseLayout =
new QFormLayout();
287 baseData->setLayout( baseLayout );
288 QCheckBox *showLabelCheckbox =
new QCheckBox( QStringLiteral(
"Show label" ) );
289 showLabelCheckbox->setChecked( itemData.
showLabel() );
290 baseLayout->addRow( showLabelCheckbox );
291 QWidget *baseWidget =
new QWidget();
292 baseWidget->setLayout( baseLayout );
306 dlg.setObjectName(
"QML Form Configuration Widget" );
308 dlg.setWindowTitle( tr(
"Configure QML Widget" ) );
310 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
311 QSplitter *qmlSplitter =
new QSplitter();
312 QWidget *qmlConfigWiget =
new QWidget();
313 QVBoxLayout *layout =
new QVBoxLayout( qmlConfigWiget );
314 layout->setContentsMargins( 0, 0, 0, 0 );
315 mainLayout->addWidget( qmlSplitter );
316 qmlSplitter->addWidget( qmlConfigWiget );
317 layout->addWidget( baseWidget );
319 QLineEdit *title =
new QLineEdit( itemName );
338 QComboBox *qmlObjectTemplate =
new QComboBox();
339 qmlObjectTemplate->addItem( tr(
"Free Text…" ) );
340 qmlObjectTemplate->addItem( tr(
"Rectangle" ) );
341 qmlObjectTemplate->addItem( tr(
"Pie Chart" ) );
342 qmlObjectTemplate->addItem( tr(
"Bar Chart" ) );
343 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [qmlCode](
int index ) {
354 qmlCode->
setText( QStringLiteral(
"import QtQuick 2.0\n"
359 " color: \"steelblue\"\n"
360 " Text{ text: \"A rectangle\" }\n"
366 qmlCode->
setText( QStringLiteral(
"import QtQuick 2.0\n"
367 "import QtCharts 2.0\n"
375 " PieSlice { label: \"First slice\"; value: 25 }\n"
376 " PieSlice { label: \"Second slice\"; value: 45 }\n"
377 " PieSlice { label: \"Third slice\"; value: 30 }\n"
384 qmlCode->
setText( QStringLiteral(
"import QtQuick 2.0\n"
385 "import QtCharts 2.0\n"
388 " title: \"Bar series\"\n"
391 " legend.alignment: Qt.AlignBottom\n"
392 " antialiasing: true\n"
401 " axisY: valueAxisY\n"
402 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
403 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
404 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
405 " 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(
'"', QLatin1String(
"\\\"" ) );
428 if ( !expression.isEmpty() )
429 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).arg( expression ) );
432 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, qmlCode] {
434 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
436 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, QStringLiteral(
"generic" ), context );
438 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
439 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
441 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
442 if ( !expression.isEmpty() )
443 qmlCode->
insertText( QStringLiteral(
"expression.evaluate(\"%1\")" ).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, [] {
477 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#other-widgets" ) );
480 mainLayout->addWidget( buttonBox );
484 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdCfg;
485 qmlEdCfg.
qmlCode = qmlCode->text();
487 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
498 dlg.setObjectName(
"HTML Form Configuration Widget" );
500 dlg.setWindowTitle( tr(
"Configure HTML Widget" ) );
502 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
503 QSplitter *htmlSplitter =
new QSplitter();
504 QWidget *htmlConfigWiget =
new QWidget();
505 QVBoxLayout *layout =
new QVBoxLayout( htmlConfigWiget );
506 layout->setContentsMargins( 0, 0, 0, 0 );
507 mainLayout->addWidget( htmlSplitter );
508 htmlSplitter->addWidget( htmlConfigWiget );
509 htmlSplitter->setChildrenCollapsible(
false );
510 htmlSplitter->setHandleWidth( 6 );
511 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
512 layout->addWidget( baseWidget );
514 QLineEdit *title =
new QLineEdit( itemName );
517 QgsCodeEditorHTML *htmlCode =
new QgsCodeEditorHTML();
518 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
521 QgsHtmlWidgetWrapper *htmlWrapper =
new QgsHtmlWidgetWrapper(
mLayer,
nullptr,
this );
522 QgsFeature previewFeature;
523 mLayer->getFeatures().nextFeature( previewFeature );
526 connect( htmlCode, &QgsCodeEditorHTML::textChanged,
this, [htmlWrapper, htmlCode, previewFeature] {
532 QgsFieldExpressionWidget *expressionWidget =
new QgsFieldExpressionWidget;
533 expressionWidget->setButtonVisible(
false );
534 expressionWidget->registerExpressionContextGenerator(
this );
535 expressionWidget->setLayer(
mLayer );
536 QToolButton *addFieldButton =
new QToolButton();
539 QToolButton *editExpressionButton =
new QToolButton();
541 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
543 connect( addFieldButton, &QAbstractButton::clicked,
this, [expressionWidget, htmlCode] {
544 QString expression = expressionWidget->expression().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
545 if ( !expression.isEmpty() )
546 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
549 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, htmlCode] {
551 expression.replace( QLatin1String(
"\\\"" ), QLatin1String(
"\"" ) );
553 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, QStringLiteral(
"generic" ), context );
555 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
556 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
558 QString expression = exprDlg.expressionText().trimmed().replace(
'"', QLatin1String(
"\\\"" ) );
559 if ( !expression.isEmpty() )
560 htmlCode->
insertText( QStringLiteral(
"<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
564 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
565 layout->addWidget( title );
566 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"HTML Code" ) );
567 layout->addWidget( expressionWidgetBox );
568 expressionWidgetBox->setLayout(
new QHBoxLayout );
569 expressionWidgetBox->layout()->addWidget( expressionWidget );
570 expressionWidgetBox->layout()->addWidget( addFieldButton );
571 expressionWidgetBox->layout()->addWidget( editExpressionButton );
572 layout->addWidget( htmlCode );
573 QScrollArea *htmlPreviewBox =
new QgsScrollArea();
574 htmlPreviewBox->setLayout(
new QGridLayout );
575 htmlPreviewBox->setMinimumWidth( 200 );
576 htmlPreviewBox->layout()->addWidget( htmlWrapper->
widget() );
578 emit htmlCode->textChanged();
579 htmlSplitter->addWidget( htmlPreviewBox );
580 htmlSplitter->setChildrenCollapsible(
false );
581 htmlSplitter->setHandleWidth( 6 );
582 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
584 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
586 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
587 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
588 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
589 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#other-widgets" ) );
592 mainLayout->addWidget( buttonBox );
596 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdCfg;
597 htmlEdCfg.
htmlCode = htmlCode->text();
599 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
610 dlg.setObjectName(
"Text Form Configuration Widget" );
612 dlg.setWindowTitle( tr(
"Configure Text Widget" ) );
614 QVBoxLayout *mainLayout =
new QVBoxLayout( &dlg );
615 QSplitter *textSplitter =
new QSplitter();
616 QWidget *textConfigWiget =
new QWidget();
617 QVBoxLayout *layout =
new QVBoxLayout( textConfigWiget );
618 layout->setContentsMargins( 0, 0, 0, 0 );
619 mainLayout->addWidget( textSplitter );
620 textSplitter->addWidget( textConfigWiget );
621 layout->addWidget( baseWidget );
623 QLineEdit *title =
new QLineEdit( itemName );
625 QgsCodeEditorHTML *text =
new QgsCodeEditorHTML();
626 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
629 QgsTextWidgetWrapper *textWrapper =
new QgsTextWidgetWrapper(
mLayer,
nullptr,
this );
630 QgsFeature previewFeature;
631 ( void )
mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( previewFeature );
634 connect( text, &QgsCodeEditorExpression::textChanged,
this, [textWrapper, previewFeature, text] {
635 textWrapper->
setText( text->text() );
640 QgsFieldExpressionWidget *expressionWidget =
new QgsFieldExpressionWidget;
641 expressionWidget->setButtonVisible(
false );
642 expressionWidget->registerExpressionContextGenerator(
this );
643 expressionWidget->setLayer(
mLayer );
644 QToolButton *addFieldButton =
new QToolButton();
647 QToolButton *editExpressionButton =
new QToolButton();
649 editExpressionButton->setToolTip( tr(
"Insert/Edit Expression" ) );
651 connect( addFieldButton, &QAbstractButton::clicked,
this, [expressionWidget, text] {
652 QString expression = expressionWidget->expression().trimmed();
653 if ( !expression.isEmpty() )
654 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
656 connect( editExpressionButton, &QAbstractButton::clicked,
this, [
this, text] {
660 QgsExpressionBuilderDialog exprDlg(
mLayer, expression,
this, QStringLiteral(
"generic" ), context );
662 exprDlg.setWindowTitle( tr(
"Insert Expression" ) );
663 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
665 QString expression = exprDlg.expressionText().trimmed();
666 if ( !expression.isEmpty() )
667 text->
insertText( QStringLiteral(
"[%%1%]" ).arg( expression ) );
671 layout->addWidget(
new QLabel( tr(
"Title" ) ) );
672 layout->addWidget( title );
673 QGroupBox *expressionWidgetBox =
new QGroupBox( tr(
"Text" ) );
674 layout->addWidget( expressionWidgetBox );
675 expressionWidgetBox->setLayout(
new QHBoxLayout );
676 expressionWidgetBox->layout()->addWidget( expressionWidget );
677 expressionWidgetBox->layout()->addWidget( addFieldButton );
678 expressionWidgetBox->layout()->addWidget( editExpressionButton );
679 layout->addWidget( text );
680 QScrollArea *textPreviewBox =
new QgsScrollArea();
681 textPreviewBox->setLayout(
new QGridLayout );
682 textPreviewBox->setMinimumWidth( 200 );
683 textPreviewBox->layout()->addWidget( textWrapper->
widget() );
685 emit text->textChanged();
686 textSplitter->addWidget( textPreviewBox );
687 textSplitter->setChildrenCollapsible(
false );
688 textSplitter->setHandleWidth( 6 );
689 textSplitter->setSizes( QList<int>() << 1 << 1 );
691 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
693 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
694 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
695 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
696 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#other-widgets" ) );
699 mainLayout->addWidget( buttonBox );
703 QgsAttributesFormData::TextElementEditorConfiguration textEdCfg;
704 textEdCfg.
text = text->text();
706 itemData.
setShowLabel( showLabelCheckbox->isChecked() );
717 dlg.setObjectName(
"Spacer Form Configuration Widget" );
719 dlg.setWindowTitle( tr(
"Configure Spacer Widget" ) );
721 QVBoxLayout *mainLayout =
new QVBoxLayout();
722 mainLayout->addWidget(
new QLabel( tr(
"Title" ) ) );
723 QLineEdit *title =
new QLineEdit( itemName );
724 mainLayout->addWidget( title );
726 QHBoxLayout *cbLayout =
new QHBoxLayout();
727 mainLayout->addLayout( cbLayout );
728 dlg.setLayout( mainLayout );
729 QCheckBox *cb =
new QCheckBox { &dlg };
731 cbLayout->addWidget(
new QLabel( tr(
"Draw horizontal line" ), &dlg ) );
732 cbLayout->addWidget( cb );
734 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
736 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
737 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
738 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [] {
739 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#other-widgets" ) );
742 mainLayout->addWidget( buttonBox );
746 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdCfg;
747 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.