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 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
224 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingCheckState )
227 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingCheckState, natural ) );
233 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
235 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingEnableState )
238 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingEnableState, natural ) );
244 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
246 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingVisibility )
249 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingVisibility, natural ) );
255 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
257 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingExpressionText )
260 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingExpressionText ) );
268 if ( ( event->modifiers() & ( Qt::ControlModifier ) )
269 ||
event->button() == Qt::RightButton )
271 setActivePrivate( !mProperty.
isActive() );
279 QToolButton::mousePressEvent( event );
293 mFieldName =
property.field();
298 mExpressionString =
property.expressionString();
306 mExpressionString.clear();
308 mProperty = property;
315 void QgsPropertyOverrideButton::aboutToShowMenu()
317 mDefineMenu->clear();
321 bool hasExp = !mExpressionString.isEmpty();
322 QString ddTitle = tr(
"Data defined override" );
324 QAction *ddTitleAct = mDefineMenu->addAction( ddTitle );
325 QFont titlefont = ddTitleAct->font();
326 titlefont.setItalic(
true );
327 ddTitleAct->setFont( titlefont );
328 ddTitleAct->setEnabled(
false );
330 bool addActiveAction =
false;
340 addActiveAction = mFieldNameList.contains( mFieldName );
343 if ( addActiveAction )
346 mDefineMenu->addAction( mActionActive );
347 mActionActive->setText( mProperty.
isActive() ? tr(
"Deactivate" ) : tr(
"Activate" ) );
348 mActionActive->setData( QVariant( !mProperty.
isActive() ) );
351 if ( !mFullDescription.isEmpty() )
353 mDefineMenu->addAction( mActionDescription );
356 mDefineMenu->addSeparator();
359 if ( mAuxiliaryStorageEnabled && mVectorLayer )
361 mDefineMenu->addAction( mActionCreateAuxiliaryField );
365 mActionCreateAuxiliaryField->setEnabled(
true );
366 mActionCreateAuxiliaryField->setChecked(
false );
370 if ( index >= 0 && alayer && mVectorLayer->
isAuxiliaryField( index, srcIndex ) )
372 mActionCreateAuxiliaryField->setEnabled(
false );
373 mActionCreateAuxiliaryField->setChecked(
true );
377 bool fieldActive =
false;
378 if ( !mDataTypesString.isEmpty() )
380 QAction *fieldTitleAct = mDefineMenu->addAction( tr(
"Attribute Field" ) );
381 fieldTitleAct->setFont( titlefont );
382 fieldTitleAct->setEnabled(
false );
384 mDefineMenu->addAction( mActionDataTypes );
386 mFieldsMenu->clear();
388 if ( !mFieldNameList.isEmpty() )
391 for (
int j = 0; j < mFieldNameList.count(); ++j )
393 QString fldname = mFieldNameList.at( j );
394 QAction *act = mFieldsMenu->addAction( fldname +
" (" + mFieldTypeList.at( j ) +
')' );
395 act->setData( QVariant( fldname ) );
396 if ( mFieldName == fldname )
398 act->setCheckable(
true );
406 QAction *act = mFieldsMenu->addAction( tr(
"No matching field types found" ) );
407 act->setEnabled(
false );
410 mDefineMenu->addSeparator();
413 mFieldsMenu->menuAction()->setCheckable(
true );
416 bool colorActive =
false;
417 mColorsMenu->clear();
422 QAction *colorTitleAct = mDefineMenu->addAction( tr(
"Project Color" ) );
423 colorTitleAct->setFont( titlefont );
424 colorTitleAct->setEnabled(
false );
426 QList<QgsProjectColorScheme *> projectSchemes;
428 if ( projectSchemes.length() > 0 )
432 for (
const auto &color : colors )
434 if ( color.second.isEmpty() )
438 QAction *act = mColorsMenu->addAction( color.second );
439 act->setIcon( icon );
442 act->setCheckable(
true );
443 act->setChecked(
true );
449 if ( mColorsMenu->actions().isEmpty() )
451 QAction *act = mColorsMenu->addAction( tr(
"No colors set" ) );
452 act->setEnabled(
false );
455 mDefineMenu->addAction( mActionColors );
456 mColorsMenu->menuAction()->setCheckable(
true );
457 mColorsMenu->menuAction()->setChecked( colorActive && !mProperty.
transformer() );
459 mDefineMenu->addSeparator();
462 QAction *exprTitleAct = mDefineMenu->addAction( tr(
"Expression" ) );
463 exprTitleAct->setFont( titlefont );
464 exprTitleAct->setEnabled(
false );
466 mVariablesMenu->clear();
467 bool variableActive =
false;
468 if ( mExpressionContextGenerator )
472 Q_FOREACH (
const QString &variable, variables )
476 if ( variable.startsWith(
'_' ) )
479 QAction *act = mVariablesMenu->addAction( variable );
480 act->setData( QVariant( variable ) );
484 act->setCheckable(
true );
485 act->setChecked(
true );
486 variableActive =
true;
491 if ( mVariablesMenu->actions().isEmpty() )
493 QAction *act = mVariablesMenu->addAction( tr(
"No variables set" ) );
494 act->setEnabled(
false );
497 mDefineMenu->addAction( mActionVariables );
498 mVariablesMenu->menuAction()->setCheckable(
true );
499 mVariablesMenu->menuAction()->setChecked( variableActive && !mProperty.
transformer() );
503 QString expString = mExpressionString;
504 if ( expString.length() > 35 )
506 expString.truncate( 35 );
507 expString.append( QChar( 0x2026 ) );
510 expString.prepend( tr(
"Current: " ) );
512 if ( !mActionExpression )
514 mActionExpression =
new QAction( expString,
this );
515 mActionExpression->setCheckable(
true );
519 mActionExpression->setText( expString );
521 mDefineMenu->addAction( mActionExpression );
524 mDefineMenu->addAction( mActionExpDialog );
525 mDefineMenu->addAction( mActionCopyExpr );
526 mDefineMenu->addAction( mActionPasteExpr );
527 mDefineMenu->addAction( mActionClearExpr );
531 mDefineMenu->addAction( mActionExpDialog );
532 mDefineMenu->addAction( mActionPasteExpr );
537 mDefineMenu->addSeparator();
538 mActionAssistant->setCheckable( mProperty.
transformer() );
539 mActionAssistant->setChecked( mProperty.
transformer() );
540 mDefineMenu->addAction( mActionAssistant );
544 void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
546 if ( action == mActionActive )
548 setActivePrivate( mActionActive->data().toBool() );
552 else if ( action == mActionDescription )
554 showDescriptionDialog();
556 else if ( action == mActionExpDialog )
558 showExpressionDialog();
560 else if ( action == mActionExpression )
564 setActivePrivate(
true );
569 else if ( action == mActionCopyExpr )
571 QApplication::clipboard()->setText( mExpressionString );
573 else if ( action == mActionPasteExpr )
575 QString exprString = QApplication::clipboard()->text();
576 if ( !exprString.isEmpty() )
578 mExpressionString = exprString;
581 setActivePrivate(
true );
587 else if ( action == mActionClearExpr )
589 setActivePrivate(
false );
592 mExpressionString.clear();
597 else if ( action == mActionAssistant )
601 else if ( action == mActionCreateAuxiliaryField )
605 else if ( mFieldsMenu->actions().contains( action ) )
607 if ( action->isEnabled() )
609 if ( mFieldName != action->text() )
611 mFieldName = action->data().toString();
615 setActivePrivate(
true );
621 else if ( mVariablesMenu->actions().contains( action ) )
623 if ( mExpressionString != action->text().prepend(
"@" ) )
625 mExpressionString = action->data().toString().prepend(
"@" );
629 setActivePrivate(
true );
634 else if ( mColorsMenu->actions().contains( action ) )
636 if ( mExpressionString != QStringLiteral(
"project_color('%1')" ).arg( action->text() ) )
638 mExpressionString = QStringLiteral(
"project_color('%1')" ).arg( action->text() );
642 setActivePrivate(
true );
650 void QgsPropertyOverrideButton::showDescriptionDialog()
653 mv->setWindowTitle( tr(
"Data Definition Description" ) );
659 void QgsPropertyOverrideButton::showExpressionDialog()
667 QgsExpressionBuilderDialog d( const_cast<QgsVectorLayer *>( mVectorLayer ), currentExpression,
this, QStringLiteral(
"generic" ), context );
669 if ( d.exec() == QDialog::Accepted )
674 setActivePrivate( !mExpressionString.isEmpty() );
682 void QgsPropertyOverrideButton::showAssistant()
702 mFieldName = this->mProperty.
field();
715 QDialog *dlg =
new QDialog(
this );
716 QString key = QStringLiteral(
"/UI/paneldialog/%1" ).arg( widget->
panelTitle() );
718 dlg->restoreGeometry( settings.
value( key ).toByteArray() );
720 dlg->setLayout(
new QVBoxLayout() );
721 dlg->layout()->addWidget( widget );
722 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
723 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
724 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject );
725 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsPropertyOverrideButton::showHelp );
726 dlg->layout()->addWidget( buttonBox );
728 if ( dlg->exec() == QDialog::Accepted )
732 mFieldName = mProperty.
field();
739 settings.
setValue( key, dlg->saveGeometry() );
743 void QgsPropertyOverrideButton::updateGui()
745 bool hasExp = !mExpressionString.isEmpty();
746 bool hasField = !mFieldName.isEmpty();
749 QString deftip = tr(
"undefined" );
755 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
756 QRegularExpressionMatch match = rx.match( mExpressionString );
757 if ( match.hasMatch() )
760 deftip = match.captured( 1 );
761 deftype = tr(
"project color" );
773 deftip = mExpressionString;
781 if ( !mFieldNameList.contains( mFieldName ) && !mProperty.
transformer() )
784 deftip = tr(
"'%1' field missing" ).arg( mFieldName );
795 mFullDescription = tr(
"<b><u>Data defined override</u></b><br>" );
797 mFullDescription += tr(
"<b>Active: </b>%1 <i>(ctrl|right-click toggles)</i><br>" ).arg( mProperty.
isActive() ? tr(
"yes" ) : tr(
"no" ) );
799 if ( !mUsageInfo.isEmpty() )
801 mFullDescription += tr(
"<b>Usage:</b><br>%1<br>" ).arg( mUsageInfo );
804 if ( !mInputDescription.isEmpty() )
806 mFullDescription += tr(
"<b>Expected input:</b><br>%1<br>" ).arg( mInputDescription );
809 if ( !mDataTypesString.isEmpty() )
811 mFullDescription += tr(
"<b>Valid input types:</b><br>%1<br>" ).arg( mDataTypesString );
814 if ( deftype.isEmpty() && deftip != tr(
"undefined" ) )
820 if ( deftip.length() > 75 )
822 deftip.truncate( 75 );
823 deftip.append( QChar( 0x2026 ) );
826 mFullDescription += tr(
"<b>Current definition (%1):</b><br>%2" ).arg( deftype, deftip );
828 setToolTip( mFullDescription );
832 void QgsPropertyOverrideButton::setActivePrivate(
bool active )
841 void QgsPropertyOverrideButton::updateSiblingWidgets(
bool state )
843 Q_FOREACH (
const SiblingWidget &sw, mSiblingWidgets )
845 switch ( sw.mSiblingType )
848 case SiblingCheckState:
853 QAbstractButton *btn = qobject_cast< QAbstractButton * >( sw.mWidgetPointer.data() );
854 if ( btn && btn->isCheckable() )
856 btn->setChecked( sw.mNatural ? state : !state );
860 QGroupBox *grpbx = qobject_cast< QGroupBox * >( sw.mWidgetPointer.data() );
861 if ( grpbx && grpbx->isCheckable() )
863 grpbx->setChecked( sw.mNatural ? state : !state );
870 case SiblingEnableState:
872 QLineEdit *le = qobject_cast< QLineEdit * >( sw.mWidgetPointer.data() );
874 le->setReadOnly( sw.mNatural ? !state : state );
876 sw.mWidgetPointer.data()->setEnabled( sw.mNatural ? state : !state );
880 case SiblingVisibility:
882 sw.mWidgetPointer.data()->setVisible( sw.mNatural ? state : !state );
886 case SiblingExpressionText:
888 QLineEdit *le = qobject_cast<QLineEdit *>( sw.mWidgetPointer.data() );
895 QTextEdit *te = qobject_cast<QTextEdit *>( sw.mWidgetPointer.data() );
904 case SiblingLinkedWidget:
906 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( sw.mWidgetPointer.data() ) )
910 QRegularExpression rx( QStringLiteral(
"^project_color\\('(.*)'\\)$" ) );
911 QRegularExpressionMatch match = rx.match( mExpressionString );
912 if ( match.hasMatch() )
914 cb->linkToProjectColor( match.captured( 1 ) );
919 cb->linkToProjectColor( QString() );
942 mExpressionContextGenerator = generator;
947 for (
const SiblingWidget &sw : qgis::as_const( mSiblingWidgets ) )
949 if ( widget == sw.mWidgetPointer.data() && sw.mSiblingType == SiblingLinkedWidget )
952 mSiblingWidgets.append( SiblingWidget( QPointer<QWidget>( widget ), SiblingLinkedWidget ) );
954 if (
QgsColorButton *cb = qobject_cast< QgsColorButton * >( widget ) )
966 void QgsPropertyOverrideButton::showHelp()
968 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:
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.
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.
Invalid (not set) property.
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.