QGIS/src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp
2016-06-13 18:07:39 +10:00

395 lines
12 KiB
C++

/***************************************************************************
qgsrendererv2propertiesdialog.cpp
---------------------
begin : December 2009
copyright : (C) 2009 by Martin Dobias
email : wonder dot sk at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgsrendererv2propertiesdialog.h"
#include "qgsrendererv2.h"
#include "qgsrendererv2registry.h"
#include "qgsrendererv2widget.h"
#include "qgssinglesymbolrendererv2widget.h"
#include "qgscategorizedsymbolrendererv2widget.h"
#include "qgsgraduatedsymbolrendererv2widget.h"
#include "qgsrulebasedrendererv2widget.h"
#include "qgspointdisplacementrendererwidget.h"
#include "qgsinvertedpolygonrendererwidget.h"
#include "qgsheatmaprendererwidget.h"
#include "qgs25drendererwidget.h"
#include "qgsnullsymbolrendererwidget.h"
#include "qgspanelwidget.h"
#include "qgsorderbydialog.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsvectorlayer.h"
#include <QKeyEvent>
#include <QMessageBox>
static bool _initRenderer( const QString& name, QgsRendererV2WidgetFunc f, const QString& iconName = QString() )
{
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance();
QgsRendererV2AbstractMetadata* am = reg->rendererMetadata( name );
if ( !am )
return false;
QgsRendererV2Metadata* m = dynamic_cast<QgsRendererV2Metadata*>( am );
if ( !m )
return false;
m->setWidgetFunction( f );
if ( !iconName.isEmpty() )
{
QString iconPath = QgsApplication::defaultThemePath() + iconName;
QPixmap pix;
if ( pix.load( iconPath ) )
m->setIcon( pix );
}
QgsDebugMsg( "Set for " + name );
return true;
}
static void _initRendererWidgetFunctions()
{
static bool initialized = false;
if ( initialized )
return;
_initRenderer( "singleSymbol", QgsSingleSymbolRendererV2Widget::create, "rendererSingleSymbol.svg" );
_initRenderer( "categorizedSymbol", QgsCategorizedSymbolRendererV2Widget::create, "rendererCategorizedSymbol.svg" );
_initRenderer( "graduatedSymbol", QgsGraduatedSymbolRendererV2Widget::create, "rendererGraduatedSymbol.svg" );
_initRenderer( "RuleRenderer", QgsRuleBasedRendererV2Widget::create, "rendererRuleBasedSymbol.svg" );
_initRenderer( "pointDisplacement", QgsPointDisplacementRendererWidget::create, "rendererPointDisplacementSymbol.svg" );
_initRenderer( "invertedPolygonRenderer", QgsInvertedPolygonRendererWidget::create, "rendererInvertedSymbol.svg" );
_initRenderer( "heatmapRenderer", QgsHeatmapRendererWidget::create, "rendererHeatmapSymbol.svg" );
_initRenderer( "25dRenderer", Qgs25DRendererWidget::create, "renderer25dSymbol.svg" );
_initRenderer( "nullSymbol", QgsNullSymbolRendererWidget::create, "rendererNullSymbol.svg" );
initialized = true;
}
QgsRendererV2PropertiesDialog::QgsRendererV2PropertiesDialog( QgsVectorLayer* layer, QgsStyleV2* style, bool embedded, QWidget* parent )
: QDialog( parent )
, mLayer( layer )
, mStyle( style )
, mActiveWidget( nullptr )
, mPaintEffect( nullptr )
, mMapCanvas( nullptr )
{
setupUi( this );
mLayerRenderingGroupBox->setSettingGroup( "layerRenderingGroupBox" );
// can be embedded in vector layer properties
if ( embedded )
{
buttonBox->hide();
layout()->setContentsMargins( 0, 0, 0, 0 );
}
this->setDockMode( embedded );
// initialize registry's widget functions
_initRendererWidgetFunctions();
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance();
QStringList renderers = reg->renderersList( mLayer );
Q_FOREACH ( const QString& name, renderers )
{
QgsRendererV2AbstractMetadata* m = reg->rendererMetadata( name );
cboRenderers->addItem( m->icon(), m->visibleName(), name );
}
cboRenderers->setCurrentIndex( -1 ); // set no current renderer
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( onOK() ) );
// connect layer transparency slider and spin box
connect( mLayerTransparencySlider, SIGNAL( valueChanged( int ) ), mLayerTransparencySpnBx, SLOT( setValue( int ) ) );
connect( mLayerTransparencySpnBx, SIGNAL( valueChanged( int ) ), mLayerTransparencySlider, SLOT( setValue( int ) ) );
connect( cboRenderers, SIGNAL( currentIndexChanged( int ) ), this, SLOT( rendererChanged() ) );
connect( checkboxEnableOrderBy, SIGNAL( toggled( bool ) ), btnOrderBy, SLOT( setEnabled( bool ) ) );
connect( checkboxEnableOrderBy, SIGNAL( toggled( bool ) ), lineEditOrderBy, SLOT( setEnabled( bool ) ) );
connect( btnOrderBy, SIGNAL( clicked( bool ) ), this, SLOT( showOrderByDialog() ) );
QList<QgsPanelWidget*> panels;
panels << mEffectWidget;
mainStack->connectPanels( panels );
syncToLayer();
QList<QWidget*> widgets;
widgets << mLayerTransparencySpnBx
<< cboRenderers
<< checkboxEnableOrderBy
<< lineEditOrderBy
<< mBlendModeComboBox
<< mFeatureBlendComboBox
<< mEffectWidget;
connectValueChanged( widgets, SIGNAL( widgetChanged() ) );
}
void QgsRendererV2PropertiesDialog::connectValueChanged( QList<QWidget *> widgets, const char *slot )
{
Q_FOREACH ( QWidget* widget, widgets )
{
if ( QgsDataDefinedButton* w = qobject_cast<QgsDataDefinedButton*>( widget ) )
{
connect( w, SIGNAL( dataDefinedActivated( bool ) ), this, slot );
connect( w, SIGNAL( dataDefinedChanged( QString ) ), this, slot );
}
else if ( QgsFieldExpressionWidget* w = qobject_cast<QgsFieldExpressionWidget*>( widget ) )
{
connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
}
else if ( QComboBox* w = qobject_cast<QComboBox*>( widget ) )
{
connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
}
else if ( QSpinBox* w = qobject_cast<QSpinBox*>( widget ) )
{
connect( w, SIGNAL( valueChanged( int ) ), this, slot );
}
else if ( QDoubleSpinBox* w = qobject_cast<QDoubleSpinBox*>( widget ) )
{
connect( w , SIGNAL( valueChanged( double ) ), this, slot );
}
else if ( QgsColorButtonV2* w = qobject_cast<QgsColorButtonV2*>( widget ) )
{
connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
}
else if ( QCheckBox* w = qobject_cast<QCheckBox*>( widget ) )
{
connect( w, SIGNAL( toggled( bool ) ), this, slot );
}
else if ( QLineEdit* w = qobject_cast<QLineEdit*>( widget ) )
{
connect( w, SIGNAL( textEdited( QString ) ), this, slot );
connect( w, SIGNAL( textChanged( QString ) ), this, slot );
}
else if ( QgsEffectStackCompactWidget* w = qobject_cast<QgsEffectStackCompactWidget*>( widget ) )
{
connect( w, SIGNAL( changed() ), this, slot );
}
}
}
QgsRendererV2PropertiesDialog::~QgsRendererV2PropertiesDialog()
{
delete mPaintEffect;
}
void QgsRendererV2PropertiesDialog::setMapCanvas( QgsMapCanvas* canvas )
{
mMapCanvas = canvas;
if ( mActiveWidget )
mActiveWidget->setMapCanvas( mMapCanvas );
}
void QgsRendererV2PropertiesDialog::setDockMode( bool dockMode )
{
mDockMode = dockMode;
mEffectWidget->setDockMode( dockMode );
}
void QgsRendererV2PropertiesDialog::rendererChanged()
{
QgsDebugMsg( "RENDERER CHANGED" );
if ( cboRenderers->currentIndex() == -1 )
{
QgsDebugMsg( "No current item -- this should never happen!" );
return;
}
QString rendererName = cboRenderers->itemData( cboRenderers->currentIndex() ).toString();
//Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
QgsFeatureRendererV2* oldRenderer;
if ( mActiveWidget && mActiveWidget->renderer() )
{
oldRenderer = mActiveWidget->renderer()->clone();
}
else
{
oldRenderer = mLayer->rendererV2()->clone();
}
// get rid of old active widget (if any)
if ( mActiveWidget )
{
stackedWidget->removeWidget( mActiveWidget );
delete mActiveWidget;
mActiveWidget = nullptr;
}
QgsRendererV2Widget* w = nullptr;
QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererName );
if ( m )
w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
delete oldRenderer;
if ( w )
{
// instantiate the widget and set as active
mActiveWidget = w;
stackedWidget->addWidget( mActiveWidget );
stackedWidget->setCurrentWidget( mActiveWidget );
if ( mActiveWidget->renderer() )
{
if ( mMapCanvas )
mActiveWidget->setMapCanvas( mMapCanvas );
changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
connect( mActiveWidget, SIGNAL( layerVariablesChanged() ), this, SIGNAL( layerVariablesChanged() ) );
}
connect( mActiveWidget, SIGNAL( widgetChanged() ), this, SIGNAL( widgetChanged() ) );
mainStack->connectPanel( mActiveWidget );
w->setDockMode( mDockMode );
}
else
{
// set default "no edit widget available" page
stackedWidget->setCurrentWidget( pageNoWidget );
}
}
void QgsRendererV2PropertiesDialog::apply()
{
if ( !mActiveWidget || !mLayer )
{
return;
}
mActiveWidget->applyChanges();
QgsFeatureRendererV2* renderer = mActiveWidget->renderer();
if ( renderer )
{
renderer->setPaintEffect( mPaintEffect->clone() );
// set the order by
renderer->setOrderBy( mOrderBy );
renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
mLayer->setRendererV2( renderer->clone() );
}
// set the blend modes for the layer
mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
// set transparency for the layer
mLayer->setLayerTransparency( mLayerTransparencySlider->value() );
}
void QgsRendererV2PropertiesDialog::onOK()
{
apply();
accept();
}
void QgsRendererV2PropertiesDialog::syncToLayer()
{
// Blend mode
mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
// Feature blend mode
mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
// Layer transparency
mLayerTransparencySlider->setValue( mLayer->layerTransparency() );
mLayerTransparencySpnBx->setValue( mLayer->layerTransparency() );
//paint effect widget
if ( mLayer->rendererV2() )
{
if ( mLayer->rendererV2()->paintEffect() )
{
mPaintEffect = mLayer->rendererV2()->paintEffect()->clone();
mEffectWidget->setPaintEffect( mPaintEffect );
}
mOrderBy = mLayer->rendererV2()->orderBy();
}
lineEditOrderBy->setText( mOrderBy.dump() );
// setup slot rendererChanged()
//setup order by
if ( mLayer->rendererV2()->orderByEnabled() )
{
checkboxEnableOrderBy->setChecked( true );
}
else
{
btnOrderBy->setEnabled( false );
checkboxEnableOrderBy->setChecked( false );
lineEditOrderBy->setEnabled( false );
}
lineEditOrderBy->setReadOnly( true );
// set current renderer from layer
QString rendererName = mLayer->rendererV2()->type();
int rendererIdx = cboRenderers->findData( rendererName );
cboRenderers->setCurrentIndex( rendererIdx );
// no renderer found... this mustn't happen
Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
}
void QgsRendererV2PropertiesDialog::showOrderByDialog()
{
QgsOrderByDialog dlg( mLayer, this );
dlg.setOrderBy( mOrderBy );
if ( dlg.exec() )
{
mOrderBy = dlg.orderBy();
lineEditOrderBy->setText( mOrderBy.dump() );
}
}
void QgsRendererV2PropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy& orderBy, bool orderByEnabled )
{
mOrderBy = orderBy;
lineEditOrderBy->setText( mOrderBy.dump() );
checkboxEnableOrderBy->setChecked( orderByEnabled );
}
void QgsRendererV2PropertiesDialog::updateUIState( bool hidden )
{
mLayerRenderingGroupBox->setHidden( hidden );
cboRenderers->setHidden( hidden );
}
void QgsRendererV2PropertiesDialog::keyPressEvent( QKeyEvent * e )
{
// Ignore the ESC key to avoid close the dialog without the properties window
if ( !isWindow() && e->key() == Qt::Key_Escape )
{
e->ignore();
}
else
{
QDialog::keyPressEvent( e );
}
}