32 #include <QMouseEvent> 35 #include <QRegularExpression> 39 : QToolButton( parent )
40 , mVectorLayer( layer )
43 setFocusPolicy( Qt::StrongFocus );
48 setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
50 setIconSize( QSize( iconSize, iconSize ) );
51 setPopupMode( QToolButton::InstantPopup );
55 mDefineMenu =
new QMenu(
this );
56 connect( mDefineMenu, &QMenu::aboutToShow,
this, &QgsPropertyOverrideButton::aboutToShowMenu );
57 connect( mDefineMenu, &QMenu::triggered,
this, &QgsPropertyOverrideButton::menuActionTriggered );
58 setMenu( mDefineMenu );
60 mFieldsMenu =
new QMenu(
this );
61 mActionDataTypes =
new QAction(
this );
63 mActionDataTypes->setMenu( mFieldsMenu );
65 mActionVariables =
new QAction( tr(
"Variable" ),
this );
66 mVariablesMenu =
new QMenu(
this );
67 mActionVariables->setMenu( mVariablesMenu );
69 mActionColors =
new QAction( tr(
"Color" ),
this );
70 mColorsMenu =
new QMenu(
this );
71 mActionColors->setMenu( mColorsMenu );
73 mActionActive =
new QAction(
this );
74 QFont f = mActionActive->font();
76 mActionActive->setFont( f );
78 mActionDescription =
new QAction( tr(
"Description…" ),
this );
80 mActionCreateAuxiliaryField =
new QAction( tr(
"Store Data in the Project" ),
this );
81 mActionCreateAuxiliaryField->setCheckable(
true );
83 mActionExpDialog =
new QAction( tr(
"Edit…" ),
this );
84 mActionExpression =
nullptr;
85 mActionPasteExpr =
new QAction( tr(
"Paste" ),
this );
86 mActionCopyExpr =
new QAction( tr(
"Copy" ),
this );
87 mActionClearExpr =
new QAction( tr(
"Clear" ),
this );
88 mActionAssistant =
new QAction( tr(
"Assistant…" ),
this );
89 QFont assistantFont = mActionAssistant->font();
90 assistantFont.setBold(
true );
91 mActionAssistant->setFont( assistantFont );
92 mDefineMenu->addAction( mActionAssistant );
98 init( propertyKey, property, definitions.
value( propertyKey ), layer, auxiliaryStorageEnabled );
103 mVectorLayer = layer;
104 mAuxiliaryStorageEnabled = auxiliaryStorageEnabled;
108 mDefinition = definition;
109 mDataTypes = mDefinition.
dataType();
111 mInputDescription = mDefinition.
helpText();
112 mFullDescription.clear();
116 mDataTypesString.clear();
119 switch ( mDataTypes )
122 ts << tr(
"boolean" );
127 ts << tr(
"double" );
131 ts << tr(
"string" );
137 mDataTypesString = ts.join( QStringLiteral(
", " ) );
138 mActionDataTypes->setText( tr(
"Field type: " ) + mDataTypesString );
148 init( propertyKey, collection.
property( propertyKey ), definitions, layer, auxiliaryStorageEnabled );
154 mFieldNameList.clear();
155 mFieldTypeList.clear();
163 bool fieldMatch =
false;
166 switch ( mDataTypes )
173 fieldMatch = f.isNumeric() || f.type() == QVariant::String;
177 fieldMatch = f.type() == QVariant::String;
183 case QVariant::String:
184 fieldType = tr(
"string" );
187 fieldType = tr(
"integer" );
189 case QVariant::LongLong:
190 fieldType = tr(
"integer64" );
192 case QVariant::Double:
193 fieldType = tr(
"double" );
196 fieldType = tr(
"boolean" );
199 fieldType = tr(
"unknown type" );
203 mFieldNameList << f.name();
204 mFieldTypeList << fieldType;
217 mVectorLayer = layer;
222 const auto constMSiblingWidgets = mSiblingWidgets;
223 for (
const SiblingWidget &sw : constMSiblingWidgets )
225 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingCheckState )
228 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingCheckState, natural ) );
234 const auto constMSiblingWidgets = mSiblingWidgets;
235 for (
const SiblingWidget &sw : constMSiblingWidgets )
237 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingEnableState )
240 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingEnableState, natural ) );
246 const auto constMSiblingWidgets = mSiblingWidgets;
247 for (
const SiblingWidget &sw : constMSiblingWidgets )
249 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingVisibility )
252 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingVisibility, natural ) );
258 const auto constMSiblingWidgets = mSiblingWidgets;
259 for (
const SiblingWidget &sw : constMSiblingWidgets )
261 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingExpressionText )
264 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingExpressionText ) );
272 if ( ( event->modifiers() & ( Qt::ControlModifier ) )
273 ||
event->button() == Qt::RightButton )
275 setActivePrivate( !mProperty.
isActive() );
283 QToolButton::mousePressEvent( event );
297 mFieldName =
property.field();
302 mExpressionString =
property.expressionString();
310 mExpressionString.clear();
312 mProperty = property;
319 void QgsPropertyOverrideButton::aboutToShowMenu()
321 mDefineMenu->clear();
325 bool hasExp = !mExpressionString.isEmpty();
326 QString ddTitle = tr(
"Data defined override" );
328 QAction *ddTitleAct = mDefineMenu->addAction( ddTitle );
329 QFont titlefont = ddTitleAct->font();
330 titlefont.setItalic(
true );
331 ddTitleAct->setFont( titlefont );
332 ddTitleAct->setEnabled(
false );
334 bool addActiveAction =
false;
344 addActiveAction = mFieldNameList.contains( mFieldName );
347 if ( addActiveAction )
350 mDefineMenu->addAction( mActionActive );
351 mActionActive->setText( mProperty.
isActive() ? tr(
"Deactivate" ) : tr(
"Activate" ) );
352 mActionActive->setData( QVariant( !mProperty.
isActive() ) );
355 if ( !mFullDescription.isEmpty() )
357 mDefineMenu->addAction( mActionDescription );
360 mDefineMenu->addSeparator();
363 if ( mAuxiliaryStorageEnabled && mVectorLayer )
365 mDefineMenu->addAction( mActionCreateAuxiliaryField );
369 mActionCreateAuxiliaryField->setEnabled(
true );
370 mActionCreateAuxiliaryField->setChecked(
false );
374 if ( index >= 0 && alayer && mVectorLayer->
isAuxiliaryField( index, srcIndex ) )
376 mActionCreateAuxiliaryField->setEnabled(
false );
377 mActionCreateAuxiliaryField->setChecked(
true );
381 bool fieldActive =
false;
382 if ( !mDataTypesString.isEmpty() )
384 QAction *fieldTitleAct = mDefineMenu->addAction( tr(
"Attribute Field" ) );
385 fieldTitleAct->setFont( titlefont );
386 fieldTitleAct->setEnabled(
false );
388 mDefineMenu->addAction( mActionDataTypes );
390 mFieldsMenu->clear();
392 if ( !mFieldNameList.isEmpty() )
395 for (
int j = 0; j < mFieldNameList.count(); ++j )
397 QString fldname = mFieldNameList.at( j );
398 QAction *act = mFieldsMenu->addAction( fldname +
" (" + mFieldTypeList.at( j ) +
')' );
399 act->setData( QVariant( fldname ) );
400 if ( mFieldName == fldname )
402 act->setCheckable(
true );
410 QAction *act = mFieldsMenu->addAction( tr(
"No matching field types found" ) );
411 act->setEnabled(
false );
414 mDefineMenu->addSeparator();
417 mFieldsMenu->menuAction()->setCheckable(
true );
420 bool colorActive =
false;
421 mColorsMenu->clear();
426 QAction *colorTitleAct = mDefineMenu->addAction( tr(
"Project Color" ) );
427 colorTitleAct->setFont( titlefont );
428 colorTitleAct->setEnabled(
false );
430 QList<QgsProjectColorScheme *> projectSchemes;
432 if ( projectSchemes.length() > 0 )
436 for (
const auto &color : colors )
438 if ( color.second.isEmpty() )
442 QAction *act = mColorsMenu->addAction( color.second );
443 act->setIcon( icon );
446 act->setCheckable(
true );
447 act->setChecked(
true );
453 if ( mColorsMenu->actions().isEmpty() )
455 QAction *act = mColorsMenu->addAction( tr(
"No colors set" ) );
456 act->setEnabled(
false );
459 mDefineMenu->addAction( mActionColors );
460 mColorsMenu->menuAction()->setCheckable(
true );
461 mColorsMenu->menuAction()->setChecked( colorActive && !mProperty.
transformer() );
463 mDefineMenu->addSeparator();
466 QAction *exprTitleAct = mDefineMenu->addAction( tr(
"Expression" ) );
467 exprTitleAct->setFont( titlefont );
468 exprTitleAct->setEnabled(
false );
470 mVariablesMenu->clear();
471 bool variableActive =
false;
472 if ( mExpressionContextGenerator )
476 const auto constVariables = variables;
477 for (
const QString &variable : constVariables )
481 if ( variable.startsWith(
'_' ) )
484 QAction *act = mVariablesMenu->addAction( variable );
485 act->setData( QVariant( variable ) );
489 act->setCheckable(
true );
490 act->setChecked(
true );
491 variableActive =
true;
496 if ( mVariablesMenu->actions().isEmpty() )
498 QAction *act = mVariablesMenu->addAction( tr(
"No variables set" ) );
499 act->setEnabled(
false );
502 mDefineMenu->addAction( mActionVariables );
503 mVariablesMenu->menuAction()->setCheckable(
true );
504 mVariablesMenu->menuAction()->setChecked( variableActive && !mProperty.
transformer() );
508 QString expString = mExpressionString;
509 if ( expString.length() > 35 )
511 expString.truncate( 35 );
512 expString.append( QChar( 0x2026 ) );
515 expString.prepend( tr(
"Current: " ) );
517 if ( !mActionExpression )
519 mActionExpression =
new QAction( expString,
this );
520 mActionExpression->setCheckable(
true );
524 mActionExpression->setText( expString );
526 mDefineMenu->addAction( mActionExpression );
529 mDefineMenu->addAction( mActionExpDialog );
530 mDefineMenu->addAction( mActionCopyExpr );
531 mDefineMenu->addAction( mActionPasteExpr );
532 mDefineMenu->addAction( mActionClearExpr );
536 mDefineMenu->addAction( mActionExpDialog );
537 mDefineMenu->addAction( mActionPasteExpr );
542 mDefineMenu->addSeparator();
543 mActionAssistant->setCheckable( mProperty.
transformer() );
544 mActionAssistant->setChecked( mProperty.
transformer() );
545 mDefineMenu->addAction( mActionAssistant );
549 void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
551 if ( action == mActionActive )
553 setActivePrivate( mActionActive->data().toBool() );
557 else if ( action == mActionDescription )
559 showDescriptionDialog();
561 else if ( action == mActionExpDialog )
563 showExpressionDialog();
565 else if ( action == mActionExpression )
569 setActivePrivate(
true );
574 else if ( action == mActionCopyExpr )
576 QApplication::clipboard()->setText( mExpressionString );
578 else if ( action == mActionPasteExpr )
580 QString exprString = QApplication::clipboard()->text();
581 if ( !exprString.isEmpty() )
583 mExpressionString = exprString;
586 setActivePrivate(
true );
592 else if ( action == mActionClearExpr )
594 setActivePrivate(
false );
597 mExpressionString.clear();
602 else if ( action == mActionAssistant )
606 else if ( action == mActionCreateAuxiliaryField )
610 else if ( mFieldsMenu->actions().contains( action ) )
612 if ( action->isEnabled() )
614 if ( mFieldName != action->text() )
616 mFieldName = action->data().toString();
620 setActivePrivate(
true );
626 else if ( mVariablesMenu->actions().contains( action ) )
628 if ( mExpressionString != action->text().prepend(
"@" ) )
630 mExpressionString = action->data().toString().prepend(
"@" );
634 setActivePrivate(
true );
639 else if ( mColorsMenu->actions().contains( action ) )
641 if ( mExpressionString != QStringLiteral(
"project_color('%1')" ).arg( action->text() ) )
643 mExpressionString = QStringLiteral(
"project_color('%1')" ).arg( action->text() );
647 setActivePrivate(
true );
655 void QgsPropertyOverrideButton::showDescriptionDialog()
658 mv->setWindowTitle( tr(
"Data Definition Description" ) );
664 void QgsPropertyOverrideButton::showExpressionDialog()
672 QgsExpressionBuilderDialog d( const_cast<QgsVectorLayer *>( mVectorLayer ), currentExpression,
this, QStringLiteral(
"generic" ), context );
674 if ( d.exec() == QDialog::Accepted )
679 setActivePrivate( !mExpressionString.isEmpty() );
687 void QgsPropertyOverrideButton::showAssistant()
707 mFieldName = this->mProperty.
field();
720 QDialog *dlg =
new QDialog(
this );
721 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
723 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
725 dlg->setLayout(
new QVBoxLayout() );
726 dlg->layout()->addWidget( widget );
727 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
728 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
729 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
730 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
731 dlg->layout()->addWidget( buttonBox );
733 if ( dlg->exec() == QDialog::Accepted )
737 mFieldName = mProperty.
field();
744 settings.
setValue( key, dlg->saveGeometry() );
748 void QgsPropertyOverrideButton::updateGui()
750 bool hasExp = !mExpressionString.isEmpty();
751 bool hasField = !mFieldName.isEmpty();
754 QString deftip = tr(
"undefined" );
760 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
761 QRegularExpressionMatch match = rx.match( mExpressionString );
762 if ( match.hasMatch() )
765 deftip = match.captured( 1 );
766 deftype = tr(
"project color" );
778 deftip = mExpressionString;
786 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
789 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
800 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
802 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
804 if ( !mUsageInfo.isEmpty() )
806 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
809 if ( !mInputDescription.isEmpty() )
811 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
814 if ( !mDataTypesString.isEmpty() )
816 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
819 if ( deftype.isEmpty() && deftip != tr(
"undefined" ) )
825 if ( deftip.length() > 75 )
827 deftip.truncate( 75 );
828 deftip.append( QChar( 0x2026 ) );
831 mFullDescription += tr(
"<b>Current definition (%1):</b><br>%2" ).arg( deftype, deftip );
833 setToolTip( mFullDescription );
837 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
846 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
848 const auto constMSiblingWidgets = mSiblingWidgets;
849 for (
const SiblingWidget &sw : constMSiblingWidgets )
851 switch ( sw.mSiblingType )
854 case SiblingCheckState:
859 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
860 if ( btn && btn->isCheckable() )
862 btn->setChecked( sw.mNatural ? state : !state );
866 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
867 if ( grpbx && grpbx->isCheckable() )
869 grpbx->setChecked( sw.mNatural ? state : !state );
876 case SiblingEnableState:
878 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
880 le->setReadOnly( sw.mNatural ? !state : state );
882 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
886 case SiblingVisibility:
888 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
892 case SiblingExpressionText:
894 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
901 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
910 case SiblingLinkedWidget:
912 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( sw.mWidgetPointer.data() ) )
916 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
917 QRegularExpressionMatch match = rx.match( mExpressionString );
918 if ( match.hasMatch() )
920 cb->linkToProjectColor( match.captured( 1 ) );
925 cb->linkToProjectColor( QString() );
948 mExpressionContextGenerator = generator;
953 for (
const SiblingWidget &sw : qgis::as_const( mSiblingWidgets ) )
955 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingLinkedWidget )
958 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingLinkedWidget ) );
960 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( widget ) )
972 void QgsPropertyOverrideButton::showHelp()
974 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)
Set the expected format string, which is shown in the dialog.
A color scheme which contains project specific colors set through project properties dialog...
This class is a composition of two QSettings instances:
Invalid (not set) property.
Expression based property (QgsExpressionBasedProperty)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
Class allowing to manage the auxiliary storage for a vector layer.
Container of fields for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Color with alpha channel.
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.
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
bool isProjectColor() const
Returns true if the property is set to a linked project color.
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Type propertyType() const
Returns the property type.
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.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
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.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
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.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes. ...
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.
Static property (QgsStaticProperty)
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
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.
StandardPropertyTemplate standardTemplate() const
Returns the property's standard template, if applicable.
Color with no alpha channel.