[FEATURE] Conditional formatting for attribute table cells

This commit is contained in:
Nathan Woodrow 2015-08-20 23:06:05 +10:00
parent 3ff3b02ad7
commit faa32f36cf
27 changed files with 1764 additions and 66 deletions

View File

@ -22,6 +22,7 @@
%Include qgscontexthelp.sip %Include qgscontexthelp.sip
%Include qgscoordinatereferencesystem.sip %Include qgscoordinatereferencesystem.sip
%Include qgscoordinatetransform.sip %Include qgscoordinatetransform.sip
%Include qgsconditionalstyle.sip
%Include qgscredentials.sip %Include qgscredentials.sip
%Include qgscrscache.sip %Include qgscrscache.sip
%Include qgsdatadefined.sip %Include qgsdatadefined.sip
@ -40,6 +41,7 @@
%Include qgsfeatureiterator.sip %Include qgsfeatureiterator.sip
%Include qgsfeaturerequest.sip %Include qgsfeaturerequest.sip
%Include qgsfield.sip %Include qgsfield.sip
%Include qgsfielduiproperties.sip
%Include qgsgeometryvalidator.sip %Include qgsgeometryvalidator.sip
%Include qgsgeometrysimplifier.sip %Include qgsgeometrysimplifier.sip
%Include qgshistogram.sip %Include qgshistogram.sip

View File

@ -0,0 +1,107 @@
/** \class QgsCondtionalStyle
* \ingroup core
* Conditional styling for a rule.
*/
class QgsConditionalStyle
{
%TypeHeaderCode
#include <qgsconditionalstyle.h>
%End
public:
QgsConditionalStyle();
QgsConditionalStyle( QString rule );
/**
* @brief Check if the rule matches using the given value and feature
* @param feature The feature to match the values from.
* @return True of the rule matches against the given feature
*/
bool matches( QVariant value, QgsFeature *feature = 0 );
/**
* @brief Render a preview icon of the rule.
* @return QPixmap preview of the style
*/
QPixmap renderPreview();
/**
* @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
* @param value
*/
void setRule( QString value );
/**
* @brief Set the background color for the style
* @param value QColor for background color
*/
void setBackgroundColor( QColor value );
/**
* @brief Set the text color for the style
* @param value QColor for text color
*/
void setTextColor( QColor value );
/**
* @brief Set the font for the the style
* @param value QFont to be used for text
*/
void setFont( QFont value );
/**
* @brief Set the icon for the style. Icons are generated from symbols
* @param value QgsSymbolV2 to be used when generating the icon
*/
void setSymbol( QgsSymbolV2* value );
/**
* @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
* @return A QPixmap that was set for the icon
*/
QPixmap icon() const;
/**
* @brief The text color set for style
* @return QColor for text color
*/
QColor textColor() const;
/**
* @brief The background color for style
* @return QColor for background color
*/
QColor backgroundColor() const;
/**
* @brief The font for the style
* @return QFont for the style
*/
QFont font() const;
/**
* @brief The condtion rule set for the style. Rule may contain variable @value
* to represent the current value
* @return QString of the current set rule
*/
QString rule() const;
/**
* @brief isValid Check if this rule is valid. A valid rule has one or more properties
* set.
* @return True if the rule is valid.
*/
bool isValid() const;
/** Reads vector conditional style specific state from layer Dom node.
*/
virtual bool readXml( const QDomNode& node );
/** Write vector conditional style specific state from layer Dom node.
*/
virtual bool writeXml( QDomNode & node, QDomDocument & doc );
};

View File

@ -0,0 +1,45 @@
/** \class QgsFieldUIProperties
* \ingroup core
* Holds extra UI properties for a field.
*
* Currently this object holds informations about condtional styles but in future will hold
* things like field widgets, etc
*/
class QgsFieldUIProperties
{
%TypeHeaderCode
#include <qgsfielduiproperties.h>
%End
public:
QgsFieldUIProperties();
/**
* @brief Set the condtional styles for the field UI properties.
* @param styles
*/
void setConditionalStyles( QList<QgsConditionalStyle> styles );
/**
* @brief Returns the condtional styles set for the field UI properties
* @return A list of condtional styles that have been set.
*/
const QList<QgsConditionalStyle> getConditionalStyles();
/**
* @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()
*/
const QgsConditionalStyle matchingConditionalStyle( QVariant value, QgsFeature* feature );
/** Reads field ui properties specific state from Dom node.
*/
virtual bool readXml( const QDomNode& node );
/** Write field ui properties specific state from Dom node.
*/
virtual bool writeXml( QDomNode & node, QDomDocument & doc );
};

View File

