29 #include <QMouseEvent> 35 : QToolButton( parent )
36 , mVectorLayer( layer )
39 setFocusPolicy( Qt::StrongFocus );
45 setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
47 ss += QStringLiteral(
"QToolButton{ background: none; border: 1px solid rgba(0, 0, 0, 0%); } QToolButton:focus { border: 1px solid palette(highlight); }" );
49 ss += QStringLiteral(
"QToolButton::menu-indicator{ width: 5px; }" );
53 setIconSize( QSize( iconSize, iconSize ) );
54 setPopupMode( QToolButton::InstantPopup );
58 mDefineMenu =
new QMenu(
this );
59 connect( mDefineMenu, &QMenu::aboutToShow,
this, &QgsPropertyOverrideButton::aboutToShowMenu );
60 connect( mDefineMenu, &QMenu::triggered,
this, &QgsPropertyOverrideButton::menuActionTriggered );
61 setMenu( mDefineMenu );
63 mFieldsMenu =
new QMenu(
this );
64 mActionDataTypes =
new QAction(
this );
66 mActionDataTypes->setMenu( mFieldsMenu );
68 mActionVariables =
new QAction( tr(
"Variable" ),
this );
69 mVariablesMenu =
new QMenu(
this );
70 mActionVariables->setMenu( mVariablesMenu );
72 mActionActive =
new QAction(
this );
73 QFont f = mActionActive->font();
75 mActionActive->setFont( f );
77 mActionDescription =
new QAction( tr(
"Description…" ),
this );
79 mActionCreateAuxiliaryField =
new QAction( tr(
"Store Data in the Project" ),
this );
80 mActionCreateAuxiliaryField->setCheckable(
true );
82 mActionExpDialog =
new QAction( tr(
"Edit…" ),
this );
83 mActionExpression =
nullptr;
84 mActionPasteExpr =
new QAction( tr(
"Paste" ),
this );
85 mActionCopyExpr =
new QAction( tr(
"Copy" ),
this );
86 mActionClearExpr =
new QAction( tr(
"Clear" ),
this );
87 mActionAssistant =
new QAction( tr(
"Assistant…" ),
this );
88 QFont assistantFont = mActionAssistant->font();
89 assistantFont.setBold(
true );
90 mActionAssistant->setFont( assistantFont );
91 mDefineMenu->addAction( mActionAssistant );
97 init( propertyKey, property, definitions.
value( propertyKey ), layer, auxiliaryStorageEnabled );
102 mVectorLayer = layer;
103 mAuxiliaryStorageEnabled = auxiliaryStorageEnabled;
107 mDefinition = definition;
108 mDataTypes = mDefinition.
dataType();
110 mInputDescription = mDefinition.
helpText();
111 mFullDescription.clear();
115 mDataTypesString.clear();
118 switch ( mDataTypes )
121 ts << tr(
"boolean" );
126 ts << tr(
"double" );
130 ts << tr(
"string" );
136 mDataTypesString = ts.join( QStringLiteral(
", " ) );
137 mActionDataTypes->setText( tr(
"Field type: " ) + mDataTypesString );
146 init( propertyKey, collection.
property( propertyKey ), definitions, layer, auxiliaryStorageEnabled );
152 mFieldNameList.clear();
153 mFieldTypeList.clear();
160 bool fieldMatch =
false;
163 switch ( mDataTypes )
174 fieldMatch = f.
type() == QVariant::String;
180 case QVariant::String:
181 fieldType = tr(
"string" );
184 fieldType = tr(
"integer" );
186 case QVariant::LongLong:
187 fieldType = tr(
"integer64" );
189 case QVariant::Double:
190 fieldType = tr(
"double" );
193 fieldType = tr(
"boolean" );
196 fieldType = tr(
"unknown type" );
200 mFieldNameList << f.
name();
201 mFieldTypeList << fieldType;
214 mVectorLayer = layer;
219 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
221 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingCheckState )
224 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingCheckState, natural ) );
230 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
232 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingEnableState )
235 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingEnableState, natural ) );
241 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
243 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingVisibility )
246 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingVisibility, natural ) );
252 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
254 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingExpressionText )
257 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingExpressionText ) );
265 if ( ( event->modifiers() & ( Qt::ControlModifier ) )
266 ||
event->button() == Qt::RightButton )
268 setActivePrivate( !mProperty.
isActive() );
276 QToolButton::mousePressEvent( event );
290 mFieldName =
property.field();
295 mExpressionString =
property.expressionString();
303 mExpressionString.clear();
305 mProperty = property;
311 void QgsPropertyOverrideButton::aboutToShowMenu()
313 mDefineMenu->clear();
317 bool hasExp = !mExpressionString.isEmpty();
318 QString ddTitle = tr(
"Data defined override" );
320 QAction *ddTitleAct = mDefineMenu->addAction( ddTitle );
321 QFont titlefont = ddTitleAct->font();
322 titlefont.setItalic(
true );
323 ddTitleAct->setFont( titlefont );
324 ddTitleAct->setEnabled(
false );
326 bool addActiveAction =
false;
336 addActiveAction = mFieldNameList.contains( mFieldName );
339 if ( addActiveAction )
342 mDefineMenu->addAction( mActionActive );
343 mActionActive->setText( mProperty.
isActive() ? tr(
"Deactivate" ) : tr(
"Activate" ) );
344 mActionActive->setData( QVariant( !mProperty.
isActive() ) );
347 if ( !mFullDescription.isEmpty() )
349 mDefineMenu->addAction( mActionDescription );
352 mDefineMenu->addSeparator();
355 if ( mAuxiliaryStorageEnabled && mVectorLayer )
357 mDefineMenu->addAction( mActionCreateAuxiliaryField );
361 mActionCreateAuxiliaryField->setEnabled(
true );
362 mActionCreateAuxiliaryField->setChecked(
false );
366 if ( index >= 0 && alayer && mVectorLayer->
isAuxiliaryField( index, srcIndex ) )
368 mActionCreateAuxiliaryField->setEnabled(
false );
369 mActionCreateAuxiliaryField->setChecked(
true );
373 bool fieldActive =
false;
374 if ( !mDataTypesString.isEmpty() )
376 QAction *fieldTitleAct = mDefineMenu->addAction( tr(
"Attribute Field" ) );
377 fieldTitleAct->setFont( titlefont );
378 fieldTitleAct->setEnabled(
false );
380 mDefineMenu->addAction( mActionDataTypes );
382 mFieldsMenu->clear();
384 if ( !mFieldNameList.isEmpty() )
387 for (
int j = 0; j < mFieldNameList.count(); ++j )
389 QString fldname = mFieldNameList.at( j );
390 QAction *act = mFieldsMenu->addAction( fldname +
" (" + mFieldTypeList.at( j ) +
')' );
391 act->setData( QVariant( fldname ) );
392 if ( mFieldName == fldname )
394 act->setCheckable(
true );
402 QAction *act = mFieldsMenu->addAction( tr(
"No matching field types found" ) );
403 act->setEnabled(
false );
406 mDefineMenu->addSeparator();
409 mFieldsMenu->menuAction()->setCheckable(
true );
412 QAction *exprTitleAct = mDefineMenu->addAction( tr(
"Expression" ) );
413 exprTitleAct->setFont( titlefont );
414 exprTitleAct->setEnabled(
false );
416 mVariablesMenu->clear();
417 bool variableActive =
false;
418 if ( mExpressionContextGenerator )
422 Q_FOREACH (
const QString &variable, variables )
426 if ( variable.startsWith(
'_' ) )
429 QAction *act = mVariablesMenu->addAction( variable );
430 act->setData( QVariant( variable ) );
434 act->setCheckable(
true );
435 act->setChecked(
true );
436 variableActive =
true;
441 if ( mVariablesMenu->actions().isEmpty() )
443 QAction *act = mVariablesMenu->addAction( tr(
"No variables set" ) );
444 act->setEnabled(
false );
447 mDefineMenu->addAction( mActionVariables );
448 mVariablesMenu->menuAction()->setCheckable(
true );
449 mVariablesMenu->menuAction()->setChecked( variableActive && !mProperty.
transformer() );
453 QString expString = mExpressionString;
454 if ( expString.length() > 35 )
456 expString.truncate( 35 );
457 expString.append( QChar( 0x2026 ) );
460 expString.prepend( tr(
"Current: " ) );
462 if ( !mActionExpression )
464 mActionExpression =
new QAction( expString,
this );
465 mActionExpression->setCheckable(
true );
469 mActionExpression->setText( expString );
471 mDefineMenu->addAction( mActionExpression );
474 mDefineMenu->addAction( mActionExpDialog );
475 mDefineMenu->addAction( mActionCopyExpr );
476 mDefineMenu->addAction( mActionPasteExpr );
477 mDefineMenu->addAction( mActionClearExpr );
481 mDefineMenu->addAction( mActionExpDialog );
482 mDefineMenu->addAction( mActionPasteExpr );
487 mDefineMenu->addSeparator();
488 mActionAssistant->setCheckable( mProperty.
transformer() );
489 mActionAssistant->setChecked( mProperty.
transformer() );
490 mDefineMenu->addAction( mActionAssistant );
494 void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
496 if ( action == mActionActive )
498 setActivePrivate( mActionActive->data().toBool() );
502 else if ( action == mActionDescription )
504 showDescriptionDialog();
506 else if ( action == mActionExpDialog )
508 showExpressionDialog();
510 else if ( action == mActionExpression )
514 setActivePrivate(
true );
519 else if ( action == mActionCopyExpr )
521 QApplication::clipboard()->setText( mExpressionString );
523 else if ( action == mActionPasteExpr )
525 QString exprString = QApplication::clipboard()->text();
526 if ( !exprString.isEmpty() )
528 mExpressionString = exprString;
531 setActivePrivate(
true );
537 else if ( action == mActionClearExpr )
539 setActivePrivate(
false );
542 mExpressionString.clear();
547 else if ( action == mActionAssistant )
551 else if ( action == mActionCreateAuxiliaryField )
555 else if ( mFieldsMenu->actions().contains( action ) )
557 if ( action->isEnabled() )
559 if ( mFieldName != action->text() )
561 mFieldName = action->data().toString();
565 setActivePrivate(
true );
571 else if ( mVariablesMenu->actions().contains( action ) )
573 if ( mExpressionString != action->text().prepend(
"@" ) )
575 mExpressionString = action->data().toString().prepend(
"@" );
579 setActivePrivate(
true );
586 void QgsPropertyOverrideButton::showDescriptionDialog()
589 mv->setWindowTitle( tr(
"Data Definition Description" ) );
595 void QgsPropertyOverrideButton::showExpressionDialog()
603 QgsExpressionBuilderDialog d( const_cast<QgsVectorLayer *>( mVectorLayer ), currentExpression,
this, QStringLiteral(
"generic" ), context );
605 if ( d.exec() == QDialog::Accepted )
610 setActivePrivate( !mExpressionString.isEmpty() );
617 void QgsPropertyOverrideButton::showAssistant()
637 mFieldName = this->mProperty.
field();
649 QDialog *dlg =
new QDialog(
this );
650 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
652 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
654 dlg->setLayout(
new QVBoxLayout() );
655 dlg->layout()->addWidget( widget );
656 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
657 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
658 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
659 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
660 dlg->layout()->addWidget( buttonBox );
662 if ( dlg->exec() == QDialog::Accepted )
666 mFieldName = mProperty.
field();
672 settings.
setValue( key, dlg->saveGeometry() );
676 void QgsPropertyOverrideButton::updateGui()
678 bool hasExp = !mExpressionString.isEmpty();
679 bool hasField = !mFieldName.isEmpty();
682 QString deftip = tr(
"undefined" );
695 deftip = mExpressionString;
702 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
705 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
716 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
718 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
720 if ( !mUsageInfo.isEmpty() )
722 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
725 if ( !mInputDescription.isEmpty() )
727 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
730 if ( !mDataTypesString.isEmpty() )
732 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
736 if ( deftip != tr(
"undefined" ) )
742 if ( deftip.length() > 75 )
744 deftip.truncate( 75 );
745 deftip.append( QChar( 0x2026 ) );
748 mFullDescription += tr(
"<b>Current definition %1:</b><br>%2" ).arg( deftype, deftip );
750 setToolTip( mFullDescription );
754 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
763 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
766 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
768 switch ( sw.mSiblingType )
771 case SiblingCheckState:
776 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
777 if ( btn && btn->isCheckable() )
779 btn->setChecked( sw.mNatural ? state : !state );
783 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
784 if ( grpbx && grpbx->isCheckable() )
786 grpbx->setChecked( sw.mNatural ? state : !state );
793 case SiblingEnableState:
795 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
797 le->setReadOnly( sw.mNatural ? !state : state );
799 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
803 case SiblingVisibility:
805 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
809 case SiblingExpressionText:
811 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
818 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
849 mExpressionContextGenerator = generator;
852 void QgsPropertyOverrideButton::showHelp()
854 QgsHelp::openHelp( QStringLiteral(
"introduction/general_tools.html#data-defined" ) );
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
bool supportsAssistant() const
Returns true if the property is of a type which is compatible with property override assistants...
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Field based property (QgsFieldBasedProperty)
bool isReadOnly(const QString &name) const
Returns whether a variable is read only, and should not be modifiable by users.
void setExpectedOutputFormat(const QString &expected)
The set expected format string.
static const double UI_SCALE_FACTOR
UI scaling factor.
This class is a composition of two QSettings instances:
Expression based property (QgsExpressionBasedProperty)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Class allowing to manage the auxiliary storage for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
QString parserErrorString() const
Returns parser error.
const QgsPropertyTransformer * transformer() const
Returns the existing transformer used for manipulating the calculated values for the property...
void setMessageAsHtml(const QString &msg)
void setField(const QString &field)
Sets the field name the property references.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
DataType dataType() const
Returns the allowable field/value data type for the property.
Type propertyType() const
Returns the property type.
QgsFields fields() const override
Returns the list of fields of this layer.
Property requires a boolean value.
bool convertToTransformer()
Attempts to convert an existing expression based property to a base expression with corresponding tra...
void setActive(bool active)
Sets whether the property is currently active.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Abstract base class for QgsPropertyCollection like objects.
Property requires a numeric value.
virtual QgsProperty property(int key) const =0
Returns a matching property from the collection, if one exists.
Encapsulate a field in an attribute table or data source.
QStringList variableNames() const
Returns a list of variables names set by all scopes in the context.
A store for object properties.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
void setExpressionString(const QString &expression)
Sets the expression to use for the property value.
Definition for a property.
QString field() const
Returns the current field name the property references.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
QString helpText() const
Helper text for using the property, including a description of the valid values for the property...
Abstract interface for generating an expression context.
Property requires a string value.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
A generic message view for displaying QGIS messages.
QVariant staticValue() const
Returns the current static value for the property.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
QString name() const
Returns the name of the property.
Represents a vector layer which manages a vector based data sets.
Invalid (not set) property.
void setStaticValue(const QVariant &value)
Sets the static value for the property.
A generic dialog for building expression strings.
void setTransformer(QgsPropertyTransformer *transformer)
Sets an optional transformer to use for manipulating the calculated values for the property...
bool isActive() const
Returns whether the property is currently active.