30 #include <QMouseEvent> 36 : QToolButton( parent )
37 , mVectorLayer( layer )
40 setFocusPolicy( Qt::StrongFocus );
45 setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
47 setIconSize( QSize( iconSize, iconSize ) );
48 setPopupMode( QToolButton::InstantPopup );
52 mDefineMenu =
new QMenu(
this );
53 connect( mDefineMenu, &QMenu::aboutToShow,
this, &QgsPropertyOverrideButton::aboutToShowMenu );
54 connect( mDefineMenu, &QMenu::triggered,
this, &QgsPropertyOverrideButton::menuActionTriggered );
55 setMenu( mDefineMenu );
57 mFieldsMenu =
new QMenu(
this );
58 mActionDataTypes =
new QAction(
this );
60 mActionDataTypes->setMenu( mFieldsMenu );
62 mActionVariables =
new QAction( tr(
"Variable" ),
this );
63 mVariablesMenu =
new QMenu(
this );
64 mActionVariables->setMenu( mVariablesMenu );
66 mActionActive =
new QAction(
this );
67 QFont f = mActionActive->font();
69 mActionActive->setFont( f );
71 mActionDescription =
new QAction( tr(
"Description…" ),
this );
73 mActionCreateAuxiliaryField =
new QAction( tr(
"Store Data in the Project" ),
this );
74 mActionCreateAuxiliaryField->setCheckable(
true );
76 mActionExpDialog =
new QAction( tr(
"Edit…" ),
this );
77 mActionExpression =
nullptr;
78 mActionPasteExpr =
new QAction( tr(
"Paste" ),
this );
79 mActionCopyExpr =
new QAction( tr(
"Copy" ),
this );
80 mActionClearExpr =
new QAction( tr(
"Clear" ),
this );
81 mActionAssistant =
new QAction( tr(
"Assistant…" ),
this );
82 QFont assistantFont = mActionAssistant->font();
83 assistantFont.setBold(
true );
84 mActionAssistant->setFont( assistantFont );
85 mDefineMenu->addAction( mActionAssistant );
91 init( propertyKey, property, definitions.
value( propertyKey ), layer, auxiliaryStorageEnabled );
97 mAuxiliaryStorageEnabled = auxiliaryStorageEnabled;
101 mDefinition = definition;
102 mDataTypes = mDefinition.
dataType();
104 mInputDescription = mDefinition.
helpText();
105 mFullDescription.clear();
109 mDataTypesString.clear();
112 switch ( mDataTypes )
115 ts << tr(
"boolean" );
120 ts << tr(
"double" );
124 ts << tr(
"string" );
130 mDataTypesString = ts.join( QStringLiteral(
", " ) );
131 mActionDataTypes->setText( tr(
"Field type: " ) + mDataTypesString );
140 init( propertyKey, collection.
property( propertyKey ), definitions, layer, auxiliaryStorageEnabled );
146 mFieldNameList.clear();
147 mFieldTypeList.clear();
155 bool fieldMatch =
false;
158 switch ( mDataTypes )
165 fieldMatch = f.isNumeric() || f.type() == QVariant::String;
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;
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 );
475 mDefineMenu->addAction( mActionExpDialog );
476 mDefineMenu->addAction( mActionPasteExpr );
479 if ( hasExp || !mFieldName.isEmpty() )
481 mDefineMenu->addSeparator();
482 mDefineMenu->addAction( mActionClearExpr );
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() );
618 void QgsPropertyOverrideButton::showAssistant()
638 mFieldName = this->mProperty.
field();
651 QDialog *dlg =
new QDialog(
this );
652 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
654 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
656 dlg->setLayout(
new QVBoxLayout() );
657 dlg->layout()->addWidget( widget );
658 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
659 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
660 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
661 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
662 dlg->layout()->addWidget( buttonBox );
664 if ( dlg->exec() == QDialog::Accepted )
668 mFieldName = mProperty.
field();
675 settings.
setValue( key, dlg->saveGeometry() );
679 void QgsPropertyOverrideButton::updateGui()
681 bool hasExp = !mExpressionString.isEmpty();
682 bool hasField = !mFieldName.isEmpty();
685 QString deftip = tr(
"undefined" );
698 deftip = mExpressionString;
705 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
708 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
719 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
721 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
723 if ( !mUsageInfo.isEmpty() )
725 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
728 if ( !mInputDescription.isEmpty() )
730 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
733 if ( !mDataTypesString.isEmpty() )
735 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
739 if ( deftip != tr(
"undefined" ) )
745 if ( deftip.length() > 75 )
747 deftip.truncate( 75 );
748 deftip.append( QChar( 0x2026 ) );
751 mFullDescription += tr(
"<b>Current definition %1:</b><br>%2" ).arg( deftype, deftip );
753 setToolTip( mFullDescription );
757 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
766 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
769 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
771 switch ( sw.mSiblingType )
774 case SiblingCheckState:
779 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
780 if ( btn && btn->isCheckable() )
782 btn->setChecked( sw.mNatural ? state : !state );
786 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
787 if ( grpbx && grpbx->isCheckable() )
789 grpbx->setChecked( sw.mNatural ? state : !state );
796 case SiblingEnableState:
798 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
800 le->setReadOnly( sw.mNatural ? !state : state );
802 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
806 case SiblingVisibility:
808 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
812 case SiblingExpressionText:
814 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
821 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
852 mExpressionContextGenerator = generator;
855 void QgsPropertyOverrideButton::showHelp()
857 QgsHelp::openHelp( QStringLiteral(
"introduction/general_tools.html#data-defined" ) );
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString helpText() const
Helper text for using the property, including a description of the valid values for the property...
Field based property (QgsFieldBasedProperty)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the dialog.
This class is a composition of two QSettings instances:
Expression based property (QgsExpressionBasedProperty)
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
const QgsPropertyTransformer * transformer() const
Returns the existing transformer used for manipulating the calculated values for the property...
Class allowing to manage the auxiliary storage for a vector layer.
bool isActive() const
Returns whether the property is currently active.
DataType dataType() const
Returns the allowable field/value data type for the property.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Container of fields for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QVariant staticValue() const
Returns the current static value for the property.
void setMessageAsHtml(const QString &msg)
void setField(const QString &field)
Sets the field name the property references.
QStringList variableNames() const
Returns a list of variables names set by all scopes in the context.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QString name() const
Returns the name of the property.
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...
Type propertyType() const
Returns the property type.
Abstract base class for QgsPropertyCollection like objects.
Property requires a numeric value.
bool isReadOnly(const QString &name) const
Returns whether a variable is read only, and should not be modifiable by users.
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.
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.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Abstract interface for generating an expression context.
QString field() const
Returns the current field name the property references.
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...
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.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
A generic message view for displaying QGIS messages.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Represents a vector layer which manages a vector based data sets.
Invalid (not set) property.
QString parserErrorString() const
Returns parser error.
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 supportsAssistant() const
Returns true if the property is of a type which is compatible with property override assistants...