@ -2,6 +2,7 @@
typedef QList<int> QgsAttributeList; typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsAttributeIds; typedef QSet<int> QgsAttributeIds;
class QgsAttributeEditorElement : QObject class QgsAttributeEditorElement : QObject
{ {
%TypeHeaderCode %TypeHeaderCode

View File

@ -133,6 +133,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
connect( mFilterActionMapper, SIGNAL( mapped( QObject* ) ), SLOT( filterColumnChanged( QObject* ) ) ); connect( mFilterActionMapper, SIGNAL( mapped( QObject* ) ), SLOT( filterColumnChanged( QObject* ) ) );
connect( mFilterQuery, SIGNAL( returnPressed() ), SLOT( filterQueryAccepted() ) ); connect( mFilterQuery, SIGNAL( returnPressed() ), SLOT( filterQueryAccepted() ) );
connect( mActionApplyFilter, SIGNAL( triggered() ), SLOT( filterQueryAccepted() ) ); connect( mActionApplyFilter, SIGNAL( triggered() ), SLOT( filterQueryAccepted() ) );
connect( mSetStyles, SIGNAL( pressed() ), SLOT( openConditionalStyles() ) );
// info from layer to table // info from layer to table
connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) ); connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
@ -729,6 +730,11 @@ void QgsAttributeTableDialog::filterQueryAccepted()
filterQueryChanged( mFilterQuery->text() ); filterQueryChanged( mFilterQuery->text() );
} }
void QgsAttributeTableDialog::openConditionalStyles()
{
mMainView->openConditionalStyles();
}
void QgsAttributeTableDialog::setFilterExpression( QString filterString ) void QgsAttributeTableDialog::setFilterExpression( QString filterString )
{ {
if ( mCurrentSearchWidgetWrapper == 0 || !mCurrentSearchWidgetWrapper->applyDirectly() ) if ( mCurrentSearchWidgetWrapper == 0 || !mCurrentSearchWidgetWrapper->applyDirectly() )

View File

@ -152,6 +152,7 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
void filterEdited(); void filterEdited();
void filterQueryChanged( const QString& query ); void filterQueryChanged( const QString& query );
void filterQueryAccepted(); void filterQueryAccepted();
void openConditionalStyles();
/** /**
* update window title * update window title
@ -206,6 +207,7 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
QDockWidget* mDock; QDockWidget* mDock;
QgsDistanceArea* myDa; QgsDistanceArea* myDa;
QMenu* mFilterColumnsMenu; QMenu* mFilterColumnsMenu;
QSignalMapper* mFilterActionMapper; QSignalMapper* mFilterActionMapper;

View File

@ -79,6 +79,7 @@ SET(QGIS_CORE_SRCS
qgscontexthelp_texts.cpp qgscontexthelp_texts.cpp
qgscoordinatereferencesystem.cpp qgscoordinatereferencesystem.cpp
qgscoordinatetransform.cpp qgscoordinatetransform.cpp
qgsconditionalstyle.cpp
qgscredentials.cpp qgscredentials.cpp
qgsdartmeasurement.cpp qgsdartmeasurement.cpp
qgscrscache.cpp qgscrscache.cpp
@ -100,6 +101,7 @@ SET(QGIS_CORE_SRCS
qgsfeaturerequest.cpp qgsfeaturerequest.cpp
qgsfeaturestore.cpp qgsfeaturestore.cpp
qgsfield.cpp qgsfield.cpp
qgsfielduiproperties.cpp
qgsfontutils.cpp qgsfontutils.cpp
qgsgeometrycache.cpp qgsgeometrycache.cpp
qgsgeometrysimplifier.cpp qgsgeometrysimplifier.cpp
@ -516,6 +518,7 @@ SET(QGIS_CORE_HDRS
qgscolorschemeregistry.h qgscolorschemeregistry.h
qgsconnectionpool.h qgsconnectionpool.h
qgscontexthelp.h qgscontexthelp.h
qgsconditionalstyle.h
qgscoordinatereferencesystem.h qgscoordinatereferencesystem.h
qgscrscache.h qgscrscache.h
qgscsexception.h qgscsexception.h
@ -541,6 +544,7 @@ SET(QGIS_CORE_HDRS
qgsfeaturerequest.h qgsfeaturerequest.h
qgsfeaturestore.h qgsfeaturestore.h
qgsfield.h qgsfield.h
qgsfielduiproperties.h
qgsfield_p.h qgsfield_p.h
qgsfontutils.h qgsfontutils.h
qgsgeometrycache.h qgsgeometrycache.h

View File

@ -0,0 +1,144 @@
#include <QPainter>
#include "qgsconditionalstyle.h"
#include "qgsexpression.h"
#include "qgsfontutils.h"
#include "qgssymbollayerv2utils.h"
#include "qgsmarkersymbollayerv2.h"
QgsConditionalStyle::QgsConditionalStyle()
: mValid( false )
, mSymbol( 0 )
{}
QgsConditionalStyle::QgsConditionalStyle( QString rule )
: mValid( false )
, mSymbol( 0 )
{
setRule( rule );
}
QgsConditionalStyle::QgsConditionalStyle( const QgsConditionalStyle &other )
: mValid( other.mValid )
, mRule( other.mRule )
, mFont( other.mFont )
, mBackColor( other.mBackColor )
, mTextColor( other.mTextColor )
, mIcon( other.mIcon )
{
if ( other.mSymbol.data() )
mSymbol.reset( other.mSymbol->clone() );
}
QgsConditionalStyle& QgsConditionalStyle::operator=( const QgsConditionalStyle & other )
{
mValid = other.mValid;
mRule = other.mRule;
mFont = other.mFont;
mBackColor = other.mBackColor;
mTextColor = other.mTextColor;
mIcon = other.mIcon;
if ( other.mSymbol.data() )
{
mSymbol.reset( other.mSymbol->clone() );
}
else
{
mSymbol.reset();
}
return ( *this );
}
QgsConditionalStyle::~QgsConditionalStyle()
{
}
void QgsConditionalStyle::setSymbol( QgsSymbolV2* value )
{
mValid = true;
if ( value )
{
mSymbol.reset( value->clone() );
mIcon = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.data(), QSize( 16, 16 ) );
}
else
{
mSymbol.reset();
}
}
bool QgsConditionalStyle::matches( QVariant value, QgsFeature *feature )
{
// TODO Replace with expression context
QgsExpression exp( QString( mRule ).replace( "@value", value.toString() ) );
if ( feature )
{
return exp.evaluate( feature, *feature->fields() ).toBool();
}
{
return exp.evaluate().toBool();
}
}
QPixmap QgsConditionalStyle::renderPreview()
{
QPixmap pixmap( 64, 32 );
QPainter painter( &pixmap );
if ( mBackColor.isValid() )
painter.setBrush( mBackColor );
else
painter.setBrush( QColor( Qt::white ) );
QRect rect = QRect( 0, 0, 64, 32 );
painter.setPen( Qt::NoPen );
painter.drawRect( rect );
painter.drawPixmap( 8, 8, icon() );
if ( mTextColor.isValid() )
painter.setPen( mTextColor );
else
painter.setPen( Qt::black );
painter.setRenderHint( QPainter::Antialiasing );
painter.setRenderHint( QPainter::HighQualityAntialiasing );
painter.setFont( font() );
rect = QRect( 32, 0, 32, 32 );
painter.drawText( rect, Qt::AlignCenter, "abc\n123" );
painter.end();
return pixmap;
}
bool QgsConditionalStyle::writeXml( QDomNode &node, QDomDocument &doc )
{
QDomElement stylesel = doc.createElement( "style" );
stylesel.setAttribute( "rule", mRule );
stylesel.setAttribute( "background_color", mBackColor.name() );
stylesel.setAttribute( "text_color", mTextColor.name() );
QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, "font" );
stylesel.appendChild( labelFontElem );
if ( ! mSymbol.isNull() )
{
QDomElement symbolElm = QgsSymbolLayerV2Utils::saveSymbol( "icon", mSymbol.data(), doc );
stylesel.appendChild( symbolElm );
}
node.appendChild( stylesel );
return true;
}
bool QgsConditionalStyle::readXml( const QDomNode &node )
{
QDomElement styleElm = node.toElement();
setRule( styleElm.attribute( "rule" ) );
setBackgroundColor( QColor( styleElm.attribute( "background_color" ) ) );
setTextColor( QColor( styleElm.attribute( "text_color" ) ) );
QgsFontUtils::setFromXmlChildNode( mFont, styleElm, "font" );
QDomElement symbolElm = styleElm.firstChildElement( "symbol" );
if ( !symbolElm.isNull() )
{
QgsSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( symbolElm );
setSymbol( symbol );
}
return true;
}

View File

@ -0,0 +1,131 @@
#ifndef QGSCONDITIONALSTYLE_H
#define QGSCONDITIONALSTYLE_H
#include <QFont>
#include <QColor>
#include <QPixmap>
#include <QDomNode>
#include <QDomDocument>
#include "qgsfeature.h"
#include "qgssymbolv2.h"
/** \class QgsFieldFormat
* Conditional styling for a rule.
*/
class CORE_EXPORT QgsConditionalStyle
{
public:
QgsConditionalStyle();
QgsConditionalStyle( const QgsConditionalStyle& other );
QgsConditionalStyle( QString rule );
~QgsConditionalStyle();
QgsConditionalStyle& operator=( const QgsConditionalStyle& other );
/**
* @brief Check if the rule matches using the given value and feature
* @param value The current value being checked. \@value is replaced in the rule with this value.
* @param feature The feature to match the values from.
* @return True of the rule matches against the given feature
*/
bool matches( QVariant value, QgsFeature *feature = 0 );
/**
* @brief Render a preview icon of the rule.
* @return QPixmap preview of the style
*/
QPixmap renderPreview();
/**
* @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
* @param value The QgsExpression style rule to use for this style
*/
void setRule( QString value ) { mRule = value; mValid = true; }
/**
* @brief Set the background color for the style
* @param value QColor for background color
*/
void setBackgroundColor( QColor value ) { mBackColor = value; mValid = true; }
/**
* @brief Set the text color for the style
* @param value QColor for text color
*/
void setTextColor( QColor value ) { mTextColor = value; mValid = true; }
/**
* @brief Set the font for the the style
* @param value QFont to be used for text
*/
void setFont( QFont value ) { mFont = value; mValid = true; }
/**
* @brief Set the icon for the style. Icons are generated from symbols
* @param value QgsSymbolV2 to be used when generating the icon
*/
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
*/
QPixmap icon() const { return mIcon; }
/**
* @brief The symbol used to generate the icon for the style
* @return The QgsSymbolV2 used for the icon
*/
QgsSymbolV2* symbol() const { return mSymbol.data(); }
/**
* @brief The text color set for style
* @return QColor for text color
*/
QColor textColor() const { return mTextColor; }
/**
* @brief The background color for style
* @return QColor for background color
*/
QColor backgroundColor() const { return mBackColor; }
/**
* @brief The font for the style
* @return QFont for the style
*/
QFont font() const { return mFont; }
/**
* @brief The condtion rule set for the style. Rule may contain variable \@value
* to represent the current value
* @return QString of the current set rule
*/
QString rule() const { return mRule; }
/**
* @brief isValid Check if this rule is valid. A valid rule has one or more properties
* set.
* @return True if the rule is valid.
*/
bool isValid() const { return mValid; }
/** Reads vector conditional style specific state from layer Dom node.
*/
virtual bool readXml( const QDomNode& node );
/** Write vector conditional style specific state from layer Dom node.
*/
virtual bool writeXml( QDomNode & node, QDomDocument & doc );
bool mValid;
QString mRule;
QScopedPointer<QgsSymbolV2> mSymbol;
QFont mFont;
QColor mBackColor;
QColor mTextColor;
QPixmap mIcon;
};
#endif // QGSCONDITIONALSTYLE_H

View File

@ -20,6 +20,7 @@
#include <QSettings> #include <QSettings>
#include <QtCore/qmath.h> #include <QtCore/qmath.h>
#if 0 #if 0
QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num, QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
QString comment ) QString comment )
@ -33,8 +34,8 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
// names how they are now. // names how they are now.
} }
#endif #endif
QgsField::QgsField( QString name, QVariant::Type type,
QgsField::QgsField( QString name, QVariant::Type type, QString typeName, int len, int prec, QString comment ) QString typeName, int len, int prec, QString comment )
{ {
d = new QgsFieldPrivate( name, type, typeName, len, prec, comment ); d = new QgsFieldPrivate( name, type, typeName, len, prec, comment );
} }
@ -176,6 +177,7 @@ bool QgsField::convertCompatible( QVariant& v ) const
return true; return true;
} }
QDataStream& operator<<( QDataStream& out, const QgsField& field ) QDataStream& operator<<( QDataStream& out, const QgsField& field )
{ {
out << field.name(); out << field.name();

View File

@ -27,6 +27,8 @@ class QgsExpression;
class QgsFieldPrivate; class QgsFieldPrivate;
class QgsFieldsPrivate; class QgsFieldsPrivate;
/** \class QgsField /** \class QgsField
* \ingroup core * \ingroup core
* Encapsulate a field in an attribute table or data source. * Encapsulate a field in an attribute table or data source.
@ -148,10 +150,12 @@ class CORE_EXPORT QgsField
*/ */
bool convertCompatible( QVariant& v ) const; bool convertCompatible( QVariant& v ) const;
private: private:
QSharedDataPointer<QgsFieldPrivate> d; QSharedDataPointer<QgsFieldPrivate> d;
}; // class QgsField }; // class QgsField
Q_DECLARE_METATYPE( QgsField ); Q_DECLARE_METATYPE( QgsField );

View File

@ -0,0 +1,56 @@
#include <QDomElement>
#include "qgsconditionalstyle.h"
#include "qgsfielduiproperties.h"
QgsFieldUIProperties::QgsFieldUIProperties()
: mStyles( QList<QgsConditionalStyle>() )
{}
void QgsFieldUIProperties::setConditionalStyles( QList<QgsConditionalStyle> styles )
{
mStyles = styles;
}
QList<QgsConditionalStyle> QgsFieldUIProperties::getConditionalStyles()
{
return mStyles;
}
QgsConditionalStyle QgsFieldUIProperties::matchingConditionalStyle( QVariant value, QgsFeature *feature )
{
foreach ( QgsConditionalStyle style, mStyles )
{
if ( style.matches( value, feature ) )
return style;
}
return QgsConditionalStyle();
}
bool QgsFieldUIProperties::writeXml( QDomNode &node, QDomDocument &doc )
{
QDomElement stylesel = doc.createElement( "conditionalstyles" );
foreach ( QgsConditionalStyle style, mStyles )
{
style.writeXml( stylesel, doc );
}
node.appendChild( stylesel );
return true;
}
bool QgsFieldUIProperties::readXml( const QDomNode &node )
{
mStyles.clear();
QDomElement condel = node.firstChildElement( "conditionalstyles" );
QDomNodeList stylesList = condel.elementsByTagName( "style" );
for ( int i = 0; i < stylesList.size(); ++i )
{
QDomElement styleElm = stylesList.at( i ).toElement();
QgsConditionalStyle style = QgsConditionalStyle();
style.readXml( styleElm );
mStyles.append( style );
}
return true;
}

View File

@ -0,0 +1,56 @@
#ifndef QGSFIELDUIPROPERTIES_H
#define QGSFIELDUIPROPERTIES_H
#include <QDomDocument>
#include <QDomNode>
#include "qgsfeature.h"
#include "qgsconditionalstyle.h"
/** \class QgsFieldUIProperties
* Holds extra UI properties for a field.
*
* Currently this object holds informations about condtional styles but in future will hold
* things like field widgets, etc
*
* TODO Move UI field related stuff from QgsVectorLayer here
*/
class CORE_EXPORT QgsFieldUIProperties
{
public:
QgsFieldUIProperties();
/**
* @brief Set the condtional styles for the field UI properties.
* @param styles
*/
void setConditionalStyles( QList<QgsConditionalStyle> styles );
/**
* @brief Returns the condtional styles set for the field UI properties
* @return A list of condtional styles that have been set.
*/
QList<QgsConditionalStyle> getConditionalStyles();
/**
* @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()
*/
QgsConditionalStyle matchingConditionalStyle( QVariant value, QgsFeature* feature );
/** Reads field ui properties specific state from Dom node.
*/
virtual bool readXml( const QDomNode& node );
/** Write field ui properties specific state from Dom node.
*/
virtual bool writeXml( QDomNode & node, QDomDocument & doc );
private:
QList<QgsConditionalStyle> mStyles;
};
#endif // QGSFIELDUIPROPERTIES_H

View File

@ -45,6 +45,7 @@
#include "qgsfeature.h" #include "qgsfeature.h"
#include "qgsfeaturerequest.h" #include "qgsfeaturerequest.h"
#include "qgsfield.h" #include "qgsfield.h"
#include "qgsfielduiproperties.h"
#include "qgsgeometrycache.h" #include "qgsgeometrycache.h"
#include "qgsgeometry.h" #include "qgsgeometry.h"
#include "qgslabel.h" #include "qgslabel.h"
@ -1315,6 +1316,19 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
readStyleManager( layer_node ); readStyleManager( layer_node );
mFieldProperties.clear();
QDomNodeList nodeList = layer_node.toElement().elementsByTagName( "fielduiproperty" );
for ( int i = 0;i < nodeList.count(); i++ )
{
QDomElement propElm = nodeList.at( i ).toElement();
QString fieldName = propElm.attribute( "fieldname" );
QgsDebugMsg( "FIELDS!!" );
QgsDebugMsg( fieldName );
QgsFieldUIProperties props = QgsFieldUIProperties();
props.readXml( propElm );
setFieldUIProperties( fieldName, props );
}
setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) ); setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
return mValid; // should be true if read successfully return mValid; // should be true if read successfully
@ -1508,6 +1522,19 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
writeStyleManager( layer_node, document ); writeStyleManager( layer_node, document );
QDomElement properties = document.createElement( "fielduiproperties" );
QHash<QString, QgsFieldUIProperties>::iterator props;
for ( props = mFieldProperties.begin(); props != mFieldProperties.end(); ++props )
{
QDomElement fielduipropel = document.createElement( "fielduiproperty" );
fielduipropel.setAttribute( "fieldname", props.key() );
QgsFieldUIProperties property = props.value();
property.writeXml( fielduipropel, document );
properties.appendChild( fielduipropel );
}
layer_node.appendChild( properties );
// renderer specific settings // renderer specific settings
QString errorMsg; QString errorMsg;
return writeSymbology( layer_node, document, errorMsg ); return writeSymbology( layer_node, document, errorMsg );
@ -2002,6 +2029,20 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
return true; return true;
} }
QgsFieldUIProperties QgsVectorLayer::fieldUIProperties( QString fieldName )
{
if ( mFieldProperties.contains( fieldName ) )
{
return mFieldProperties[fieldName];
}
return QgsFieldUIProperties();
}
void QgsVectorLayer::setFieldUIProperties( QString fieldName, QgsFieldUIProperties props )
{
mFieldProperties.insert( fieldName, props );
}
bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage ) bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
{ {
// get the Name element // get the Name element

View File

@ -23,6 +23,7 @@
#include <QSet> #include <QSet>
#include <QList> #include <QList>
#include <QStringList> #include <QStringList>
#include <QFont>
#include "qgis.h" #include "qgis.h"
#include "qgsmaplayer.h" #include "qgsmaplayer.h"
@ -39,6 +40,7 @@ class QImage;
class QgsAbstractGeometrySimplifier; class QgsAbstractGeometrySimplifier;
class QgsAttributeAction; class QgsAttributeAction;
class QgsFieldUIProperties;
class QgsCoordinateTransform; class QgsCoordinateTransform;
class QgsDiagramLayerSettings; class QgsDiagramLayerSettings;
class QgsDiagramRendererV2; class QgsDiagramRendererV2;
@ -65,6 +67,7 @@ class QgsPointV2;
typedef QList<int> QgsAttributeList; typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsAttributeIds; typedef QSet<int> QgsAttributeIds;
/** /**
* This is an abstract base class for any elements of a drag and drop form. * This is an abstract base class for any elements of a drag and drop form.
* *
@ -356,6 +359,8 @@ protected:
QSharedPointer<QStringList> joinFieldsSubset; QSharedPointer<QStringList> joinFieldsSubset;
}; };
/** \ingroup core /** \ingroup core
* Represents a vector layer which manages a vector based data sets. * Represents a vector layer which manages a vector based data sets.
* *
@ -1749,6 +1754,22 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/ */
bool simplifyDrawingCanbeApplied( const QgsRenderContext& renderContext, QgsVectorSimplifyMethod::SimplifyHint simplifyHint ) const; bool simplifyDrawingCanbeApplied( const QgsRenderContext& renderContext, QgsVectorSimplifyMethod::SimplifyHint simplifyHint ) const;
/**
* @brief Return the field properties that have been set for the given field.
* Field UI properties hold extra UI information for a field that can be used in the UI.
* @param fieldName The field name to get the field properties for.
* @return Return the UI properties set for the field. Returns a new \class QgsFieldUIProperties if
* the none is currently set for the field.
*/
QgsFieldUIProperties fieldUIProperties( QString fieldName );
/**
* @brief Set the the field UI properties for a given field.
* @param fieldName The field name.
* @param props The properties to assign to a field.
*/
void setFieldUIProperties( QString fieldName, QgsFieldUIProperties props );
public slots: public slots:
/** /**
* Select feature by its ID * Select feature by its ID
@ -1951,6 +1972,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/ */
void writeCustomSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage ) const; void writeCustomSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage ) const;
private slots: private slots:
void onRelationsLoaded(); void onRelationsLoaded();
void onJoinedFieldsChanged(); void onJoinedFieldsChanged();
@ -2001,6 +2023,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
private: // Private attributes private: // Private attributes
QHash<QString, QgsFieldUIProperties> mFieldProperties;
/** Pointer to data provider derived from the abastract base class QgsDataProvider */ /** Pointer to data provider derived from the abastract base class QgsDataProvider */
QgsVectorDataProvider *mDataProvider; QgsVectorDataProvider *mDataProvider;

