diff --git a/python/core/qgsconditionalstyle.sip b/python/core/qgsconditionalstyle.sip index 1fe3e7e04cd..85e098164f6 100644 --- a/python/core/qgsconditionalstyle.sip +++ b/python/core/qgsconditionalstyle.sip @@ -25,6 +25,12 @@ class QgsConditionalStyle */ QPixmap renderPreview(); + /** + * @brief Set the name of the style. Names are optional but handy for display + * @param value The name given to the style + */ + void setName( QString value ); + /** * @brief Set the rule for the style. Rules should be of QgsExpression syntax. * Special value of \@value is replaced at run time with the check value @@ -57,15 +63,27 @@ class QgsConditionalStyle void setSymbol( QgsSymbolV2* value ); /** - * @brief The icon set for style generated from the set symbol - * @return A QPixmap that was set for the icon using the symbol + * @brief The name of the style. + * @return The name of the style. Names are optional so might be empty. */ - QgsSymbolV2* symbol() const; + QString displayText() const; + + /** + * @brief The name of the style. + * @return The name of the style. Names are optional so might be empty. + */ + QString name() const; /** * @brief The symbol used to generate the icon for the style * @return The QgsSymbolV2 used for the icon */ + QgsSymbolV2* symbol() const; + + /** + * @brief The icon set for style generated from the set symbol + * @return A QPixmap that was set for the icon using the symbol + */ QPixmap icon() const; /** @@ -99,6 +117,32 @@ class QgsConditionalStyle */ bool isValid() const; + /** + * @brief Find and return the matching styles for the value and feature. + * If no match is found a invalid QgsCondtionalStyle is return. + * + * @return A condtional style that matches the value and feature. + * Check with QgsCondtionalStyle::isValid() + */ + static QList matchingConditionalStyles( QList styles, QVariant value, QgsFeature* feature ); + + /** + * @brief Find and return the matching style for the value and feature. + * If no match is found a invalid QgsCondtionalStyle is return. + * + * @return A condtional style that matches the value and feature. + * Check with QgsCondtionalStyle::isValid() + */ + static QgsConditionalStyle matchingConditionalStyle( QList styles, QVariant value, QgsFeature* feature ); + + /** + * @brief Compress a list of styles into a single style. This can be used to stack the elements of the + * styles. The font of the last style is used in the output. + * @param styles The list of styles to compress down + * @return A single style generated from joining each style property. + */ + static QgsConditionalStyle compressStyles( QList styles ); + /** Reads vector conditional style specific state from layer Dom node. */ virtual bool readXml( const QDomNode& node ); diff --git a/python/core/qgsfielduiproperties.sip b/python/core/qgsfielduiproperties.sip index c9618c7c434..f527533467f 100644 --- a/python/core/qgsfielduiproperties.sip +++ b/python/core/qgsfielduiproperties.sip @@ -23,28 +23,7 @@ class QgsFieldUIProperties * @brief Returns the conditional styles set for the field UI properties * @return A list of conditional styles that have been set. */ - const QList getConditionalStyles() const; - - /** - * @brief Find and return all matching styles for a value and context. - * If no match is found an empty list is returned. - * @param value current cell value - * @param context expression context for evaluating conditional rules - * @return A list of conditional styles that matches the value and context. - * @see matchingConditionalStyle - */ - QList matchingConditionalStyles(QVariant value, QgsExpressionContext& context ) const; - - /** - * @brief Find and return the matching style for the value and context. - * If no match is found a invalid QgsConditionalStyle is return. - * @param value current cell value - * @param context expression context for evaluating conditional rules - * @return A conditional style that matches the value and context. - * Check with QgsConditionalStyle::isValid() - * @see matchingConditionalStyles - */ - QgsConditionalStyle matchingConditionalStyle( QVariant value, QgsExpressionContext& context ) const; + const QList conditionalStyles(); /** Reads field ui properties specific state from Dom node. */ diff --git a/src/core/qgsconditionalstyle.cpp b/src/core/qgsconditionalstyle.cpp index d8bbc17e36b..463e797974d 100644 --- a/src/core/qgsconditionalstyle.cpp +++ b/src/core/qgsconditionalstyle.cpp @@ -25,6 +25,7 @@ QgsConditionalStyle::QgsConditionalStyle( const QgsConditionalStyle &other ) , mBackColor( other.mBackColor ) , mTextColor( other.mTextColor ) , mIcon( other.mIcon ) + , mName( other.mName ) { if ( other.mSymbol.data() ) mSymbol.reset( other.mSymbol->clone() ); @@ -38,6 +39,7 @@ QgsConditionalStyle& QgsConditionalStyle::operator=( const QgsConditionalStyle & mBackColor = other.mBackColor; mTextColor = other.mTextColor; mIcon = other.mIcon; + mName = other.mName; if ( other.mSymbol.data() ) { mSymbol.reset( other.mSymbol->clone() ); @@ -53,6 +55,14 @@ QgsConditionalStyle::~QgsConditionalStyle() { } +QString QgsConditionalStyle::displayText() const +{ + if ( name().isEmpty() ) + return rule(); + else + return QString( "%1 \n%2" ).arg( name() ).arg( rule() ); +} + void QgsConditionalStyle::setSymbol( QgsSymbolV2* value ) { mValid = true; @@ -103,10 +113,48 @@ QPixmap QgsConditionalStyle::renderPreview() return pixmap; } +QList QgsConditionalStyle::matchingConditionalStyles( QList styles, QVariant value, QgsFeature *feature ) +{ + QList matchingstyles; + foreach ( QgsConditionalStyle style, styles ) + { + if ( style.matches( value, feature ) ) + matchingstyles.append( style ); + } + return matchingstyles; +} + +QgsConditionalStyle QgsConditionalStyle::matchingConditionalStyle( QList styles, QVariant value, QgsFeature *feature ) +{ + foreach ( QgsConditionalStyle style, styles ) + { + if ( style.matches( value, feature ) ) + return style; + } + return QgsConditionalStyle(); +} + +QgsConditionalStyle QgsConditionalStyle::compressStyles( QList styles ) +{ + QgsConditionalStyle style; + foreach ( QgsConditionalStyle s, styles ) + { + style.setFont( s.font() ); + if ( s.backgroundColor().isValid() && s.backgroundColor().alpha() != 0 ) + style.setBackgroundColor( s.backgroundColor() ); + if ( s.textColor().isValid() && s.textColor().alpha() != 0 ) + style.setTextColor( s.textColor() ); + if ( s.symbol() ) + style.setSymbol( s.symbol() ); + } + return style; +} + bool QgsConditionalStyle::writeXml( QDomNode &node, QDomDocument &doc ) { QDomElement stylesel = doc.createElement( "style" ); stylesel.setAttribute( "rule", mRule ); + stylesel.setAttribute( "name", mName ); stylesel.setAttribute( "background_color", mBackColor.name() ); stylesel.setAttribute( "text_color", mTextColor.name() ); QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, "font" ); @@ -124,6 +172,7 @@ bool QgsConditionalStyle::readXml( const QDomNode &node ) { QDomElement styleElm = node.toElement(); setRule( styleElm.attribute( "rule" ) ); + setName( styleElm.attribute( "name" ) ); setBackgroundColor( QColor( styleElm.attribute( "background_color" ) ) ); setTextColor( QColor( styleElm.attribute( "text_color" ) ) ); QgsFontUtils::setFromXmlChildNode( mFont, styleElm, "font" ); diff --git a/src/core/qgsconditionalstyle.h b/src/core/qgsconditionalstyle.h index cc263bf2162..0bfc46eb1cc 100644 --- a/src/core/qgsconditionalstyle.h +++ b/src/core/qgsconditionalstyle.h @@ -37,6 +37,12 @@ class CORE_EXPORT QgsConditionalStyle */ QPixmap renderPreview(); + /** + * @brief Set the name of the style. Names are optional but handy for display + * @param value The name given to the style + */ + void setName( QString value ) { mName = value; mValid = true; } + /** * @brief Set the rule for the style. Rules should be of QgsExpression syntax. * Special value of \@value is replaced at run time with the check value @@ -68,6 +74,18 @@ class CORE_EXPORT QgsConditionalStyle */ void setSymbol( QgsSymbolV2* value ); + /** + * @brief The name of the style. + * @return The name of the style. Names are optional so might be empty. + */ + QString displayText() const; + + /** + * @brief The name of the style. + * @return The name of the style. Names are optional so might be empty. + */ + QString name() const { return mName; } + /** * @brief The icon set for style generated from the set symbol * @return A QPixmap that was set for the icon using the symbol @@ -111,6 +129,32 @@ class CORE_EXPORT QgsConditionalStyle */ bool isValid() const { return mValid; } + /** + * @brief Find and return the matching styles for the value and feature. + * If no match is found a invalid QgsCondtionalStyle is return. + * + * @return A condtional style that matches the value and feature. + * Check with QgsCondtionalStyle::isValid() + */ + static QList matchingConditionalStyles( QList styles, QVariant value, QgsFeature* feature ); + + /** + * @brief Find and return the matching style for the value and feature. + * If no match is found a invalid QgsCondtionalStyle is return. + * + * @return A condtional style that matches the value and feature. + * Check with QgsCondtionalStyle::isValid() + */ + static QgsConditionalStyle matchingConditionalStyle( QList styles, QVariant value, QgsFeature* feature ); + + /** + * @brief Compress a list of styles into a single style. This can be used to stack the elements of the + * styles. The font of the last style is used in the output. + * @param styles The list of styles to compress down + * @return A single style generated from joining each style property. + */ + static QgsConditionalStyle compressStyles( QList styles ); + /** Reads vector conditional style specific state from layer Dom node. */ virtual bool readXml( const QDomNode& node ); @@ -119,9 +163,11 @@ class CORE_EXPORT QgsConditionalStyle */ virtual bool writeXml( QDomNode & node, QDomDocument & doc ); + private: bool mValid; + QString mName; QString mRule; QScopedPointer mSymbol; QFont mFont; diff --git a/src/core/qgsfielduiproperties.cpp b/src/core/qgsfielduiproperties.cpp index 1629098f733..857f0925544 100644 --- a/src/core/qgsfielduiproperties.cpp +++ b/src/core/qgsfielduiproperties.cpp @@ -13,32 +13,11 @@ void QgsFieldUIProperties::setConditionalStyles( QList styl mStyles = styles; } -QList QgsFieldUIProperties::getConditionalStyles() const +QList QgsFieldUIProperties::conditionalStyles() { return mStyles; } -QList QgsFieldUIProperties::matchingConditionalStyles( QVariant value, QgsExpressionContext& context ) const -{ - QList styles; - foreach ( QgsConditionalStyle style, mStyles ) - { - if ( style.matches( value, context ) ) - styles.append( style ); - } - return styles; -} - -QgsConditionalStyle QgsFieldUIProperties::matchingConditionalStyle( QVariant value, QgsExpressionContext& context ) const -{ - foreach ( QgsConditionalStyle style, mStyles ) - { - if ( style.matches( value, context ) ) - return style; - } - return QgsConditionalStyle(); -} - bool QgsFieldUIProperties::writeXml( QDomNode &node, QDomDocument &doc ) const { QDomElement stylesel = doc.createElement( "conditionalstyles" ); diff --git a/src/core/qgsfielduiproperties.h b/src/core/qgsfielduiproperties.h index 2a2caf084a2..e37fe47a0c4 100644 --- a/src/core/qgsfielduiproperties.h +++ b/src/core/qgsfielduiproperties.h @@ -30,28 +30,7 @@ class CORE_EXPORT QgsFieldUIProperties * @brief Returns the conditional styles set for the field UI properties * @return A list of conditional styles that have been set. */ - QList getConditionalStyles() const; - - /** - * @brief Find and return all matching styles for a value and context. - * If no match is found an empty list is returned. - * @param value current cell value - * @param context expression context for evaluating conditional rules - * @return A list of conditional styles that matches the value and context. - * @see matchingConditionalStyle - */ - QList matchingConditionalStyles( QVariant value, QgsExpressionContext& context ) const; - - /** - * @brief Find and return the matching style for the value and context. - * If no match is found a invalid QgsConditionalStyle is return. - * @param value current cell value - * @param context expression context for evaluating conditional rules - * @return A conditional style that matches the value and context. - * Check with QgsConditionalStyle::isValid() - * @see matchingConditionalStyles - */ - QgsConditionalStyle matchingConditionalStyle( QVariant value, QgsExpressionContext& context ) const; + QList conditionalStyles(); /** Reads field ui properties specific state from Dom node. */ diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index d8ae91c22ce..c4fc8a05276 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -2044,6 +2044,16 @@ QgsFieldUIProperties QgsVectorLayer::fieldUIProperties( QString fieldName ) return QgsFieldUIProperties(); } +QList QgsVectorLayer::rowStyles() +{ + return mRowStyles; +} + +void QgsVectorLayer::setRowStyles( QList styles ) +{ + mRowStyles = styles; +} + void QgsVectorLayer::setFieldUIProperties( QString fieldName, QgsFieldUIProperties props ) { mFieldProperties.insert( fieldName, props ); diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 73857c0407a..42788e49ae5 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -27,6 +27,7 @@ #include "qgis.h" #include "qgsmaplayer.h" +#include "qgsconditionalstyle.h" #include "qgsfeature.h" #include "qgsfeatureiterator.h" #include "qgseditorwidgetconfig.h" @@ -1764,6 +1765,16 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer */ QgsFieldUIProperties fieldUIProperties( QString fieldName ); + QList rowStyles(); + + /** + * @brief Set the conditional styles that apply to full rows of data in the attribute table. + * Each row will check be checked against each rule. + * @param styles The styles to assign to all the rows + * @note added in QGIS 2.12 + */ + void setRowStyles( QList styles ); + /** * @brief Set the the field UI properties for a given field. * @param fieldName The field name. @@ -2026,6 +2037,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer private: // Private attributes QHash mFieldProperties; + QList mRowStyles; /** Pointer to data provider derived from the abastract base class QgsDataProvider */ QgsVectorDataProvider *mDataProvider; diff --git a/src/gui/attributetable/qgsattributetablemodel.cpp b/src/gui/attributetable/qgsattributetablemodel.cpp index dc869e4201a..3804ae1af52 100644 --- a/src/gui/attributetable/qgsattributetablemodel.cpp +++ b/src/gui/attributetable/qgsattributetablemodel.cpp @@ -391,6 +391,13 @@ void QgsAttributeTableModel::loadLayer() void QgsAttributeTableModel::fieldConditionalStyleChanged( const QString &fieldName ) { + if ( fieldName.isNull() ) + { + mRowStylesMap.clear(); + emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) ); + return; + } + int fieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName ); if ( fieldIndex == -1 ) return; @@ -588,36 +595,39 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons } if ( role == Qt::BackgroundColorRole || role == Qt::TextColorRole || role == Qt::DecorationRole || role == Qt::FontRole ) + { + mExpressionContext.setFeature( mFeat ); + QList styles; + if ( mRowStylesMap.contains( index.row() ) ) { - mExpressionContext.setFeature( mFeat ); + styles = mRowStylesMap[index.row()]; + } + else + { + styles = QgsConditionalStyle::matchingConditionalStyles( layer()->rowStyles(), QVariant(), &mFeat ); + mRowStylesMap.insert( index.row(), styles ); - QgsFieldUIProperties props = layer()->fieldUIProperties( field.name() ); - QList styles = props.matchingConditionalStyles( val, mExpressionContext ); - QgsConditionalStyle style; - foreach ( QgsConditionalStyle s, styles ) - { - style.setFont( s.font() ); - if ( s.backgroundColor().isValid() && s.backgroundColor().alpha() != 0 ) - style.setBackgroundColor( s.backgroundColor() ); - if ( s.textColor().isValid() && s.textColor().alpha() != 0 ) - style.setTextColor( s.textColor() ); - if ( s.symbol() ) - style.setSymbol( s.symbol() ); - } - - if ( style.isValid() ) - { - if ( role == Qt::BackgroundColorRole && style.backgroundColor().isValid() ) - return style.backgroundColor(); - if ( role == Qt::TextColorRole && style.textColor().isValid() ) - return style.textColor(); - if ( role == Qt::DecorationRole ) - return style.icon(); - if ( role == Qt::FontRole ) - return style.font(); - } } + QgsConditionalStyle rowstyle = QgsConditionalStyle::compressStyles( styles ); + QgsFieldUIProperties props = layer()->fieldUIProperties( field.name() ); + styles = QgsConditionalStyle::matchingConditionalStyles( props.conditionalStyles(), val, &mFeat ); + styles.insert( 0, rowstyle ); + QgsConditionalStyle style = QgsConditionalStyle::compressStyles( styles ); + + if ( style.isValid() ) + { + if ( role == Qt::BackgroundColorRole && style.backgroundColor().isValid() ) + return style.backgroundColor(); + if ( role == Qt::TextColorRole && style.textColor().isValid() ) + return style.textColor(); + if ( role == Qt::DecorationRole ) + return style.icon(); + if ( role == Qt::FontRole ) + return style.font(); + } + + } return val; } @@ -682,7 +692,6 @@ void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelInde } - void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx ) const { QgsFeature f = feature( idx ); diff --git a/src/gui/attributetable/qgsattributetablemodel.h b/src/gui/attributetable/qgsattributetablemodel.h index b340b4af181..41dc9fe0d6c 100644 --- a/src/gui/attributetable/qgsattributetablemodel.h +++ b/src/gui/attributetable/qgsattributetablemodel.h @@ -299,6 +299,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel QHash mIdRowMap; QHash mRowIdMap; + mutable QHash> mRowStylesMap; mutable QgsExpressionContext mExpressionContext; diff --git a/src/gui/attributetable/qgsfieldconditionalformatwidget.cpp b/src/gui/attributetable/qgsfieldconditionalformatwidget.cpp index 034df04a37a..268e1930882 100644 --- a/src/gui/attributetable/qgsfieldconditionalformatwidget.cpp +++ b/src/gui/attributetable/qgsfieldconditionalformatwidget.cpp @@ -14,20 +14,26 @@ QgsFieldConditionalFormatWidget::QgsFieldConditionalFormatWidget( QWidget *paren setupUi( this ); mDeleteButton->hide(); connect( mFieldCombo, SIGNAL( fieldChanged( QString ) ), SLOT( fieldChanged( QString ) ) ); + connect( fieldRadio, SIGNAL( clicked() ), SLOT( reloadStyles() ) ); + connect( rowRadio, SIGNAL( clicked() ), SLOT( reloadStyles() ) ); connect( mNewButton, SIGNAL( clicked() ), SLOT( addNewRule() ) ); connect( mSaveRule, SIGNAL( clicked() ), SLOT( saveRule() ) ); connect( mCancelButton, SIGNAL( clicked() ), SLOT( cancelRule() ) ); connect( mDeleteButton, SIGNAL( clicked() ), SLOT( deleteRule() ) ); connect( listView, SIGNAL( clicked( QModelIndex ) ), SLOT( ruleClicked( QModelIndex ) ) ); - connect( mDefaultButtons , SIGNAL( buttonPressed( QAbstractButton* ) ), SLOT( defaultPressed( QAbstractButton* ) ) ); connect( btnChangeIcon , SIGNAL( clicked() ), SLOT( updateIcon() ) ); connect( btnBuildExpression , SIGNAL( clicked() ), SLOT( setExpression() ) ); + connect( mPresetsList , SIGNAL( currentIndexChanged( int ) ), SLOT( presetSet( int ) ) ); btnBackgroundColor->setAllowAlpha( true ); btnBackgroundColor->setShowNoColor( true ); btnTextColor->setAllowAlpha( true ); btnTextColor->setShowNoColor( true ); mModel = new QStandardItemModel(); + mPresetsModel = new QStandardItemModel(); listView->setModel( mModel ); + mPresetsList->setModel( mPresetsModel ); + + setPresets( defaultPresets() ); } void QgsFieldConditionalFormatWidget::updateIcon() @@ -63,12 +69,13 @@ void QgsFieldConditionalFormatWidget::setExpression() } } -void QgsFieldConditionalFormatWidget::defaultPressed( QAbstractButton *button ) +void QgsFieldConditionalFormatWidget::presetSet( int index ) { - QColor backColor = button->property( "backColor" ).value(); - QColor fontColor = button->property( "fontColor" ).value(); - btnBackgroundColor->setColor( backColor ); - btnTextColor->setColor( fontColor ); + if ( index == -1 || mPresets.count() == 0 ) + return; + + QgsConditionalStyle style = mPresets.at( index ); + setFormattingFromStyle( style ); } void QgsFieldConditionalFormatWidget::setLayer( QgsVectorLayer *theLayer ) @@ -80,8 +87,7 @@ void QgsFieldConditionalFormatWidget::setLayer( QgsVectorLayer *theLayer ) void QgsFieldConditionalFormatWidget::ruleClicked( QModelIndex index ) { - QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); - QList styles = props.getConditionalStyles(); + QList styles = getStyles(); QgsConditionalStyle style = styles.at( index.row() ); editStyle( index.row(), style ); } @@ -91,9 +97,18 @@ void QgsFieldConditionalFormatWidget::editStyle( int editIndex, QgsConditionalSt pages->setCurrentIndex( 1 ); mEditIndex = editIndex; mEditing = true; - - mRuleEdit->setText( style.rule() ); mDeleteButton->show(); + loadStyle( style ); +} + +void QgsFieldConditionalFormatWidget::loadStyle( QgsConditionalStyle style ) +{ + mRuleEdit->setText( style.rule() ); + mNameEdit->setText( style.name() ); + setFormattingFromStyle( style ); +} +void QgsFieldConditionalFormatWidget::setFormattingFromStyle( QgsConditionalStyle style ) +{ btnBackgroundColor->setColor( style.backgroundColor() ); btnTextColor->setColor( style.textColor() ); if ( !style.icon().isNull() ) @@ -123,16 +138,41 @@ void QgsFieldConditionalFormatWidget::editStyle( int editIndex, QgsConditionalSt mFontFamilyCmbBx->setFont( font ); } +QList QgsFieldConditionalFormatWidget::getStyles() +{ + QList styles; + if ( fieldRadio->isChecked() ) + { + QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); + styles = props.conditionalStyles(); + } + if ( rowRadio->isChecked() ) + { + styles = mLayer->rowStyles(); + } + return styles; +} + void QgsFieldConditionalFormatWidget::deleteRule() { - QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); - QList styles = props.getConditionalStyles(); + QList styles = getStyles(); styles.removeAt( mEditIndex ); - props.setConditionalStyles( styles ); - mLayer->setFieldUIProperties( mFieldCombo->currentField(), props ); + QString fieldName; + if ( fieldRadio->isChecked() ) + { + QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); + props.setConditionalStyles( styles ); + mLayer->setFieldUIProperties( mFieldCombo->currentField(), props ); + fieldName = mFieldCombo->currentField(); + } + if ( rowRadio->isChecked() ) + { + mLayer->setRowStyles( styles ); + } + pages->setCurrentIndex( 0 ); reloadStyles(); - emit rulesUpdated( mFieldCombo->currentField() ); + emit rulesUpdated( fieldName ); } void QgsFieldConditionalFormatWidget::cancelRule() @@ -151,11 +191,15 @@ void QgsFieldConditionalFormatWidget::addNewRule() void QgsFieldConditionalFormatWidget::reset() { mSymbol = 0; - mRuleEdit->setText( "@value " ); + mNameEdit->clear(); + mRuleEdit->clear(); + if ( fieldRadio->isChecked() ) + { + mRuleEdit->setText( "@value " ); + } btnBackgroundColor->setColor( QColor() ); btnTextColor->setColor( QColor() ); - mDefault1->toggle(); - defaultPressed( mDefault1 ); + mPresetsList->setCurrentIndex( 0 ); mDeleteButton->hide(); mEditing = false; checkIcon->setChecked( false ); @@ -167,13 +211,71 @@ void QgsFieldConditionalFormatWidget::reset() mFontUnderlineBtn->setChecked( false ); } + +void QgsFieldConditionalFormatWidget::setPresets( QList styles ) +{ + mPresets.clear(); + mPresetsModel->clear(); + foreach ( QgsConditionalStyle style, styles ) + { + if ( style.isValid() ) + { + QStandardItem* item = new QStandardItem( "abc - 123" ); + if ( style.backgroundColor().isValid() ) + item->setBackground( style.backgroundColor() ); + if ( style.textColor().isValid() ) + item->setForeground( style.textColor() ); + if ( style.symbol() ) + item->setIcon( style.icon() ); + item->setFont( style.font() ); + mPresetsModel->appendRow( item ); + mPresets.append( style ); + } + } + mPresetsList->setCurrentIndex( 0 ); +} + +QList QgsFieldConditionalFormatWidget::defaultPresets() const +{ + QList styles; + QgsConditionalStyle style = QgsConditionalStyle(); + style.setBackgroundColor( QColor( 154, 216, 113 ) ); + styles.append( style ); + style = QgsConditionalStyle(); + style.setBackgroundColor( QColor( 251, 193, 78 ) ); + styles.append( style ); + style = QgsConditionalStyle(); + style.setBackgroundColor( QColor( 251, 154, 153 ) ); + styles.append( style ); + style = QgsConditionalStyle(); + style.setTextColor( QColor( 154, 216, 113 ) ); + styles.append( style ); + style = QgsConditionalStyle(); + style.setTextColor( QColor( 251, 193, 78 ) ); + styles.append( style ); + style = QgsConditionalStyle(); + style.setTextColor( QColor( 251, 154, 153 ) ); + styles.append( style ); + return styles; +} + void QgsFieldConditionalFormatWidget::saveRule() { - QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); - QList styles = props.getConditionalStyles(); + QList styles; + if ( fieldRadio->isChecked() ) + { + QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); + styles = props.conditionalStyles(); + } + if ( rowRadio->isChecked() ) + { + styles = mLayer->rowStyles(); + } + QgsConditionalStyle style = QgsConditionalStyle(); style.setRule( mRuleEdit->text() ); + style.setName( mNameEdit->text() ); QColor backColor = btnBackgroundColor->color(); QColor fontColor = btnTextColor->color(); @@ -202,22 +304,32 @@ void QgsFieldConditionalFormatWidget::saveRule() { styles.append( style ); } - props.setConditionalStyles( styles ); - mLayer->setFieldUIProperties( mFieldCombo->currentField(), props ); + + QString fieldName; + if ( fieldRadio->isChecked() ) + { + QgsFieldUIProperties props = QgsFieldUIProperties(); + props.setConditionalStyles( styles ); + mLayer->setFieldUIProperties( mFieldCombo->currentField(), props ); + fieldName = mFieldCombo->currentField(); + } + if ( rowRadio->isChecked() ) + { + mLayer->setRowStyles( styles ); + } pages->setCurrentIndex( 0 ); reloadStyles(); - emit rulesUpdated( mFieldCombo->currentField() ); + emit rulesUpdated( fieldName ); reset(); } void QgsFieldConditionalFormatWidget::reloadStyles() { mModel->clear(); - QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() ); - QList styles = props.getConditionalStyles(); - foreach ( QgsConditionalStyle style, styles ) + + foreach ( QgsConditionalStyle style, getStyles() ) { - QStandardItem* item = new QStandardItem( style.rule() ); + QStandardItem* item = new QStandardItem( style.displayText() ); item->setIcon( QIcon( style.renderPreview() ) ); mModel->appendRow( item ); } diff --git a/src/gui/attributetable/qgsfieldconditionalformatwidget.h b/src/gui/attributetable/qgsfieldconditionalformatwidget.h index a96cea84647..c0a1f10d563 100644 --- a/src/gui/attributetable/qgsfieldconditionalformatwidget.h +++ b/src/gui/attributetable/qgsfieldconditionalformatwidget.h @@ -56,10 +56,19 @@ class GUI_EXPORT QgsFieldConditionalFormatWidget : public QWidget, private Ui::Q */ void editStyle( int index, QgsConditionalStyle style ); + /** + * @param style initial conditional styling options + */ + void loadStyle( QgsConditionalStyle style ); + /** Resets the formatting options to their default state. */ void reset(); + void setPresets( QList styles ); + + QList defaultPresets() const; + signals: /** Emitted when the conditional styling rules are updated. @@ -74,12 +83,18 @@ class GUI_EXPORT QgsFieldConditionalFormatWidget : public QWidget, private Ui::Q int mEditIndex; bool mEditing; QStandardItemModel* mModel; + QStandardItemModel* mPresetsModel; QgsSymbolV2* mSymbol; + QList mPresets; + + QList getStyles(); + + void setFormattingFromStyle( QgsConditionalStyle style ); private slots: void setExpression(); void updateIcon(); - void defaultPressed( QAbstractButton*button ); + void presetSet( int index ); bool isCustomSet(); void ruleClicked( QModelIndex index ); void reloadStyles(); diff --git a/src/ui/qgsfieldconditionalformatwidget.ui b/src/ui/qgsfieldconditionalformatwidget.ui index aee028cfbdb..fa64938ff84 100644 --- a/src/ui/qgsfieldconditionalformatwidget.ui +++ b/src/ui/qgsfieldconditionalformatwidget.ui @@ -1,765 +1,651 @@ - - - QgsFieldConditionalWidget - - - - 0 - 0 - 400 - 374 - - - - - 0 - 0 - - - - - 400 - 16777215 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Conditional Format Rules - - - Qt::AlignCenter - - - - - - - 1 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::NoEditTriggers - - - - 64 - 32 - - - - - - - - 0 - - - - - - 0 - 0 - - - - Field - - - - - - - - - - - 0 - 0 - - - - New Rule - - - - :/images/themes/default/symbologyAdd.png:/images/themes/default/symbologyAdd.png - - - - - - - - - - - - - - 0 - 0 - - - - Condition - - - - - - - - - @value - - - - - - - ... - - - - :/images/themes/default/mIconExpression.svg:/images/themes/default/mIconExpression.svg - - - - - - - - - - - background-color: rgb(240, 204, 146); - - - abc - 123 - - - true - - - - 241 - 186 - 118 - - - - mDefaultButtons - - - - - - - color: rgb(170, 64, 75); - - - abc - 123 - - - true - - - - 188 - 54 - 49 - - - - mDefaultButtons - - - - - - - color: rgb(209, 166, 57); - - - abc - 123 - - - true - - - - 207 - 141 - 61 - - - - mDefaultButtons - - - - - - - color: rgb(98, 136, 78); - - - abc - 123 - - - true - - - - 80 - 157 - 52 - - - - mDefaultButtons - - - - - - - background-color: rgb(255, 167, 151); - - - abc - 123 - - - true - - - - 255 - 130 - 130 - - - - mDefaultButtons - - - - - - - background-color: rgb(208, 255, 187); - - - abc - 123 - - - true - - - - 154 - 216 - 113 - - - - mDefaultButtons - - - - - - - Format - - - - - - - - - Custom - - - true - - - - 0 - - - 5 - - - 0 - - - 0 - - - - - - - - 0 - 0 - - - - Background - - - - - - - - 0 - 0 - - - - - 10 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - - - 0 - 0 - - - - Text - - - - - - - - 0 - 0 - - - - - 10 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - - - - - - - 0 - 0 - - - - Icon - - - - - - - false - - - - 0 - 0 - - - - - 10 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - true - - - - 24 - 24 - - - - - 24 - 24 - - - - - 13 - - - - Bold text -(data defined only, overrides Style) - - - B - - - true - - - mFontButtons - - - - - - - true - - - - 24 - 24 - - - - - 24 - 24 - - - - - 13 - true - - - - Italic text -(data defined only, overrides Style) - - - I - - - true - - - mFontButtons - - - - - - - true - - - - 24 - 24 - - - - - 24 - 24 - - - - - 13 - true - - - - Underlined text - - - U - - - true - - - mFontButtons - - - - - - - true - - - - 24 - 24 - - - - - 24 - 24 - - - - - 13 - true - - - - Strikeout text - - - S - - - true - - - mFontButtons - - - - - - - false - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - Done - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Delete - - - - :/images/themes/default/mActionDeleteSelected.svg:/images/themes/default/mActionDeleteSelected.svg - - - Qt::ToolButtonTextBesideIcon - - - - - - - - - - - - - - QgsFieldComboBox - QComboBox -
qgsfieldcombobox.h
-
- - QgsColorButtonV2 - QToolButton -
qgscolorbuttonv2.h
- 1 -
-
- - listView - mRuleEdit - btnBuildExpression - mDefault1 - mDefault3 - mDefault2 - pushButton_3 - pushButton_8 - pushButton_7 - btnBackgroundColor - btnTextColor - checkIcon - btnChangeIcon - mFontBoldBtn - mFontItalicBtn - mFontUnderlineBtn - mFontStrikethroughBtn - mFontFamilyCmbBx - mSaveRule - mCancelButton - mDeleteButton - - - - - - - checkIcon - toggled(bool) - btnChangeIcon - setEnabled(bool) - - - 69 - 235 - - - 132 - 229 - - - - - - - - false - - - - -
+ + + QgsFieldConditionalWidget + + + + 0 + 0 + 335 + 376 + + + + + 0 + 0 + + + + + 400 + 16777215 + + + + Form + + + + 3 + + + 0 + + + 3 + + + 0 + + + + + Condtional Format Rules + + + Qt::AlignCenter + + + + + + + 1 + + + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + + 64 + 32 + + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + + 0 + 0 + + + + New Rule + + + + :/images/themes/default/symbologyAdd.png:/images/themes/default/symbologyAdd.png + + + + + + + 0 + + + + + + + + + + + 0 + 0 + + + + Field + + + true + + + + + + + + 0 + 0 + + + + Full row + + + + + + + + + + + + + + + @value + + + + + + + ... + + + + :/images/themes/default/mIconExpression.svg:/images/themes/default/mIconExpression.svg + + + + + + + + + + 0 + 0 + + + + Condition + + + + + + + + + Done + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete + + + + :/images/themes/default/mActionDeleteSelected.svg:/images/themes/default/mActionDeleteSelected.svg + + + Qt::ToolButtonTextBesideIcon + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 0 + + + 5 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + Background + + + + + + + + 0 + 0 + + + + + 10 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + 0 + 0 + + + + Text + + + + + + + + 0 + 0 + + + + + 10 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + + + + + 0 + 0 + + + + Icon + + + + + + + false + + + + 0 + 0 + + + + + 10 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + true + + + + 24 + 24 + + + + + 24 + 24 + + + + + 13 + + + + Bold text +(data defined only, overrides Style) + + + B + + + true + + + mFontButtons + + + + + + + true + + + + 24 + 24 + + + + + 24 + 24 + + + + + 13 + true + + + + Italic text +(data defined only, overrides Style) + + + I + + + true + + + mFontButtons + + + + + + + true + + + + 24 + 24 + + + + + 24 + 24 + + + + + 13 + true + + + + Underlined text + + + U + + + true + + + mFontButtons + + + + + + + true + + + + 24 + 24 + + + + + 24 + 24 + + + + + 13 + true + + + + Strikeout text + + + S + + + true + + + mFontButtons + + + + + + + false + + + + + + + + + + + + + 0 + 0 + + + + Name + + + + + + + + + + + + + + Preset + + + + + + + + + + + + + + + QgsFieldComboBox + QComboBox +
qgsfieldcombobox.h
+
+ + QgsColorButtonV2 + QToolButton +
qgscolorbuttonv2.h
+ 1 +
+
+ + listView + mRuleEdit + btnBuildExpression + btnBackgroundColor + btnTextColor + checkIcon + btnChangeIcon + mFontBoldBtn + mFontItalicBtn + mFontUnderlineBtn + mFontStrikethroughBtn + mFontFamilyCmbBx + mSaveRule + mCancelButton + mDeleteButton + + + + + + + fieldRadio + toggled(bool) + mFieldCombo + setEnabled(bool) + + + 14 + 27 + + + 178 + 32 + + + + + + + + false + + + + +
diff --git a/tests/src/python/test_qgsconditionalstyle.py b/tests/src/python/test_qgsconditionalstyle.py index 923724fd118..6a9f259aebb 100644 --- a/tests/src/python/test_qgsconditionalstyle.py +++ b/tests/src/python/test_qgsconditionalstyle.py @@ -26,6 +26,13 @@ TEST_DATA_DIR = unitTestDataPath() class TestPyQgsConditionalStyle(TestCase): + def new_feature(self): + feature = QgsFeature() + fields = QgsFields() + fields.append(QgsField("testfield", QVariant.Int)) + feature.setFields(fields, True) + feature["testfield"] = 20 + return feature def test_MatchesReturnsTrueForSimpleMatch(self): style = QgsConditionalStyle("@value > 10") @@ -47,6 +54,21 @@ class TestPyQgsConditionalStyle(TestCase): context = QgsExpressionContextUtils.createFeatureBasedContext(feature, fields) assert style.matches(20, context) + def test_MatchingStylesReturnsListOfCorrectStyles(self): + styles = [] + style = QgsConditionalStyle("@value > 10") + style.setName("1") + styles.append(style) + style = QgsConditionalStyle("@value > 10") + style.setName("2") + styles.append(style) + style = QgsConditionalStyle("@value < 5") + style.setName("3") + styles.append(style) + out = QgsConditionalStyle.matchingConditionalStyles(styles, 20, self.new_feature()) + assert len(out) == 2 + out[0].name() == "1" + out[1].name() == "2" if __name__ == '__main__': unittest.main()