20 #include "qgsexpression.h" 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 ) );
46 setStyleSheet( QStringLiteral(
"QToolButton{ background: none; border: 1px solid rgba(0, 0, 0, 0%);} QToolButton:focus { border: 1px solid palette(highlight); }" ) );
48 setIconSize( QSize( iconSize, iconSize ) );
49 setPopupMode( QToolButton::InstantPopup );
53 mDefineMenu =
new QMenu(
this );
54 connect( mDefineMenu, &QMenu::aboutToShow,
this, &QgsPropertyOverrideButton::aboutToShowMenu );
55 connect( mDefineMenu, &QMenu::triggered,
this, &QgsPropertyOverrideButton::menuActionTriggered );
56 setMenu( mDefineMenu );
58 mFieldsMenu =
new QMenu(
this );
59 mActionDataTypes =
new QAction(
this );
61 mActionDataTypes->setMenu( mFieldsMenu );
63 mActionVariables =
new QAction( tr(
"Variable" ),
this );
64 mVariablesMenu =
new QMenu(
this );
65 mActionVariables->setMenu( mVariablesMenu );
67 mActionActive =
new QAction(
this );
68 QFont
f = mActionActive->font();
70 mActionActive->setFont( f );
72 mActionDescription =
new QAction( tr(
"Description…" ),
this );
74 mActionCreateAuxiliaryField =
new QAction( tr(
"Store Data in the Project" ),
this );
75 mActionCreateAuxiliaryField->setCheckable(
true );
77 mActionExpDialog =
new QAction( tr(
"Edit…" ),
this );
78 mActionExpression =
nullptr;
79 mActionPasteExpr =
new QAction( tr(
"Paste" ),
this );
80 mActionCopyExpr =
new QAction( tr(
"Copy" ),
this );
81 mActionClearExpr =
new QAction( tr(
"Clear" ),
this );
82 mActionAssistant =
new QAction( tr(
"Assistant…" ),
this );
83 QFont assistantFont = mActionAssistant->font();
84 assistantFont.setBold(
true );
85 mActionAssistant->setFont( assistantFont );
86 mDefineMenu->addAction( mActionAssistant );
92 init( propertyKey, property, definitions.
value( propertyKey ), layer, auxiliaryStorageEnabled );
98 mAuxiliaryStorageEnabled = auxiliaryStorageEnabled;
102 mDefinition = definition;
103 mDataTypes = mDefinition.
dataType();
105 mInputDescription = mDefinition.
helpText();
106 mFullDescription.clear();
110 mDataTypesString.clear();
113 switch ( mDataTypes )
116 ts << tr(
"boolean" );
121 ts << tr(
"double" );
125 ts << tr(
"string" );
131 mDataTypesString = ts.join( QStringLiteral(
", " ) );
132 mActionDataTypes->setText( tr(
"Field type: " ) + mDataTypesString );
141 init( propertyKey, collection.
property( propertyKey ), definitions, layer, auxiliaryStorageEnabled );
147 mFieldNameList.clear();
148 mFieldTypeList.clear();
155 bool fieldMatch =
false;
158 switch ( mDataTypes )
169 fieldMatch = f.
type() == QVariant::String;
175 case QVariant::String:
176 fieldType = tr(
"string" );
179 fieldType = tr(
"integer" );
181 case QVariant::LongLong:
182 fieldType = tr(
"integer64" );
184 case QVariant::Double:
185 fieldType = tr(
"double" );
188 fieldType = tr(
"boolean" );
191 fieldType = tr(
"unknown type" );
195 mFieldNameList << f.
name();
196 mFieldTypeList << fieldType;
209 mVectorLayer = layer;
214 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
216 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingCheckState )
219 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingCheckState, natural ) );
225 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
227 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingEnableState )
230 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingEnableState, natural ) );
236 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
238 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingVisibility )
241 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingVisibility, natural ) );
247 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
249 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingExpressionText )
252 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingExpressionText ) );
260 if ( ( event->modifiers() & ( Qt::ControlModifier ) )
261 ||
event->button() == Qt::RightButton )
263 setActivePrivate( !mProperty.
isActive() );
271 QToolButton::mousePressEvent( event );
285 mFieldName =
property.field();
290 mExpressionString =
property.expressionString();
298 mExpressionString.clear();
300 mProperty = property;
306 void QgsPropertyOverrideButton::aboutToShowMenu()
308 mDefineMenu->clear();
312 bool hasExp = !mExpressionString.isEmpty();
313 QString ddTitle = tr(
"Data defined override" );
315 QAction *ddTitleAct = mDefineMenu->addAction( ddTitle );
316 QFont titlefont = ddTitleAct->font();
317 titlefont.setItalic(
true );
318 ddTitleAct->setFont( titlefont );
319 ddTitleAct->setEnabled(
false );
321 bool addActiveAction =
false;
324 QgsExpression exp( mExpressionString );
326 addActiveAction = !exp.hasParserError();
331 addActiveAction = mFieldNameList.contains( mFieldName );
334 if ( addActiveAction )
337 mDefineMenu->addAction( mActionActive );
338 mActionActive->setText( mProperty.
isActive() ? tr(
"Deactivate" ) : tr(
"Activate" ) );
339 mActionActive->setData( QVariant( !mProperty.
isActive() ) );
342 if ( !mFullDescription.isEmpty() )
344 mDefineMenu->addAction( mActionDescription );
347 mDefineMenu->addSeparator();
350 if ( mAuxiliaryStorageEnabled && mVectorLayer )
352 mDefineMenu->addAction( mActionCreateAuxiliaryField );
356 mActionCreateAuxiliaryField->setEnabled(
true );
357 mActionCreateAuxiliaryField->setChecked(
false );
361 if ( index >= 0 && alayer && mVectorLayer->
isAuxiliaryField( index, srcIndex ) )
363 mActionCreateAuxiliaryField->setEnabled(
false );
364 mActionCreateAuxiliaryField->setChecked(
true );
368 bool fieldActive =
false;
369 if ( !mDataTypesString.isEmpty() )
371 QAction *fieldTitleAct = mDefineMenu->addAction( tr(
"Attribute field" ) );
372 fieldTitleAct->setFont( titlefont );
373 fieldTitleAct->setEnabled(
false );
375 mDefineMenu->addAction( mActionDataTypes );
377 mFieldsMenu->clear();
379 if ( !mFieldNameList.isEmpty() )
382 for (
int j = 0; j < mFieldNameList.count(); ++j )
384 QString fldname = mFieldNameList.at( j );
385 QAction *act = mFieldsMenu->addAction( fldname +
" (" + mFieldTypeList.at( j ) +
')' );
386 act->setData( QVariant( fldname ) );
387 if ( mFieldName == fldname )
389 act->setCheckable(
true );
397 QAction *act = mFieldsMenu->addAction( tr(
"No matching field types found" ) );
398 act->setEnabled(
false );
401 mDefineMenu->addSeparator();
404 mFieldsMenu->menuAction()->setCheckable(
true );
407 QAction *exprTitleAct = mDefineMenu->addAction( tr(
"Expression" ) );
408 exprTitleAct->setFont( titlefont );
409 exprTitleAct->setEnabled(
false );
411 mVariablesMenu->clear();
412 bool variableActive =
false;
413 if ( mExpressionContextGenerator )
417 Q_FOREACH (
const QString &variable, variables )
421 if ( variable.startsWith(
'_' ) )
424 QAction *act = mVariablesMenu->addAction( variable );
425 act->setData( QVariant( variable ) );
429 act->setCheckable(
true );
430 act->setChecked(
true );
431 variableActive =
true;
436 if ( mVariablesMenu->actions().isEmpty() )
438 QAction *act = mVariablesMenu->addAction( tr(
"No variables set" ) );
439 act->setEnabled(
false );
442 mDefineMenu->addAction( mActionVariables );
443 mVariablesMenu->menuAction()->setCheckable(
true );
444 mVariablesMenu->menuAction()->setChecked( variableActive && !mProperty.
transformer() );
448 QString expString = mExpressionString;
449 if ( expString.length() > 35 )
451 expString.truncate( 35 );
452 expString.append( QChar( 0x2026 ) );
455 expString.prepend( tr(
"Current: " ) );
457 if ( !mActionExpression )
459 mActionExpression =
new QAction( expString,
this );
460 mActionExpression->setCheckable(
true );
464 mActionExpression->setText( expString );
466 mDefineMenu->addAction( mActionExpression );
469 mDefineMenu->addAction( mActionExpDialog );
470 mDefineMenu->addAction( mActionCopyExpr );
471 mDefineMenu->addAction( mActionPasteExpr );
472 mDefineMenu->addAction( mActionClearExpr );
476 mDefineMenu->addAction( mActionExpDialog );
477 mDefineMenu->addAction( mActionPasteExpr );
482 mDefineMenu->addSeparator();
483 mActionAssistant->setCheckable( mProperty.
transformer() );
484 mActionAssistant->setChecked( mProperty.
transformer() );
485 mDefineMenu->addAction( mActionAssistant );
489 void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
491 if ( action == mActionActive )
493 setActivePrivate( mActionActive->data().toBool() );
497 else if ( action == mActionDescription )
499 showDescriptionDialog();
501 else if ( action == mActionExpDialog )
503 showExpressionDialog();
505 else if ( action == mActionExpression )
509 setActivePrivate(
true );
514 else if ( action == mActionCopyExpr )
516 QApplication::clipboard()->setText( mExpressionString );
518 else if ( action == mActionPasteExpr )
520 QString exprString = QApplication::clipboard()->text();
521 if ( !exprString.isEmpty() )
523 mExpressionString = exprString;
526 setActivePrivate(
true );
532 else if ( action == mActionClearExpr )
534 setActivePrivate(
false );
537 mExpressionString.clear();
542 else if ( action == mActionAssistant )
546 else if ( action == mActionCreateAuxiliaryField )
550 else if ( mFieldsMenu->actions().contains( action ) )
552 if ( action->isEnabled() )
554 if ( mFieldName != action->text() )
556 mFieldName = action->data().toString();
560 setActivePrivate(
true );
566 else if ( mVariablesMenu->actions().contains( action ) )
568 if ( mExpressionString != action->text().prepend(
"@" ) )
570 mExpressionString = action->data().toString().prepend(
"@" );
574 setActivePrivate(
true );
581 void QgsPropertyOverrideButton::showDescriptionDialog()
584 mv->setWindowTitle( tr(
"Data Definition Description" ) );
590 void QgsPropertyOverrideButton::showExpressionDialog()
598 QgsExpressionBuilderDialog d( const_cast<QgsVectorLayer *>( mVectorLayer ), currentExpression,
this, QStringLiteral(
"generic" ), context );
599 if ( d.exec() == QDialog::Accepted )
604 setActivePrivate( !mExpressionString.isEmpty() );
611 void QgsPropertyOverrideButton::showAssistant()
631 mFieldName = this->mProperty.
field();
643 QDialog *dlg =
new QDialog(
this );
644 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
646 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
648 dlg->setLayout(
new QVBoxLayout() );
649 dlg->layout()->addWidget( widget );
650 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
651 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
652 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
653 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
654 dlg->layout()->addWidget( buttonBox );
656 if ( dlg->exec() == QDialog::Accepted )
660 mFieldName = mProperty.
field();
666 settings.
setValue( key, dlg->saveGeometry() );
670 void QgsPropertyOverrideButton::updateGui()
672 bool hasExp = !mExpressionString.isEmpty();
673 bool hasField = !mFieldName.isEmpty();
676 QString deftip = tr(
"undefined" );
681 QgsExpression exp( mExpressionString );
682 if ( exp.hasParserError() )
685 deftip = tr(
"Parse error: %1" ).arg( exp.parserErrorString() );
692 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
695 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
702 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
704 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
706 if ( !mUsageInfo.isEmpty() )
708 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
711 if ( !mInputDescription.isEmpty() )
713 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
716 if ( !mDataTypesString.isEmpty() )
718 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
721 QString deftype( QLatin1String(
"" ) );
722 if ( deftip != tr(
"undefined" ) )
728 if ( deftip.length() > 75 )
730 deftip.truncate( 75 );
731 deftip.append( QChar( 0x2026 ) );
734 mFullDescription += tr(
"<b>Current definition %1:</b><br>%2" ).arg( deftype, deftip );
736 setToolTip( mFullDescription );
740 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
749 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
752 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
754 switch ( sw.mSiblingType )
757 case SiblingCheckState:
762 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
763 if ( btn && btn->isCheckable() )
765 btn->setChecked( sw.mNatural ? state : !state );
769 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
770 if ( grpbx && grpbx->isCheckable() )
772 grpbx->setChecked( sw.mNatural ? state : !state );
779 case SiblingEnableState:
781 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
783 le->setReadOnly( sw.mNatural ? !state : state );
785 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
789 case SiblingVisibility:
791 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
795 case SiblingExpressionText:
797 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
804 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
835 mExpressionContextGenerator = generator;
838 void QgsPropertyOverrideButton::showHelp()
840 QgsHelp::openHelp( QStringLiteral(
"introduction/general_tools.html#data-defined" ) );
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.
static const double UI_SCALE_FACTOR
UI scaling factor.
This class is a composition of two QSettings instances:
Expression based property (QgsExpressionBasedProperty)
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.
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.
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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
Get 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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
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.