View File

@ -48,6 +48,7 @@ SET(QGIS_GUI_SRCS
attributetable/qgsattributetabledelegate.cpp attributetable/qgsattributetabledelegate.cpp
attributetable/qgsattributetablefiltermodel.cpp attributetable/qgsattributetablefiltermodel.cpp
attributetable/qgsfieldconditionalformatwidget.cpp
attributetable/qgsattributetablemodel.cpp attributetable/qgsattributetablemodel.cpp
attributetable/qgsattributetableview.cpp attributetable/qgsattributetableview.cpp
attributetable/qgsdualview.cpp attributetable/qgsdualview.cpp
@ -399,6 +400,7 @@ SET(QGIS_GUI_MOC_HDRS
attributetable/qgsattributetablemodel.h attributetable/qgsattributetablemodel.h
attributetable/qgsattributetableview.h attributetable/qgsattributetableview.h
attributetable/qgsdualview.h attributetable/qgsdualview.h
attributetable/qgsfieldconditionalformatwidget.h
attributetable/qgsfeaturelistmodel.h attributetable/qgsfeaturelistmodel.h
attributetable/qgsfeaturelistview.h attributetable/qgsfeaturelistview.h
attributetable/qgsfeaturelistviewdelegate.h attributetable/qgsfeaturelistviewdelegate.h

View File

@ -20,6 +20,8 @@
#include "qgsattributeaction.h" #include "qgsattributeaction.h"
#include "qgseditorwidgetregistry.h" #include "qgseditorwidgetregistry.h"
#include "qgsexpression.h" #include "qgsexpression.h"
#include "qgsconditionalstyle.h"
#include "qgsfielduiproperties.h"
#include "qgsfield.h" #include "qgsfield.h"
#include "qgslogger.h" #include "qgslogger.h"
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
@ -27,6 +29,7 @@
#include "qgsmaplayerregistry.h" #include "qgsmaplayerregistry.h"
#include "qgsrendererv2.h" #include "qgsrendererv2.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgssymbollayerv2utils.h"
#include <QVariant> #include <QVariant>
@ -509,6 +512,10 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
&& role != SortRole && role != SortRole
&& role != FeatureIdRole && role != FeatureIdRole
&& role != FieldIndexRole && role != FieldIndexRole
&& role != Qt::BackgroundColorRole
&& role != Qt::TextColorRole
&& role != Qt::DecorationRole
&& role != Qt::FontRole
) )
) )
return QVariant(); return QVariant();
@ -565,6 +572,20 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
return mWidgetFactories[ index.column()]->representValue( layer(), fieldId, mWidgetConfigs[ index.column()], mAttributeWidgetCaches[ index.column()], val ); return mWidgetFactories[ index.column()]->representValue( layer(), fieldId, mWidgetConfigs[ index.column()], mAttributeWidgetCaches[ index.column()], val );
} }
QgsFieldUIProperties props = layer()->fieldUIProperties( field.name() );
QgsConditionalStyle style = props.matchingConditionalStyle( val, &mFeat );
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; return val;
} }

