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 );
535 mDefineMenu->addAction( mActionExpDialog );
536 mDefineMenu->addAction( mActionPasteExpr );
539 if ( hasExp || !mFieldName.isEmpty() )
541 mDefineMenu->addSeparator();
542 mDefineMenu->addAction( mActionClearExpr );
547 mDefineMenu->addSeparator();
548 mActionAssistant->setCheckable( mProperty.
transformer() );
549 mActionAssistant->setChecked( mProperty.
transformer() );
550 mDefineMenu->addAction( mActionAssistant );
554 void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
556 if ( action == mActionActive )
558 setActivePrivate( mActionActive->data().toBool() );
562 else if ( action == mActionDescription )
564 showDescriptionDialog();
566 else if ( action == mActionExpDialog )
568 showExpressionDialog();
570 else if ( action == mActionExpression )
574 setActivePrivate(
true );
579 else if ( action == mActionCopyExpr )
581 QApplication::clipboard()->setText( mExpressionString );
583 else if ( action == mActionPasteExpr )
585 QString exprString = QApplication::clipboard()->text();
586 if ( !exprString.isEmpty() )
588 mExpressionString = exprString;
591 setActivePrivate(
true );
597 else if ( action == mActionClearExpr )
599 setActivePrivate(
false );
602 mExpressionString.clear();
607 else if ( action == mActionAssistant )
611 else if ( action == mActionCreateAuxiliaryField )
615 else if ( mFieldsMenu->actions().contains( action ) )
617 if ( action->isEnabled() )
619 if ( mFieldName != action->text() )
621 mFieldName = action->data().toString();
625 setActivePrivate(
true );
631 else if ( mVariablesMenu->actions().contains( action ) )
633 if ( mExpressionString != action->text().prepend(
"@" ) )
635 mExpressionString = action->data().toString().prepend(
"@" );
639 setActivePrivate(
true );
644 else if ( mColorsMenu->actions().contains( action ) )
646 if ( mExpressionString != QStringLiteral(
"project_color('%1')" ).arg( action->text() ) )
648 mExpressionString = QStringLiteral(
"project_color('%1')" ).arg( action->text() );
652 setActivePrivate(
true );
660 void QgsPropertyOverrideButton::showDescriptionDialog()
662 QgsMessageViewer *mv =
new QgsMessageViewer(
this );
663 mv->setWindowTitle( tr(
"Data Definition Description" ) );
664 mv->setMessageAsHtml( mFullDescription );
669 void QgsPropertyOverrideButton::showExpressionDialog()
677 QgsExpressionBuilderDialog d( const_cast<QgsVectorLayer *>( mVectorLayer ), currentExpression,
this, QStringLiteral(
"generic" ), context );
679 if ( d.exec() == QDialog::Accepted )
684 setActivePrivate( !mExpressionString.isEmpty() );
692 void QgsPropertyOverrideButton::showAssistant()
712 mFieldName = this->mProperty.
field();
725 QDialog *dlg =
new QDialog(
this );
726 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
728 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
730 dlg->setLayout(
new QVBoxLayout() );
731 dlg->layout()->addWidget( widget );
732 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
733 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
734 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
735 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
736 dlg->layout()->addWidget( buttonBox );
738 if ( dlg->exec() == QDialog::Accepted )
742 mFieldName = mProperty.
field();
749 settings.
setValue( key, dlg->saveGeometry() );
753 void QgsPropertyOverrideButton::updateGui()
755 bool hasExp = !mExpressionString.isEmpty();
756 bool hasField = !mFieldName.isEmpty();
759 QString deftip = tr(
"undefined" );
765 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
766 QRegularExpressionMatch match = rx.match( mExpressionString );
767 if ( match.hasMatch() )
770 deftip = match.captured( 1 );
771 deftype = tr(
"project color" );
783 deftip = mExpressionString;
791 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
794 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
805 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
807 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
809 if ( !mUsageInfo.isEmpty() )
811 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
814 if ( !mInputDescription.isEmpty() )
816 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
819 if ( !mDataTypesString.isEmpty() )
821 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
824 if ( deftype.isEmpty() && deftip != tr(
"undefined" ) )
830 if ( deftip.length() > 75 )
832 deftip.truncate( 75 );
833 deftip.append( QChar( 0x2026 ) );
836 mFullDescription += tr(
"<b>Current definition (%1):</b><br>%2" ).arg( deftype, deftip );
838 setToolTip( mFullDescription );
842 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
851 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
853 const auto constMSiblingWidgets = mSiblingWidgets;
854 for (
const SiblingWidget &sw : constMSiblingWidgets )
856 switch ( sw.mSiblingType )
859 case SiblingCheckState:
864 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
865 if ( btn && btn->isCheckable() )
867 btn->setChecked( sw.mNatural ? state : !state );
871 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
872 if ( grpbx && grpbx->isCheckable() )
874 grpbx->setChecked( sw.mNatural ? state : !state );
881 case SiblingEnableState:
883 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
885 le->setReadOnly( sw.mNatural ? !state : state );
887 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
891 case SiblingVisibility:
893 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
897 case SiblingExpressionText:
899 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
906 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
915 case SiblingLinkedWidget:
917 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( sw.mWidgetPointer.data() ) )
921 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
922 QRegularExpressionMatch match = rx.match( mExpressionString );
923 if ( match.hasMatch() )
925 cb->linkToProjectColor( match.captured( 1 ) );
930 cb->linkToProjectColor( QString() );
953 mExpressionContextGenerator = generator;
958 for (
const SiblingWidget &sw : qgis::as_const( mSiblingWidgets ) )
960 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingLinkedWidget )
963 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingLinkedWidget ) );
965 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( widget ) )
977 void QgsPropertyOverrideButton::showHelp()
979 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 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.
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.