View File

@ -32,6 +32,7 @@ class QgsMapCanvas;
class QgsMapLayerAction; class QgsMapLayerAction;
class QgsEditorWidgetFactory; class QgsEditorWidgetFactory;
/** /**
* A model backed by a {@link QgsVectorLayerCache} which is able to provide * A model backed by a {@link QgsVectorLayerCache} which is able to provide
* feature/attribute information to a QAbstractItemView. * feature/attribute information to a QAbstractItemView.

View File

@ -45,6 +45,8 @@ QgsDualView::QgsDualView( QWidget* parent )
{ {
setupUi( this ); setupUi( this );
mConditionalFormatWidget->hide();
mPreviewActionMapper = new QSignalMapper( this ); mPreviewActionMapper = new QSignalMapper( this );
mPreviewColumnsMenu = new QMenu( this ); mPreviewColumnsMenu = new QMenu( this );
@ -68,6 +70,8 @@ void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const Qg
initLayerCache( layer, !request.filterRect().isNull() ); initLayerCache( layer, !request.filterRect().isNull() );
initModels( mapCanvas, request ); initModels( mapCanvas, request );
mConditionalFormatWidget->setLayer( layer );
mTableView->setModel( mFilterModel ); mTableView->setModel( mFilterModel );
mFeatureList->setModel( mFeatureListModel ); mFeatureList->setModel( mFeatureListModel );
mAttributeForm = new QgsAttributeForm( layer, QgsFeature(), mEditorContext ); mAttributeForm = new QgsAttributeForm( layer, QgsFeature(), mEditorContext );
@ -85,7 +89,8 @@ void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const Qg
else else
columnBoxInit(); columnBoxInit();
mTableView->resizeColumnsToContents(); // This slows down load of the attribute table heaps and uses loads of memory.
//mTableView->resizeColumnsToContents();
mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) ); mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) );
} }
@ -275,6 +280,12 @@ bool QgsDualView::saveEditChanges()
return mAttributeForm->save(); return mAttributeForm->save();
} }
void QgsDualView::openConditionalStyles()
{
mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
mConditionalFormatWidget->viewRules();
}
void QgsDualView::previewExpressionBuilder() void QgsDualView::previewExpressionBuilder()
{ {
// Show expression builder // Show expression builder

View File

@ -20,6 +20,7 @@
#include "ui_qgsdualviewbase.h" #include "ui_qgsdualviewbase.h"
#include "qgsfieldconditionalformatwidget.h"
#include "qgsattributeeditorcontext.h" #include "qgsattributeeditorcontext.h"
#include "qgsattributetablefiltermodel.h" #include "qgsattributetablefiltermodel.h"
#include "qgscachedfeatureiterator.h" #include "qgscachedfeatureiterator.h"
@ -162,6 +163,8 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*/ */
bool saveEditChanges(); bool saveEditChanges();
void openConditionalStyles();
signals: signals:
/** /**
* Is emitted, whenever the display expression is successfully changed * Is emitted, whenever the display expression is successfully changed

View File

@ -0,0 +1,230 @@
#include "qgsfieldconditionalformatwidget.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgsfielduiproperties.h"
#include "qgssymbolv2.h"
#include "qgssymbolv2selectordialog.h"
#include "qgssymbollayerv2utils.h"
#include "qgsstylev2.h"
QgsFieldConditionalFormatWidget::QgsFieldConditionalFormatWidget( QWidget *parent ) :
QWidget( parent )
, mEditing( false )
{
setupUi( this );
mDeleteButton->hide();
connect( mFieldCombo, SIGNAL( fieldChanged( QString ) ), SLOT( fieldChanged( QString ) ) );
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() ) );
mModel = new QStandardItemModel();
listView->setModel( mModel );
}
void QgsFieldConditionalFormatWidget::updateIcon()
{
mSymbol = QgsSymbolV2::defaultSymbol( QGis::Point );
QgsSymbolV2SelectorDialog dlg( mSymbol, QgsStyleV2::defaultStyle(), 0, this );
if ( !dlg.exec() )
{
return;
}
QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mSymbol, btnChangeIcon->iconSize() );
btnChangeIcon->setIcon( icon );
}
void QgsFieldConditionalFormatWidget::setExpression()
{
QgsExpressionBuilderDialog dlg( mLayer, mRuleEdit->text(), this );
dlg.setWindowTitle( tr( "Conditional style rule expression" ) );
if ( dlg.exec() )
{
QString expression = dlg.expressionBuilder()->expressionText();
mRuleEdit->setText( expression );
}
}
void QgsFieldConditionalFormatWidget::defaultPressed( QAbstractButton *button )
{
QColor backColor = button->property( "backColor" ).value<QColor>();
QColor fontColor = button->property( "fontColor" ).value<QColor>();
btnBackgroundColor->setColor( backColor );
btnTextColor->setColor( fontColor );
}
void QgsFieldConditionalFormatWidget::setLayer( QgsVectorLayer *theLayer )
{
mLayer = theLayer;
mFieldCombo->setLayer( theLayer );
mFieldCombo->setCurrentIndex( 0 );
}
void QgsFieldConditionalFormatWidget::ruleClicked( QModelIndex index )
{
QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() );
QList<QgsConditionalStyle> styles = props.getConditionalStyles();
QgsConditionalStyle style = styles.at( index.row() );
editStyle( index.row(), style );
}
void QgsFieldConditionalFormatWidget::editStyle( int editIndex, QgsConditionalStyle style )
{
pages->setCurrentIndex( 1 );
mEditIndex = editIndex;
mEditing = true;
mRuleEdit->setText( style.rule() );
mDeleteButton->show();
btnBackgroundColor->setColor( style.backgroundColor() );
btnTextColor->setColor( style.textColor() );
if ( !style.icon().isNull() )
{
checkIcon->setChecked( true );
QIcon icon( style.icon() );
btnChangeIcon->setIcon( icon );
}
else
{
checkIcon->setChecked( false );
btnChangeIcon->setIcon( QIcon() );
}
if ( style.symbol() )
{
mSymbol = style.symbol()->clone();
}
else
{
mSymbol = 0;
}
QFont font = style.font();
mFontBoldBtn->setChecked( font.bold() );
mFontItalicBtn->setChecked( font.italic() );
mFontStrikethroughBtn->setChecked( font.strikeOut() );
mFontUnderlineBtn->setChecked( font.underline() );
mFontFamilyCmbBx->setFont( font );
}
void QgsFieldConditionalFormatWidget::deleteRule()
{
QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() );
QList<QgsConditionalStyle> styles = props.getConditionalStyles();
styles.removeAt( mEditIndex );
props.setConditionalStyles( styles );
mLayer->setFieldUIProperties( mFieldCombo->currentField(), props );
pages->setCurrentIndex( 0 );
reloadStyles();
emit rulesUpdates();
}
void QgsFieldConditionalFormatWidget::cancelRule()
{
pages->setCurrentIndex( 0 );
reloadStyles();
reset();
}
void QgsFieldConditionalFormatWidget::addNewRule()
{
pages->setCurrentIndex( 1 );
reset();
}
void QgsFieldConditionalFormatWidget::reset()
{
mSymbol = 0;
mRuleEdit->clear();
btnBackgroundColor->setColor( QColor() );
btnTextColor->setColor( QColor() );
mDefault1->toggle();
defaultPressed( mDefault1 );
mDeleteButton->hide();
mEditing = false;
checkIcon->setChecked( false );
btnChangeIcon->setIcon( QIcon() );
mFontBoldBtn->setChecked( false );
mFontItalicBtn->setChecked( false );
mFontStrikethroughBtn->setChecked( false );
mFontUnderlineBtn->setChecked( false );
}
void QgsFieldConditionalFormatWidget::saveRule()
{
QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() );
QList<QgsConditionalStyle> styles = props.getConditionalStyles();
QgsConditionalStyle style = QgsConditionalStyle();
style.setRule( mRuleEdit->text() );
QColor backColor = btnBackgroundColor->color();
QColor fontColor = btnTextColor->color();
QFont font = mFontFamilyCmbBx->currentFont();
font.setBold( mFontBoldBtn->isChecked() );
font.setItalic( mFontItalicBtn->isChecked() );
font.setStrikeOut( mFontStrikethroughBtn->isChecked() );
font.setUnderline( mFontUnderlineBtn->isChecked() );
style.setFont( font );
style.setBackgroundColor( backColor );
style.setTextColor( fontColor );
if ( mSymbol && checkIcon->isChecked() )
{
style.setSymbol( mSymbol );
}
else
{
style.setSymbol( 0 );
}
if ( mEditing )
{
styles.replace( mEditIndex, style );
}
else
{
styles.append( style );
}
props.setConditionalStyles( styles );
mLayer->setFieldUIProperties( mFieldCombo->currentField(), props );
pages->setCurrentIndex( 0 );
reloadStyles();
emit rulesUpdates();
reset();
}
void QgsFieldConditionalFormatWidget::reloadStyles()
{
mModel->clear();
QgsFieldUIProperties props = mLayer->fieldUIProperties( mFieldCombo->currentField() );
QList<QgsConditionalStyle> styles = props.getConditionalStyles();
foreach ( QgsConditionalStyle style, styles )
{
QStandardItem* item = new QStandardItem( style.rule() );
item->setIcon( QIcon( style.renderPreview() ) );
mModel->appendRow( item );
}
}
void QgsFieldConditionalFormatWidget::fieldChanged( QString fieldName )
{
reloadStyles();
}
void QgsFieldConditionalFormatWidget::viewRules()
{
pages->setCurrentIndex( 0 );
}
bool QgsFieldConditionalFormatWidget::isCustomSet()
{
return ( btnBackgroundColor->color().isValid()
|| btnTextColor->color().isValid()
|| mFontButtons->checkedId() != -1 );
}

View File

@ -0,0 +1,71 @@
/***************************************************************************
qgsfieldconditionalformatwidget.h
-------------------
begin :
copyright :
email :
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSFIELDCONDITIONALFORMATWIDGET_H
#define QGSFIELDCONDITIONALFORMATWIDGET_H
#include <QWidget>
#include <QStandardItemModel>
#include <QStandardItem>
#include "ui_qgsfieldconditionalformatwidget.h"
#include "qgsfieldcombobox.h"
#include "qgsconditionalstyle.h"
class GUI_EXPORT QgsFieldConditionalFormatWidget : public QWidget, private Ui::QgsFieldConditionalWidget
{
Q_OBJECT
public:
explicit QgsFieldConditionalFormatWidget( QWidget *parent = 0 );
void viewRules();
void setLayer( QgsVectorLayer* theLayer );
void editStyle( int index, QgsConditionalStyle style );
void reset();
signals:
void rulesUpdates();
public slots:
private:
QgsVectorLayer* mLayer;
int mEditIndex;
bool mEditing;
QStandardItemModel* mModel;
QgsSymbolV2* mSymbol;
private slots:
void setExpression();
void updateIcon();
void defaultPressed( QAbstractButton*button );
bool isCustomSet();
void ruleClicked( QModelIndex index );
void reloadStyles();
void cancelRule();
void deleteRule();
void saveRule();
void addNewRule();
void fieldChanged( QString fieldName );
};
#endif // QGSFIELDCONDITIONALFORMATWIDGET_H

View File

@ -14,16 +14,7 @@
<string>Attribute Table</string> <string>Attribute Table</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin"> <property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing"> <property name="spacing">
@ -484,6 +475,26 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QToolButton" name="mSetStyles">
<property name="text">
<string>Cond</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/rendererCategorizedSymbol.png</normaloff>:/images/themes/default/rendererCategorizedSymbol.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRepeat">
<bool>false</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="QToolButton" name="mHelpButton"> <widget class="QToolButton" name="mHelpButton">
<property name="sizePolicy"> <property name="sizePolicy">
@ -555,16 +566,7 @@
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum> <enum>QLayout::SetDefaultConstraint</enum>
</property> </property>
<property name="leftMargin"> <property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0"> <item row="0" column="0">
@ -673,7 +675,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QgsFieldExpressionWidget" name="mUpdateExpressionText" native="true"> <widget class="QgsFieldExpressionWidget" name="mUpdateExpressionText">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -769,7 +771,7 @@
<customwidget> <customwidget>
<class>QgsFieldExpressionWidget</class> <class>QgsFieldExpressionWidget</class>
<extends>QWidget</extends> <extends>QWidget</extends>
<header location="global">qgsfieldexpressionwidget.h</header> <header>qgsfieldexpressionwidget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget> <customwidget>

View File

@ -15,39 +15,34 @@
</property> </property>
<widget class="QWidget" name="mPageTableView"> <widget class="QWidget" name="mPageTableView">
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin"> <property name="margin">
<number>0</number> <number>0</number>
</property> </property>
<property name="topMargin"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
<property name="rightMargin"> <item row="0" column="1">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QgsAttributeTableView" name="mTableView"> <widget class="QgsAttributeTableView" name="mTableView">
<property name="alternatingRowColors"> <property name="alternatingRowColors">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2">
<widget class="QgsFieldConditionalFormatWidget" name="mConditionalFormatWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="mPageAttributeEditor"> <widget class="QWidget" name="mPageAttributeEditor">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin"> <property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0"> <item row="0" column="0">
@ -57,16 +52,7 @@
</property> </property>
<widget class="QWidget" name="listViewWdg" native="true"> <widget class="QWidget" name="listViewWdg" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin"> <property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
@ -120,16 +106,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin"> <property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0"> <item row="0" column="0">
@ -142,8 +119,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>229</width> <width>98</width>
<height>503</height> <height>28</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_4"/> <layout class="QGridLayout" name="gridLayout_4"/>
@ -182,6 +159,12 @@
<extends>QListView</extends> <extends>QListView</extends>
<header>attributetable/qgsfeaturelistview.h</header> <header>attributetable/qgsfeaturelistview.h</header>
</customwidget> </customwidget>
<customwidget>
<class>QgsFieldConditionalFormatWidget</class>
<extends>QWidget</extends>
<header>attributetable/qgsfieldconditionalformatwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../images/images.qrc"/> <include location="../../images/images.qrc"/>

View File

@ -0,0 +1,698 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsFieldConditionalWidget</class>
<widget class="QWidget" name="QgsFieldConditionalWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>380</width>
<height>336</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Condtional Format Rules</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="pages">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
</property>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="mNewButton">
<property name="text">
<string>New Rule</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/symbologyAdd.png</normaloff>:/images/themes/default/symbologyAdd.png</iconset>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Field</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListView" name="listView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="iconSize">
<size>
<width>64</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsFieldComboBox" name="mFieldCombo"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Condition</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="mRuleEdit"/>
</item>
<item>
<widget class="QToolButton" name="btnBuildExpression">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconExpression.svg</normaloff>:/images/themes/default/mIconExpression.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="mDefault1">
<property name="styleSheet">
<string notr="true">background-color: rgb(208, 255, 187);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="backColor" stdset="0">
<color>
<red>154</red>
<green>216</green>
<blue>113</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="mDefault2">
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 167, 151);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="backColor" stdset="0">
<color>
<red>255</red>
<green>130</green>
<blue>130</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="mDefault3">
<property name="styleSheet">
<string notr="true">background-color: rgb(240, 204, 146);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="backColor" stdset="0">
<color>
<red>241</red>
<green>186</green>
<blue>118</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButton_7">
<property name="styleSheet">
<string notr="true">color: rgb(170, 64, 75);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="fontColor" stdset="0">
<color>
<red>188</red>
<green>54</green>
<blue>49</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_8">
<property name="styleSheet">
<string notr="true">color: rgb(209, 166, 57);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="fontColor" stdset="0">
<color>
<red>207</red>
<green>141</green>
<blue>61</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButton_3">
<property name="styleSheet">
<string notr="true">color: rgb(98, 136, 78);</string>
</property>
<property name="text">
<string>abc - 123</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="fontColor" stdset="0">
<color>
<red>80</red>
<green>157</green>
<blue>52</blue>
</color>
</property>
<attribute name="buttonGroup">
<string notr="true">mDefaultButtons</string>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QGroupBox" name="horizontalGroupBox_2">
<property name="title">
<string>Custom</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Background</string>
</property>
</widget>
</item>
<item>
<widget class="QgsColorButtonV2" name="btnBackgroundColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item>
<widget class="QgsColorButtonV2" name="btnTextColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="checkIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Icon</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnChangeIcon">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QToolButton" name="mFontBoldBtn">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
</font>
</property>
<property name="toolTip">
<string>Bold text
(data defined only, overrides Style)</string>
</property>
<property name="text">
<string>B</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mFontButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="mFontItalicBtn">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Italic text
(data defined only, overrides Style)</string>
</property>
<property name="text">
<string>I</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mFontButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="mFontUnderlineBtn">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<underline>true</underline>
</font>
</property>
<property name="toolTip">
<string>Underlined text</string>
</property>
<property name="text">
<string>U</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mFontButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="mFontStrikethroughBtn">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<strikeout>true</strikeout>
</font>
</property>
<property name="toolTip">
<string>Strikeout text</string>
</property>
<property name="text">
<string>S</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mFontButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QFontComboBox" name="mFontFamilyCmbBx">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="9" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="mSaveRule">
<property name="text">
<string>Done</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mCancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="mDeleteButton">
<property name="text">
<string>Delete</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionDeleteSelected.svg</normaloff>:/images/themes/default/mActionDeleteSelected.svg</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsFieldComboBox</class>
<extends>QComboBox</extends>
<header>qgsfieldcombobox.h</header>
</customwidget>
<customwidget>
<class>QgsColorButtonV2</class>
<extends>QToolButton</extends>
<header>qgscolorbuttonv2.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../images/images.qrc"/>
</resources>
<connections>
<connection>
<sender>checkIcon</sender>
<signal>toggled(bool)</signal>
<receiver>btnChangeIcon</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>69</x>
<y>235</y>
</hint>
<hint type="destinationlabel">
<x>132</x>
<y>229</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="mFontButtons">
<property name="exclusive">
<bool>false</bool>
</property>
</buttongroup>
<buttongroup name="mDefaultButtons"/>
</buttongroups>
</ui>

View File

@ -22,6 +22,7 @@ ADD_PYTHON_TEST(PyQgsCoordinateTransform test_qgscoordinatetransform.py)
ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py) ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py)
ADD_PYTHON_TEST(PyQgsRelation test_qgsrelation.py) ADD_PYTHON_TEST(PyQgsRelation test_qgsrelation.py)
ADD_PYTHON_TEST(PyQgsSpatialIndex test_qgsspatialindex.py) ADD_PYTHON_TEST(PyQgsSpatialIndex test_qgsspatialindex.py)
ADD_PYTHON_TEST(PyQgsConditionalStyle test_qgsconditionalstyle.py)
ADD_PYTHON_TEST(PyQgsComposerHtml test_qgscomposerhtml.py) ADD_PYTHON_TEST(PyQgsComposerHtml test_qgscomposerhtml.py)
ADD_PYTHON_TEST(PyQgsComposition test_qgscomposition.py) ADD_PYTHON_TEST(PyQgsComposition test_qgscomposition.py)
ADD_PYTHON_TEST(PyQgsAnalysis test_qgsanalysis.py) ADD_PYTHON_TEST(PyQgsAnalysis test_qgsanalysis.py)

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for the memory layer provider.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nathan.Woodrow'
__date__ = '2015-08-11'
__copyright__ = 'Copyright 2015, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.core import QgsConditionalStyle, QgsFeature, QgsFields, QgsField
from utilities import (unitTestDataPath,
getQgisTestApp,
unittest,
TestCase,
compareWkt
)
from PyQt4.QtCore import QVariant
#
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
TEST_DATA_DIR = unitTestDataPath()
class TestPyQgsConditionalStyle(TestCase):
def test_MatchesReturnsTrueForSimpleMatch(self):
style = QgsConditionalStyle("@value > 10")
assert style.matches(20)
def test_MatchesReturnsTrueForComplexMatch(self):
style = QgsConditionalStyle("@value > 10 and @value = 20")
assert style.matches(20)
def test_MatchesTrueForFields(self):
feature = QgsFeature()
fields = QgsFields()
fields.append(QgsField("testfield", QVariant.Int))
feature.setFields(fields, True)
feature["testfield"] = 20
style = QgsConditionalStyle('"testfield" = @value')
assert style.matches(20, feature)
if __name__ == '__main__':
unittest.main()