mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-04 00:04:03 -04:00
1920 lines
73 KiB
C++
1920 lines
73 KiB
C++
/***************************************************************************
|
|
qgsdlgvectorlayerproperties.cpp
|
|
Unified property dialog for vector layers
|
|
-------------------
|
|
begin : 2004-01-28
|
|
copyright : (C) 2004 by Gary E.Sherman
|
|
email : sherman at mrcc.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 <memory>
|
|
#include <limits>
|
|
|
|
#include "qgsactionmanager.h"
|
|
#include "qgsjoindialog.h"
|
|
#include "qgsvectorlayerselectionproperties.h"
|
|
#include "qgswmsdimensiondialog.h"
|
|
#include "qgsapplication.h"
|
|
#include "qgsattributeactiondialog.h"
|
|
#include "qgsdatumtransformdialog.h"
|
|
#include "qgsdiagramwidget.h"
|
|
#include "qgssourcefieldsproperties.h"
|
|
#include "qgsattributesformproperties.h"
|
|
#include "qgslabelingwidget.h"
|
|
#include "qgsmapcanvas.h"
|
|
#include "qgsmaplayerstyleguiutils.h"
|
|
#include "qgsmetadatawidget.h"
|
|
#include "qgsproject.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgsvectorlayerjoininfo.h"
|
|
#include "qgsvectorlayerproperties.h"
|
|
#include "moc_qgsvectorlayerproperties.cpp"
|
|
#include "qgsvectordataprovider.h"
|
|
#include "qgssubsetstringeditorinterface.h"
|
|
#include "qgsdatasourceuri.h"
|
|
#include "qgsrenderer.h"
|
|
#include "qgsexpressioncontext.h"
|
|
#include "qgssettings.h"
|
|
#include "qgsrendererpropertiesdialog.h"
|
|
#include "qgsstyle.h"
|
|
#include "qgsauxiliarystorage.h"
|
|
#include "qgsmaplayersavestyledialog.h"
|
|
#include "qgsmaplayerserverproperties.h"
|
|
#include "qgsnewauxiliarylayerdialog.h"
|
|
#include "qgsnewauxiliaryfielddialog.h"
|
|
#include "qgslabelinggui.h"
|
|
#include "qgsmessagebar.h"
|
|
#include "qgssymbolwidgetcontext.h"
|
|
#include "qgsexpressioncontextutils.h"
|
|
#include "qgsmaskingwidget.h"
|
|
#include "qgsvectorlayertemporalpropertieswidget.h"
|
|
#include "qgsprovidersourcewidget.h"
|
|
#include "qgsproviderregistry.h"
|
|
#include "qgsmaplayerstylemanager.h"
|
|
#include "qgslayertreemodel.h"
|
|
#include "qgsmaptip.h"
|
|
#include "qgsgui.h"
|
|
#include "qgsnative.h"
|
|
#include "qgssubsetstringeditorproviderregistry.h"
|
|
#include "qgsprovidersourcewidgetproviderregistry.h"
|
|
#include "qgsfileutils.h"
|
|
#include "qgswebview.h"
|
|
#include "qgswebframe.h"
|
|
#include "qgsexpressionfinder.h"
|
|
#if WITH_QTWEBKIT
|
|
#include <QWebElement>
|
|
#endif
|
|
|
|
#include <QDesktopServices>
|
|
#include <QMessageBox>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QFileDialog>
|
|
#include <QFileInfo>
|
|
#include <QFontDialog>
|
|
#include <QComboBox>
|
|
#include <QCheckBox>
|
|
#include <QHeaderView>
|
|
#include <QColorDialog>
|
|
#include <QMenu>
|
|
#include <QUrl>
|
|
#include <QRegularExpressionValidator>
|
|
|
|
|
|
QgsVectorLayerProperties::QgsVectorLayerProperties(
|
|
QgsMapCanvas *canvas,
|
|
QgsMessageBar *messageBar,
|
|
QgsVectorLayer *lyr,
|
|
QWidget *parent,
|
|
Qt::WindowFlags fl
|
|
)
|
|
: QgsLayerPropertiesDialog( lyr, canvas, QStringLiteral( "VectorLayerProperties" ), parent, fl )
|
|
, mMessageBar( messageBar )
|
|
, mLayer( lyr )
|
|
, mOriginalSubsetSQL( lyr->subsetString() )
|
|
{
|
|
setupUi( this );
|
|
connect( pbnQueryBuilder, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnQueryBuilder_clicked );
|
|
connect( pbnIndex, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnIndex_clicked );
|
|
connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsVectorLayerProperties::mCrsSelector_crsChanged );
|
|
connect( pbnUpdateExtents, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnUpdateExtents_clicked );
|
|
connect( mButtonAddJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddJoin_clicked );
|
|
connect( mButtonEditJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditJoin_clicked );
|
|
connect( mJoinTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked );
|
|
connect( mButtonRemoveJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveJoin_clicked );
|
|
connect( mButtonAddWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddWmsDimension_clicked );
|
|
connect( mButtonEditWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditWmsDimension_clicked );
|
|
connect( mWmsDimensionsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked );
|
|
connect( mButtonRemoveWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked );
|
|
connect( mSimplifyDrawingGroupBox, &QGroupBox::toggled, this, &QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled );
|
|
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerProperties::showHelp );
|
|
|
|
mProjectDirtyBlocker = std::make_unique<QgsProjectDirtyBlocker>( QgsProject::instance() );
|
|
|
|
// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
|
|
// switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
|
|
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
|
|
initOptionsBase( false );
|
|
|
|
mBtnStyle = new QPushButton( tr( "Style" ), this );
|
|
QMenu *menuStyle = new QMenu( this );
|
|
mActionLoadStyle = new QAction( tr( "Load Style…" ), this );
|
|
connect( mActionLoadStyle, &QAction::triggered, this, &QgsVectorLayerProperties::loadStyle );
|
|
|
|
mActionSaveStyle = new QAction( tr( "Save Current Style…" ), this );
|
|
connect( mActionSaveStyle, &QAction::triggered, this, &QgsVectorLayerProperties::saveStyleAs );
|
|
|
|
mActionSaveMultipleStyles = new QAction( tr( "Save Multiple Styles…" ), this );
|
|
connect( mActionSaveMultipleStyles, &QAction::triggered, this, &QgsVectorLayerProperties::saveMultipleStylesAs );
|
|
|
|
mSourceGroupBox->hide();
|
|
|
|
mBtnStyle->setMenu( menuStyle );
|
|
connect( menuStyle, &QMenu::aboutToShow, this, &QgsVectorLayerProperties::aboutToShowStyleMenu );
|
|
buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
|
|
|
|
connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsVectorLayerProperties::syncToLayer );
|
|
|
|
connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsVectorLayerProperties::apply );
|
|
connect( this, &QDialog::accepted, this, &QgsVectorLayerProperties::apply );
|
|
connect( this, &QDialog::rejected, this, &QgsVectorLayerProperties::rollback );
|
|
|
|
if ( mCanvas )
|
|
{
|
|
mContext = mCanvas->createExpressionContext();
|
|
}
|
|
else
|
|
{
|
|
mContext << QgsExpressionContextUtils::globalScope()
|
|
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
|
|
<< QgsExpressionContextUtils::atlasScope( nullptr )
|
|
<< QgsExpressionContextUtils::mapSettingsScope( QgsMapSettings() );
|
|
}
|
|
mContext << QgsExpressionContextUtils::layerScope( mLayer );
|
|
|
|
mMapTipFieldComboBox->setLayer( lyr );
|
|
mDisplayExpressionWidget->setLayer( lyr );
|
|
mDisplayExpressionWidget->registerExpressionContextGenerator( this );
|
|
initMapTipPreview();
|
|
|
|
connect( mMapTipInsertFieldButton, &QAbstractButton::clicked, this, &QgsVectorLayerProperties::insertField );
|
|
connect( mMapTipInsertExpressionButton, &QAbstractButton::clicked, this, &QgsVectorLayerProperties::insertOrEditExpression );
|
|
|
|
if ( !mLayer )
|
|
return;
|
|
|
|
connect( mEnableMapTips, &QAbstractButton::toggled, mHtmlMapTipGroupBox, &QWidget::setEnabled );
|
|
mEnableMapTips->setChecked( mLayer->mapTipsEnabled() );
|
|
|
|
QVBoxLayout *layout = nullptr;
|
|
|
|
if ( mLayer->isSpatial() )
|
|
{
|
|
// Create the Labeling dialog tab
|
|
layout = new QVBoxLayout( labelingFrame );
|
|
layout->setContentsMargins( 0, 0, 0, 0 );
|
|
labelingDialog = new QgsLabelingWidget( mLayer, mCanvas, labelingFrame );
|
|
labelingDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
connect( labelingDialog, &QgsLabelingWidget::auxiliaryFieldCreated, this, [this] { updateAuxiliaryStoragePage(); } );
|
|
layout->addWidget( labelingDialog );
|
|
labelingFrame->setLayout( layout );
|
|
|
|
// Create the masking dialog tab
|
|
layout = new QVBoxLayout( mMaskingFrame );
|
|
layout->setContentsMargins( 0, 0, 0, 0 );
|
|
mMaskingWidget = new QgsMaskingWidget( mMaskingFrame );
|
|
mMaskingWidget->setLayer( mLayer );
|
|
mMaskingWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
layout->addWidget( mMaskingWidget );
|
|
mMaskingFrame->setLayout( layout );
|
|
}
|
|
else
|
|
{
|
|
labelingDialog = nullptr;
|
|
mOptsPage_Labels->setEnabled( false ); // disable labeling item
|
|
mOptsPage_Masks->setEnabled( false ); // disable masking item
|
|
mGeomGroupBox->setEnabled( false );
|
|
mGeomGroupBox->setVisible( false );
|
|
mCrsGroupBox->setEnabled( false );
|
|
mCrsGroupBox->setVisible( false );
|
|
}
|
|
|
|
// Create the Actions dialog tab
|
|
QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
|
|
actionLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
mActionDialog = new QgsAttributeActionDialog( *mLayer->actions(), actionOptionsFrame );
|
|
mActionDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
actionLayout->addWidget( mActionDialog );
|
|
|
|
mSourceFieldsPropertiesDialog = new QgsSourceFieldsProperties( mLayer, mSourceFieldsFrame );
|
|
mSourceFieldsPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
mSourceFieldsFrame->setLayout( new QVBoxLayout( mSourceFieldsFrame ) );
|
|
mSourceFieldsFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
mSourceFieldsFrame->layout()->addWidget( mSourceFieldsPropertiesDialog );
|
|
|
|
connect( mSourceFieldsPropertiesDialog, &QgsSourceFieldsProperties::toggleEditing, this, static_cast<void ( QgsVectorLayerProperties::* )()>( &QgsVectorLayerProperties::toggleEditing ) );
|
|
|
|
mAttributesFormPropertiesDialog = new QgsAttributesFormProperties( mLayer, mAttributesFormFrame );
|
|
mAttributesFormPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
mAttributesFormFrame->setLayout( new QVBoxLayout( mAttributesFormFrame ) );
|
|
mAttributesFormFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
mAttributesFormFrame->layout()->addWidget( mAttributesFormPropertiesDialog );
|
|
|
|
// Metadata tab, before the syncToLayer
|
|
QVBoxLayout *metadataLayout = new QVBoxLayout( metadataFrame );
|
|
metadataLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
mMetadataWidget = new QgsMetadataWidget( this, mLayer );
|
|
mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
mMetadataWidget->setMapCanvas( mCanvas );
|
|
metadataLayout->addWidget( mMetadataWidget );
|
|
metadataFrame->setLayout( metadataLayout );
|
|
|
|
QVBoxLayout *temporalLayout = new QVBoxLayout( temporalFrame );
|
|
temporalLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
mTemporalWidget = new QgsVectorLayerTemporalPropertiesWidget( this, mLayer );
|
|
temporalLayout->addWidget( mTemporalWidget );
|
|
|
|
setMetadataWidget( mMetadataWidget, mOptsPage_Metadata );
|
|
|
|
mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
|
|
QMenu *menuMetadata = new QMenu( this );
|
|
mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata from File…" ), this, &QgsVectorLayerProperties::loadMetadataFromFile );
|
|
mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata to File…" ), this, &QgsVectorLayerProperties::saveMetadataToFile );
|
|
menuMetadata->addSeparator();
|
|
menuMetadata->addAction( tr( "Save to Default Location" ), this, &QgsVectorLayerProperties::saveMetadataAsDefault );
|
|
menuMetadata->addAction( tr( "Restore from Default Location" ), this, &QgsVectorLayerProperties::loadDefaultMetadata );
|
|
mBtnMetadata->setMenu( menuMetadata );
|
|
buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
|
|
|
|
mSelectionColorButton->setAllowOpacity( true );
|
|
mSelectionColorButton->setColorDialogTitle( tr( "Override Selection Color" ) );
|
|
if ( mCanvas )
|
|
{
|
|
mSelectionColorButton->setColor( mCanvas->selectionColor() );
|
|
mSelectionColorButton->setDefaultColor( mCanvas->selectionColor() );
|
|
}
|
|
connect( mRadioOverrideSelectionColor, &QRadioButton::toggled, mSelectionColorButton, &QWidget::setEnabled );
|
|
mSelectionColorButton->setEnabled( false );
|
|
connect( mRadioOverrideSelectionSymbol, &QRadioButton::toggled, mSelectionSymbolButton, &QWidget::setEnabled );
|
|
switch ( mLayer->geometryType() )
|
|
{
|
|
case Qgis::GeometryType::Point:
|
|
mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Marker );
|
|
break;
|
|
case Qgis::GeometryType::Line:
|
|
mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Line );
|
|
break;
|
|
case Qgis::GeometryType::Polygon:
|
|
mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
|
|
break;
|
|
|
|
case Qgis::GeometryType::Unknown:
|
|
case Qgis::GeometryType::Null:
|
|
break;
|
|
}
|
|
mSelectionSymbolButton->setEnabled( false );
|
|
mRadioDefaultSelectionColor->setChecked( true );
|
|
|
|
// Diagram tab, before the syncToLayer
|
|
QVBoxLayout *diagLayout = new QVBoxLayout( mDiagramFrame );
|
|
diagLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
diagramPropertiesDialog = new QgsDiagramWidget( mLayer, mCanvas, mDiagramFrame );
|
|
diagramPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
connect( diagramPropertiesDialog, &QgsDiagramWidget::auxiliaryFieldCreated, this, [this] { updateAuxiliaryStoragePage(); } );
|
|
diagLayout->addWidget( diagramPropertiesDialog );
|
|
mDiagramFrame->setLayout( diagLayout );
|
|
|
|
syncToLayer();
|
|
|
|
if ( mLayer->dataProvider() )
|
|
{
|
|
//enable spatial index button group if supported by provider, or if one already exists
|
|
Qgis::VectorProviderCapabilities capabilities = mLayer->dataProvider()->capabilities();
|
|
if ( !( capabilities & Qgis::VectorProviderCapability::CreateSpatialIndex ) )
|
|
{
|
|
pbnIndex->setEnabled( false );
|
|
}
|
|
if ( mLayer->dataProvider()->hasSpatialIndex() == Qgis::SpatialIndexPresence::Present )
|
|
{
|
|
pbnIndex->setEnabled( false );
|
|
pbnIndex->setText( tr( "Spatial Index Exists" ) );
|
|
}
|
|
|
|
if ( capabilities & Qgis::VectorProviderCapability::SelectEncoding )
|
|
{
|
|
cboProviderEncoding->addItems( QgsVectorDataProvider::availableEncodings() );
|
|
QString enc = mLayer->dataProvider()->encoding();
|
|
int encindex = cboProviderEncoding->findText( enc );
|
|
if ( encindex < 0 )
|
|
{
|
|
cboProviderEncoding->insertItem( 0, enc );
|
|
encindex = 0;
|
|
}
|
|
cboProviderEncoding->setCurrentIndex( encindex );
|
|
}
|
|
else if ( mLayer->providerType() == QLatin1String( "ogr" ) )
|
|
{
|
|
// if OGR_L_TestCapability(OLCStringsAsUTF8) returns true, OGR provider encoding can be set to only UTF-8
|
|
// so make encoding box grayed out
|
|
cboProviderEncoding->addItem( mLayer->dataProvider()->encoding() );
|
|
cboProviderEncoding->setEnabled( false );
|
|
}
|
|
else
|
|
{
|
|
// other providers do not use mEncoding, so hide the group completely
|
|
mDataSourceEncodingFrame->hide();
|
|
}
|
|
}
|
|
|
|
mCrsSelector->setCrs( mLayer->crs() );
|
|
|
|
//insert existing join info
|
|
const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
|
|
for ( const QgsVectorLayerJoinInfo &join : joins )
|
|
{
|
|
addJoinToTreeWidget( join );
|
|
}
|
|
|
|
mOldJoins = mLayer->vectorJoins();
|
|
|
|
// Legend tab
|
|
mLegendWidget->setMapCanvas( mCanvas );
|
|
mLegendWidget->setLayer( mLayer );
|
|
mLegendConfigEmbeddedWidget->setLayer( mLayer );
|
|
|
|
//insert existing dimension info
|
|
QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
|
|
const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &wmsDims = serverProperties->wmsDimensions();
|
|
for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : wmsDims )
|
|
{
|
|
addWmsDimensionInfoToTreeWidget( dim );
|
|
}
|
|
|
|
QString myStyle = QgsApplication::reportStyleSheet();
|
|
myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
|
|
teMetadataViewer->clear();
|
|
teMetadataViewer->document()->setDefaultStyleSheet( myStyle );
|
|
teMetadataViewer->setOpenLinks( false );
|
|
connect( teMetadataViewer, &QTextBrowser::anchorClicked, this, &QgsVectorLayerProperties::openUrl );
|
|
|
|
QgsSettings settings;
|
|
// if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
|
|
// this will be read by restoreOptionsBaseUi()
|
|
if ( !settings.contains( QStringLiteral( "/Windows/VectorLayerProperties/tab" ) ) )
|
|
{
|
|
settings.setValue( QStringLiteral( "Windows/VectorLayerProperties/tab" ), mOptStackedWidget->indexOf( mOptsPage_Style ) );
|
|
}
|
|
|
|
QList<QgsMapLayer *> dependencySources;
|
|
const QSet<QgsMapLayerDependency> constDependencies = mLayer->dependencies();
|
|
for ( const QgsMapLayerDependency &dep : constDependencies )
|
|
{
|
|
QgsMapLayer *layer = QgsProject::instance()->mapLayer( dep.layerId() );
|
|
if ( layer )
|
|
dependencySources << layer;
|
|
}
|
|
|
|
mLayersDependenciesTreeModel = new QgsLayerTreeFilterProxyModel( this );
|
|
mLayersDependenciesTreeModel->setLayerTreeModel( new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), mLayersDependenciesTreeModel ) );
|
|
mLayersDependenciesTreeModel->setCheckedLayers( dependencySources );
|
|
connect( QgsProject::instance(), &QObject::destroyed, this, [this] { mLayersDependenciesTreeView->setModel( nullptr ); } );
|
|
mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel );
|
|
|
|
mRefreshSettingsWidget->setLayer( mLayer );
|
|
mMapLayerServerPropertiesWidget->setHasWfsTitle( true );
|
|
mMapLayerServerPropertiesWidget->setServerProperties( mLayer->serverProperties() );
|
|
|
|
// auxiliary layer
|
|
QMenu *menu = new QMenu( this );
|
|
|
|
mAuxiliaryLayerActionNew = new QAction( tr( "Create" ), this );
|
|
menu->addAction( mAuxiliaryLayerActionNew );
|
|
connect( mAuxiliaryLayerActionNew, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerNew );
|
|
|
|
mAuxiliaryLayerActionClear = new QAction( tr( "Clear" ), this );
|
|
menu->addAction( mAuxiliaryLayerActionClear );
|
|
connect( mAuxiliaryLayerActionClear, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerClear );
|
|
|
|
mAuxiliaryLayerActionDelete = new QAction( tr( "Delete" ), this );
|
|
menu->addAction( mAuxiliaryLayerActionDelete );
|
|
connect( mAuxiliaryLayerActionDelete, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerDelete );
|
|
|
|
mAuxiliaryLayerActionExport = new QAction( tr( "Export" ), this );
|
|
menu->addAction( mAuxiliaryLayerActionExport );
|
|
connect( mAuxiliaryLayerActionExport, &QAction::triggered, this, [this] { emit exportAuxiliaryLayer( mLayer->auxiliaryLayer() ); } );
|
|
|
|
mAuxiliaryStorageActions->setMenu( menu );
|
|
|
|
connect( mAuxiliaryStorageFieldsDeleteBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerDeleteField );
|
|
connect( mAuxiliaryStorageFieldsAddBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerAddField );
|
|
|
|
updateAuxiliaryStoragePage();
|
|
|
|
mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#information-properties" ) );
|
|
mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#source-properties" ) );
|
|
mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#symbology-properties" ) );
|
|
mOptsPage_Labels->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#labels-properties" ) );
|
|
mOptsPage_Masks->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#masks-properties" ) );
|
|
mOptsPage_Diagrams->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#diagrams-properties" ) );
|
|
mOptsPage_SourceFields->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#fields-properties" ) );
|
|
mOptsPage_AttributesForm->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#attributes-form-properties" ) );
|
|
mOptsPage_Joins->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#joins-properties" ) );
|
|
mOptsPage_AuxiliaryStorage->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#auxiliary-storage-properties" ) );
|
|
mOptsPage_Actions->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#actions-properties" ) );
|
|
mOptsPage_Display->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#display-properties" ) );
|
|
mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#rendering-properties" ) );
|
|
mOptsPage_Temporal->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#temporal-properties" ) );
|
|
mOptsPage_Variables->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#variables-properties" ) );
|
|
mOptsPage_Metadata->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#metadata-properties" ) );
|
|
mOptsPage_DataDependencies->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#dependencies-properties" ) );
|
|
mOptsPage_Legend->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#legend-properties" ) );
|
|
mOptsPage_Server->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#qgis-server-properties" ) );
|
|
|
|
|
|
optionsStackedWidget_CurrentChanged( mOptStackedWidget->currentIndex() );
|
|
|
|
initialize();
|
|
}
|
|
|
|
void QgsVectorLayerProperties::toggleEditing()
|
|
{
|
|
if ( !mLayer )
|
|
return;
|
|
|
|
emit toggleEditing( mLayer );
|
|
|
|
setPbnQueryBuilderEnabled();
|
|
}
|
|
|
|
void QgsVectorLayerProperties::insertField()
|
|
{
|
|
// Convert the selected field to an expression and
|
|
// insert it into the action at the cursor position
|
|
if ( mMapTipFieldComboBox->currentField().isEmpty() )
|
|
return;
|
|
QString expression = QStringLiteral( "[%\"" );
|
|
expression += mMapTipFieldComboBox->currentField();
|
|
expression += QLatin1String( "\"%]" );
|
|
|
|
mMapTipWidget->insertText( expression );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::insertOrEditExpression()
|
|
{
|
|
// Get the linear indexes if the start and end of the selection
|
|
int selectionStart = mMapTipWidget->selectionStart();
|
|
int selectionEnd = mMapTipWidget->selectionEnd();
|
|
QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mMapTipWidget );
|
|
|
|
QgsExpressionContext context = createExpressionContext();
|
|
QgsExpressionBuilderDialog exprDlg( mLayer, expression, this, QStringLiteral( "generic" ), context );
|
|
|
|
exprDlg.setWindowTitle( tr( "Insert Expression" ) );
|
|
if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
|
|
mMapTipWidget->insertText( "[%" + exprDlg.expressionText().trimmed() + "%]" );
|
|
else // Restore the selection
|
|
mMapTipWidget->setLinearSelection( selectionStart, selectionEnd );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::syncToLayer()
|
|
{
|
|
if ( !mSourceWidget )
|
|
{
|
|
mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mLayer );
|
|
if ( mSourceWidget )
|
|
{
|
|
QHBoxLayout *layout = new QHBoxLayout();
|
|
layout->addWidget( mSourceWidget );
|
|
mSourceGroupBox->setLayout( layout );
|
|
if ( !mSourceWidget->groupTitle().isEmpty() )
|
|
mSourceGroupBox->setTitle( mSourceWidget->groupTitle() );
|
|
|
|
mSourceGroupBox->show();
|
|
|
|
connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [this]( bool isValid ) {
|
|
buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
|
|
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
|
|
} );
|
|
}
|
|
}
|
|
|
|
if ( mSourceWidget )
|
|
{
|
|
mSourceWidget->setMapCanvas( mCanvas );
|
|
mSourceWidget->setSourceUri( mLayer->source() );
|
|
}
|
|
|
|
// populate the general information
|
|
mLayerOrigNameLineEdit->setText( mLayer->name() );
|
|
mBackupCrs = mLayer->crs();
|
|
|
|
//see if we are dealing with a pg layer here
|
|
mSubsetGroupBox->setEnabled( true );
|
|
txtSubsetSQL->setText( mLayer->subsetString() );
|
|
// if the user is allowed to type an adhoc query, the app will crash if the query
|
|
// is bad. For this reason, the sql box is disabled and the query must be built
|
|
// using the query builder, either by typing it in by hand or using the buttons, etc
|
|
// on the builder. If the ability to enter a query directly into the box is required,
|
|
// a mechanism to check it must be implemented.
|
|
txtSubsetSQL->setReadOnly( true );
|
|
txtSubsetSQL->setCaretWidth( 0 );
|
|
txtSubsetSQL->setCaretLineVisible( false );
|
|
setPbnQueryBuilderEnabled();
|
|
if ( mLayer->dataProvider() && !mLayer->dataProvider()->supportsSubsetString() )
|
|
{
|
|
// hide subset box entirely if not supported by data provider
|
|
mSubsetGroupBox->hide();
|
|
}
|
|
|
|
mDisplayExpressionWidget->setField( mLayer->displayExpression() );
|
|
mEnableMapTips->setChecked( mLayer->mapTipsEnabled() );
|
|
mMapTipWidget->setText( mLayer->mapTipTemplate() );
|
|
|
|
// set up the scale based layer visibility stuff....
|
|
mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
|
|
mScaleVisibilityGroupBox->setChecked( mLayer->hasScaleBasedVisibility() );
|
|
mScaleRangeWidget->setMapCanvas( mCanvas );
|
|
|
|
mUseReferenceScaleGroupBox->setChecked( mLayer->renderer() && mLayer->renderer()->referenceScale() > 0 );
|
|
mReferenceScaleWidget->setShowCurrentScaleButton( true );
|
|
mReferenceScaleWidget->setMapCanvas( mCanvas );
|
|
if ( mUseReferenceScaleGroupBox->isChecked() )
|
|
mReferenceScaleWidget->setScale( mLayer->renderer()->referenceScale() );
|
|
else if ( mCanvas )
|
|
mReferenceScaleWidget->setScale( mCanvas->scale() );
|
|
|
|
// get simplify drawing configuration
|
|
const QgsVectorSimplifyMethod &simplifyMethod = mLayer->simplifyMethod();
|
|
mSimplifyDrawingGroupBox->setChecked( simplifyMethod.simplifyHints() != Qgis::VectorRenderingSimplificationFlags( Qgis::VectorRenderingSimplificationFlag::NoSimplification ) );
|
|
mSimplifyDrawingSpinBox->setValue( simplifyMethod.threshold() );
|
|
mSimplifyDrawingSpinBox->setClearValue( 1.0 );
|
|
|
|
QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast<QgsVectorLayerSelectionProperties *>( mLayer->selectionProperties() );
|
|
if ( selectionProperties->selectionColor().isValid() )
|
|
{
|
|
mSelectionColorButton->setColor( selectionProperties->selectionColor() );
|
|
}
|
|
if ( QgsSymbol *symbol = selectionProperties->selectionSymbol() )
|
|
{
|
|
mSelectionSymbolButton->setSymbol( symbol->clone() );
|
|
}
|
|
switch ( selectionProperties->selectionRenderingMode() )
|
|
{
|
|
case Qgis::SelectionRenderingMode::Default:
|
|
mRadioDefaultSelectionColor->setChecked( true );
|
|
break;
|
|
|
|
case Qgis::SelectionRenderingMode::CustomColor:
|
|
{
|
|
if ( selectionProperties->selectionColor().isValid() )
|
|
{
|
|
mRadioOverrideSelectionColor->setChecked( true );
|
|
}
|
|
else
|
|
{
|
|
mRadioDefaultSelectionColor->setChecked( true );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Qgis::SelectionRenderingMode::CustomSymbol:
|
|
if ( selectionProperties->selectionSymbol() )
|
|
{
|
|
mRadioOverrideSelectionSymbol->setChecked( true );
|
|
}
|
|
else
|
|
{
|
|
mRadioDefaultSelectionColor->setChecked( true );
|
|
}
|
|
break;
|
|
}
|
|
|
|
QString remark = QStringLiteral( " (%1)" ).arg( tr( "Not supported" ) );
|
|
const QgsVectorDataProvider *provider = mLayer->dataProvider();
|
|
if ( !( provider && ( provider->capabilities() & Qgis::VectorProviderCapability::SimplifyGeometries ) ) )
|
|
{
|
|
mSimplifyDrawingAtProvider->setChecked( false );
|
|
mSimplifyDrawingAtProvider->setEnabled( false );
|
|
if ( !mSimplifyDrawingAtProvider->text().endsWith( remark ) )
|
|
mSimplifyDrawingAtProvider->setText( mSimplifyDrawingAtProvider->text().append( remark ) );
|
|
}
|
|
else
|
|
{
|
|
mSimplifyDrawingAtProvider->setChecked( !simplifyMethod.forceLocalOptimization() );
|
|
mSimplifyDrawingAtProvider->setEnabled( mSimplifyDrawingGroupBox->isChecked() );
|
|
if ( mSimplifyDrawingAtProvider->text().endsWith( remark ) )
|
|
{
|
|
QString newText = mSimplifyDrawingAtProvider->text();
|
|
newText.chop( remark.size() );
|
|
mSimplifyDrawingAtProvider->setText( newText );
|
|
}
|
|
}
|
|
|
|
// disable simplification for point layers, now it is not implemented
|
|
if ( mLayer->geometryType() == Qgis::GeometryType::Point )
|
|
{
|
|
mSimplifyDrawingGroupBox->setChecked( false );
|
|
mSimplifyDrawingGroupBox->setEnabled( false );
|
|
}
|
|
|
|
// Default local simplification algorithm
|
|
mSimplifyAlgorithmComboBox->addItem( tr( "Distance" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::Distance ) );
|
|
mSimplifyAlgorithmComboBox->addItem( tr( "SnapToGrid" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::SnapToGrid ) );
|
|
mSimplifyAlgorithmComboBox->addItem( tr( "Visvalingam" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::Visvalingam ) );
|
|
mSimplifyAlgorithmComboBox->setCurrentIndex( mSimplifyAlgorithmComboBox->findData( QVariant::fromValue( simplifyMethod.simplifyAlgorithm() ) ) );
|
|
|
|
QStringList myScalesList = Qgis::defaultProjectScales().split( ',' );
|
|
myScalesList.append( QStringLiteral( "1:1" ) );
|
|
mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
|
|
mSimplifyMaximumScaleComboBox->setScale( simplifyMethod.maximumScale() );
|
|
|
|
mForceRasterCheckBox->setChecked( mLayer->renderer() && mLayer->renderer()->forceRasterRender() );
|
|
|
|
mRefreshSettingsWidget->syncToLayer();
|
|
mMapLayerServerPropertiesWidget->sync();
|
|
|
|
mRefreshLayerNotificationCheckBox->setChecked( mLayer->isRefreshOnNotifyEnabled() );
|
|
mNotificationMessageCheckBox->setChecked( !mLayer->refreshOnNotifyMessage().isEmpty() );
|
|
mNotifyMessageValueLineEdit->setText( mLayer->refreshOnNotifyMessage() );
|
|
|
|
|
|
// load appropriate symbology page (V1 or V2)
|
|
updateSymbologyPage();
|
|
|
|
mActionDialog->init( *mLayer->actions(), mLayer->attributeTableConfig() );
|
|
|
|
if ( labelingDialog )
|
|
labelingDialog->adaptToLayer();
|
|
|
|
mSourceFieldsPropertiesDialog->init();
|
|
mAttributesFormPropertiesDialog->init();
|
|
|
|
// set initial state for variable editor
|
|
updateVariableEditor();
|
|
|
|
if ( diagramPropertiesDialog )
|
|
diagramPropertiesDialog->syncToOwnLayer();
|
|
|
|
// sync all plugin dialogs
|
|
for ( QgsMapLayerConfigWidget *page : std::as_const( mConfigWidgets ) )
|
|
{
|
|
page->syncToLayer( mLayer );
|
|
}
|
|
|
|
mMetadataWidget->setMetadata( &mLayer->metadata() );
|
|
|
|
mTemporalWidget->syncToLayer();
|
|
|
|
mLegendWidget->setLayer( mLayer );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::apply()
|
|
{
|
|
if ( labelingDialog )
|
|
{
|
|
labelingDialog->writeSettingsToLayer();
|
|
}
|
|
mBackupCrs = mLayer->crs();
|
|
// apply legend settings
|
|
mLegendWidget->applyToLayer();
|
|
mLegendConfigEmbeddedWidget->applyToLayer();
|
|
|
|
// save metadata
|
|
mMetadataWidget->acceptMetadata();
|
|
mMetadataFilled = false;
|
|
|
|
// save masking settings
|
|
if ( mMaskingWidget )
|
|
mMaskingWidget->apply();
|
|
|
|
// set up the scale based layer visibility stuff....
|
|
mLayer->setScaleBasedVisibility( mScaleVisibilityGroupBox->isChecked() );
|
|
mLayer->setMaximumScale( mScaleRangeWidget->maximumScale() );
|
|
mLayer->setMinimumScale( mScaleRangeWidget->minimumScale() );
|
|
|
|
// provider-specific options
|
|
if ( mLayer->dataProvider() )
|
|
{
|
|
if ( mLayer->dataProvider()->capabilities() & Qgis::VectorProviderCapability::SelectEncoding )
|
|
{
|
|
mLayer->setProviderEncoding( cboProviderEncoding->currentText() );
|
|
}
|
|
}
|
|
|
|
mLayer->setDisplayExpression( mDisplayExpressionWidget->asExpression() );
|
|
mLayer->setMapTipsEnabled( mEnableMapTips->isChecked() );
|
|
mLayer->setMapTipTemplate( mMapTipWidget->text() );
|
|
|
|
mLayer->actions()->clearActions();
|
|
const auto constActions = mActionDialog->actions();
|
|
for ( const QgsAction &action : constActions )
|
|
{
|
|
mLayer->actions()->addAction( action );
|
|
}
|
|
QgsAttributeTableConfig attributeTableConfig = mLayer->attributeTableConfig();
|
|
attributeTableConfig.update( mLayer->fields() );
|
|
attributeTableConfig.setActionWidgetStyle( mActionDialog->attributeTableWidgetStyle() );
|
|
QVector<QgsAttributeTableConfig::ColumnConfig> columns = attributeTableConfig.columns();
|
|
|
|
for ( int i = 0; i < columns.size(); ++i )
|
|
{
|
|
if ( columns.at( i ).type == QgsAttributeTableConfig::Action )
|
|
{
|
|
columns[i].hidden = !mActionDialog->showWidgetInAttributeTable();
|
|
}
|
|
}
|
|
|
|
attributeTableConfig.setColumns( columns );
|
|
|
|
mLayer->setAttributeTableConfig( attributeTableConfig );
|
|
|
|
mLayer->setName( mLayerOrigNameLineEdit->text() );
|
|
|
|
mAttributesFormPropertiesDialog->apply();
|
|
mSourceFieldsPropertiesDialog->apply();
|
|
|
|
// Update temporal properties
|
|
mTemporalWidget->saveTemporalProperties();
|
|
|
|
if ( mLayer->renderer() )
|
|
{
|
|
QgsRendererPropertiesDialog *dlg = static_cast<QgsRendererPropertiesDialog *>( widgetStackRenderers->currentWidget() );
|
|
dlg->apply();
|
|
}
|
|
|
|
//apply diagram settings
|
|
diagramPropertiesDialog->apply();
|
|
|
|
// apply all plugin dialogs
|
|
for ( QgsMapLayerConfigWidget *page : std::as_const( mConfigWidgets ) )
|
|
{
|
|
page->apply();
|
|
}
|
|
|
|
if ( mMapLayerServerPropertiesWidget->save() )
|
|
mMetadataFilled = false;
|
|
|
|
//layer simplify drawing configuration
|
|
Qgis::VectorRenderingSimplificationFlags simplifyHints = Qgis::VectorRenderingSimplificationFlag::NoSimplification;
|
|
if ( mSimplifyDrawingGroupBox->isChecked() )
|
|
{
|
|
simplifyHints |= Qgis::VectorRenderingSimplificationFlag::GeometrySimplification;
|
|
if ( mSimplifyDrawingSpinBox->value() > 1 )
|
|
simplifyHints |= Qgis::VectorRenderingSimplificationFlag::AntialiasingSimplification;
|
|
}
|
|
QgsVectorSimplifyMethod simplifyMethod = mLayer->simplifyMethod();
|
|
simplifyMethod.setSimplifyHints( simplifyHints );
|
|
simplifyMethod.setSimplifyAlgorithm( mSimplifyAlgorithmComboBox->currentData().value<Qgis::VectorSimplificationAlgorithm>() );
|
|
simplifyMethod.setThreshold( mSimplifyDrawingSpinBox->value() );
|
|
simplifyMethod.setForceLocalOptimization( !mSimplifyDrawingAtProvider->isChecked() );
|
|
simplifyMethod.setMaximumScale( mSimplifyMaximumScaleComboBox->scale() );
|
|
mLayer->setSimplifyMethod( simplifyMethod );
|
|
|
|
if ( mLayer->renderer() )
|
|
{
|
|
mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() );
|
|
mLayer->renderer()->setReferenceScale( mUseReferenceScaleGroupBox->isChecked() ? mReferenceScaleWidget->scale() : -1 );
|
|
}
|
|
|
|
QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast<QgsVectorLayerSelectionProperties *>( mLayer->selectionProperties() );
|
|
if ( mSelectionColorButton->color() != mSelectionColorButton->defaultColor() )
|
|
selectionProperties->setSelectionColor( mSelectionColorButton->color() );
|
|
else
|
|
selectionProperties->setSelectionColor( QColor() );
|
|
if ( QgsSymbol *symbol = mSelectionSymbolButton->symbol() )
|
|
selectionProperties->setSelectionSymbol( symbol->clone() );
|
|
|
|
if ( mRadioOverrideSelectionSymbol->isChecked() )
|
|
{
|
|
selectionProperties->setSelectionRenderingMode( Qgis::SelectionRenderingMode::CustomSymbol );
|
|
}
|
|
else if ( mRadioOverrideSelectionColor->isChecked() )
|
|
{
|
|
selectionProperties->setSelectionRenderingMode( Qgis::SelectionRenderingMode::CustomColor );
|
|
}
|
|
else
|
|
{
|
|
selectionProperties->setSelectionRenderingMode( Qgis::SelectionRenderingMode::Default );
|
|
}
|
|
|
|
mRefreshSettingsWidget->saveToLayer();
|
|
|
|
mLayer->setRefreshOnNotifyEnabled( mRefreshLayerNotificationCheckBox->isChecked() );
|
|
mLayer->setRefreshOnNofifyMessage( mNotificationMessageCheckBox->isChecked() ? mNotifyMessageValueLineEdit->text() : QString() );
|
|
|
|
mOldJoins = mLayer->vectorJoins();
|
|
|
|
//save variables
|
|
QgsExpressionContextUtils::setLayerVariables( mLayer, mVariableEditor->variablesInActiveScope() );
|
|
updateVariableEditor();
|
|
|
|
// save dependencies
|
|
QSet<QgsMapLayerDependency> deps;
|
|
const auto checkedLayers = mLayersDependenciesTreeModel->checkedLayers();
|
|
for ( const QgsMapLayer *layer : checkedLayers )
|
|
deps << QgsMapLayerDependency( layer->id() );
|
|
if ( !mLayer->setDependencies( deps ) )
|
|
{
|
|
QMessageBox::warning( nullptr, tr( "Save Dependency" ), tr( "This configuration introduces a cycle in data dependencies and will be ignored." ) );
|
|
}
|
|
|
|
// Why is this here? Well, we if we're making changes to the layer's source then potentially
|
|
// we are changing the geometry type of the layer, or even going from spatial <-> non spatial types.
|
|
// So we need to ensure that anything from the dialog which sets things like renderer properties
|
|
// happens BEFORE we change the source, otherwise we might end up with a renderer which is not
|
|
// compatible with the new geometry type of the layer. (And likewise for other properties like
|
|
// fields!)
|
|
bool dialogNeedsResync = false;
|
|
if ( mSourceWidget )
|
|
{
|
|
const QString newSource = mSourceWidget->sourceUri();
|
|
if ( newSource != mLayer->source() )
|
|
{
|
|
mLayer->setDataSource( newSource, mLayer->name(), mLayer->providerType(), QgsDataProvider::ProviderOptions(), Qgis::DataProviderReadFlags() );
|
|
|
|
// resync dialog to layer's new state -- this allows any changed layer properties
|
|
// (such as a forced creation of a new renderer compatible with the new layer, new field configuration, etc)
|
|
// to show in the dialog correctly
|
|
dialogNeedsResync = true;
|
|
}
|
|
}
|
|
// now apply the subset string AFTER setting the layer's source. It's messy, but the subset string
|
|
// can form part of the layer's source, but it WON'T be present in the URI returned by the source widget!
|
|
// If we don't apply the subset string AFTER changing the source, then the subset string will be lost.
|
|
mSubsetGroupBox->setEnabled( true );
|
|
if ( txtSubsetSQL->text() != mLayer->subsetString() )
|
|
{
|
|
// set the subset sql for the layer
|
|
mLayer->setSubsetString( txtSubsetSQL->text() );
|
|
mMetadataFilled = false;
|
|
// need to resync the dialog, the subset string may have changed the layer's geometry type!
|
|
dialogNeedsResync = true;
|
|
}
|
|
mOriginalSubsetSQL = mLayer->subsetString();
|
|
|
|
if ( dialogNeedsResync )
|
|
syncToLayer();
|
|
|
|
mLayer->triggerRepaint();
|
|
// notify the project we've made a change
|
|
mProjectDirtyBlocker.reset();
|
|
QgsProject::instance()->setDirty( true );
|
|
mProjectDirtyBlocker = std::make_unique<QgsProjectDirtyBlocker>( QgsProject::instance() );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::rollback()
|
|
{
|
|
if ( mOldJoins != mLayer->vectorJoins() )
|
|
{
|
|
// need to undo changes in vector layer joins - they are applied directly to the layer (not in apply())
|
|
// so other parts of the properties dialog can use the fields from the joined layers
|
|
|
|
const auto constVectorJoins = mLayer->vectorJoins();
|
|
for ( const QgsVectorLayerJoinInfo &info : constVectorJoins )
|
|
mLayer->removeJoin( info.joinLayerId() );
|
|
|
|
for ( const QgsVectorLayerJoinInfo &info : std::as_const( mOldJoins ) )
|
|
mLayer->addJoin( info );
|
|
}
|
|
|
|
if ( mOriginalSubsetSQL != mLayer->subsetString() )
|
|
{
|
|
// need to undo changes in subset string - they are applied directly to the layer (not in apply())
|
|
// by QgsQueryBuilder::accept()
|
|
|
|
mLayer->setSubsetString( mOriginalSubsetSQL );
|
|
}
|
|
|
|
// Store it because QgsLayerPropertiesDialog::rollback() calls syncToLayer() which
|
|
// resets the backupCrs
|
|
const QgsCoordinateReferenceSystem backupCrs { mBackupCrs };
|
|
|
|
QgsLayerPropertiesDialog::rollback();
|
|
|
|
if ( backupCrs != mLayer->crs() )
|
|
mLayer->setCrs( backupCrs );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::pbnQueryBuilder_clicked()
|
|
{
|
|
// launch the query builder
|
|
QgsSubsetStringEditorInterface *dialog = QgsGui::subsetStringEditorProviderRegistry()->createDialog( mLayer, this );
|
|
|
|
// Set the sql in the query builder to the same in the prop dialog
|
|
// (in case the user has already changed it)
|
|
dialog->setSubsetString( txtSubsetSQL->text() );
|
|
// Open the query builder
|
|
if ( dialog->exec() )
|
|
{
|
|
// if the sql is changed, update it in the prop subset text box
|
|
txtSubsetSQL->setText( dialog->subsetString() );
|
|
//TODO If the sql is changed in the prop dialog, the layer extent should be recalculated
|
|
|
|
// The datasource for the layer needs to be updated with the new sql since this gets
|
|
// saved to the project file. This should happen at the map layer level...
|
|
}
|
|
// delete the query builder object
|
|
delete dialog;
|
|
}
|
|
|
|
void QgsVectorLayerProperties::pbnIndex_clicked()
|
|
{
|
|
QgsVectorDataProvider *pr = mLayer->dataProvider();
|
|
if ( pr )
|
|
{
|
|
setCursor( Qt::WaitCursor );
|
|
bool errval = pr->createSpatialIndex();
|
|
setCursor( Qt::ArrowCursor );
|
|
if ( errval )
|
|
{
|
|
pbnIndex->setEnabled( false );
|
|
pbnIndex->setText( tr( "Spatial Index Exists" ) );
|
|
QMessageBox::information( this, tr( "Spatial Index" ), tr( "Creation of spatial index successful" ) );
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning( this, tr( "Spatial Index" ), tr( "Creation of spatial index failed" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
QString QgsVectorLayerProperties::htmlMetadata()
|
|
{
|
|
return mLayer->htmlMetadata();
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
|
|
{
|
|
QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation for the vector layer" ) );
|
|
mLayer->setCrs( crs );
|
|
mMetadataFilled = false;
|
|
mMetadataWidget->crsChanged();
|
|
}
|
|
|
|
void QgsVectorLayerProperties::saveMultipleStylesAs()
|
|
{
|
|
QgsMapLayerSaveStyleDialog dlg( mLayer );
|
|
dlg.setSaveOnlyCurrentStyle( false );
|
|
QgsSettings settings;
|
|
|
|
if ( dlg.exec() )
|
|
{
|
|
apply();
|
|
|
|
// Store the original style, that we can restore at the end
|
|
const QString originalStyle { mLayer->styleManager()->currentStyle() };
|
|
const QListWidget *stylesWidget { dlg.stylesWidget() };
|
|
|
|
// Collect selected (checked) styles for export/save
|
|
QStringList stylesSelected;
|
|
for ( int i = 0; i < stylesWidget->count(); i++ )
|
|
{
|
|
if ( stylesWidget->item( i )->checkState() == Qt::CheckState::Checked )
|
|
{
|
|
stylesSelected.push_back( stylesWidget->item( i )->text() );
|
|
}
|
|
}
|
|
|
|
if ( !stylesSelected.isEmpty() )
|
|
{
|
|
int styleIndex = 0;
|
|
for ( const QString &styleName : std::as_const( stylesSelected ) )
|
|
{
|
|
bool defaultLoadedFlag = false;
|
|
|
|
StyleType type = dlg.currentStyleType();
|
|
mLayer->styleManager()->setCurrentStyle( styleName );
|
|
switch ( type )
|
|
{
|
|
case QML:
|
|
case SLD:
|
|
{
|
|
QString message;
|
|
const QString filePath { dlg.outputFilePath() };
|
|
const QFileInfo fi { filePath };
|
|
QString safePath { QString( filePath ).replace( fi.baseName(), QStringLiteral( "%1_%2" ).arg( fi.baseName(), QgsFileUtils::stringToSafeFilename( styleName ) ) ) };
|
|
if ( styleIndex > 0 && stylesSelected.count() > 1 )
|
|
{
|
|
int i = 1;
|
|
while ( QFile::exists( safePath ) )
|
|
{
|
|
const QFileInfo fi { safePath };
|
|
safePath = QString( safePath ).replace( '.' + fi.completeSuffix(), QStringLiteral( "_%1.%2" ).arg( QString::number( i ), fi.completeSuffix() ) );
|
|
i++;
|
|
}
|
|
}
|
|
if ( type == QML )
|
|
message = mLayer->saveNamedStyle( safePath, defaultLoadedFlag, dlg.styleCategories() );
|
|
else
|
|
message = mLayer->saveSldStyle( safePath, defaultLoadedFlag );
|
|
|
|
//reset if the default style was loaded OK only
|
|
if ( defaultLoadedFlag )
|
|
{
|
|
syncToLayer();
|
|
}
|
|
else
|
|
{
|
|
//let the user know what went wrong
|
|
QMessageBox::information( this, tr( "Save Style" ), message );
|
|
}
|
|
|
|
break;
|
|
}
|
|
case DatasourceDatabase:
|
|
{
|
|
QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
|
|
.arg( styleName, mLayer->providerType() );
|
|
QString msgError;
|
|
|
|
QgsMapLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
|
|
|
|
// If a name is defined, we add _1 etc. else we use the style name
|
|
QString name { dbSettings.name };
|
|
if ( name.isEmpty() )
|
|
{
|
|
name = styleName;
|
|
}
|
|
else
|
|
{
|
|
name += QStringLiteral( "_%1" ).arg( styleName );
|
|
QStringList ids, names, descriptions;
|
|
mLayer->listStylesInDatabase( ids, names, descriptions, msgError );
|
|
int i = 1;
|
|
while ( names.contains( name ) )
|
|
{
|
|
name = QStringLiteral( "%1 %2" ).arg( name, QString::number( i ) );
|
|
i++;
|
|
}
|
|
}
|
|
|
|
QString errorMessage;
|
|
if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
|
|
{
|
|
if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ), QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ), QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if ( !errorMessage.isEmpty() )
|
|
{
|
|
QMessageBox::warning( this, infoWindowTitle, errorMessage );
|
|
return;
|
|
}
|
|
|
|
mLayer->saveStyleToDatabaseV2( name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError, dlg.styleCategories() );
|
|
|
|
if ( !msgError.isNull() )
|
|
{
|
|
QMessageBox::warning( this, infoWindowTitle, msgError );
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::information( this, infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ) );
|
|
}
|
|
break;
|
|
}
|
|
case UserDatabase:
|
|
break;
|
|
}
|
|
styleIndex++;
|
|
}
|
|
// Restore original style
|
|
mLayer->styleManager()->setCurrentStyle( originalStyle );
|
|
}
|
|
} // Nothing selected!
|
|
}
|
|
|
|
void QgsVectorLayerProperties::aboutToShowStyleMenu()
|
|
{
|
|
// this should be unified with QgsRasterLayerProperties::aboutToShowStyleMenu()
|
|
QMenu *m = qobject_cast<QMenu *>( sender() );
|
|
m->clear();
|
|
|
|
m->addAction( mActionLoadStyle );
|
|
m->addAction( mActionSaveStyle );
|
|
|
|
// If we have multiple styles, offer an option to save them at once
|
|
if ( mLayer->styleManager()->styles().count() > 1 )
|
|
{
|
|
mActionSaveStyle->setText( tr( "Save Current Style…" ) );
|
|
m->addAction( mActionSaveMultipleStyles );
|
|
}
|
|
else
|
|
{
|
|
mActionSaveStyle->setText( tr( "Save Style…" ) );
|
|
}
|
|
|
|
m->addSeparator();
|
|
m->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultStyle );
|
|
m->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultStyle );
|
|
|
|
// re-add style manager actions!
|
|
m->addSeparator();
|
|
QgsMapLayerStyleGuiUtils::instance()->addStyleManagerActions( m, mLayer );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mButtonAddJoin_clicked()
|
|
{
|
|
if ( !mLayer )
|
|
return;
|
|
|
|
QList<QgsMapLayer *> joinedLayers;
|
|
const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
|
|
joinedLayers.reserve( joins.size() );
|
|
for ( int i = 0; i < joins.size(); ++i )
|
|
{
|
|
joinedLayers.append( joins[i].joinLayer() );
|
|
}
|
|
|
|
QgsJoinDialog d( mLayer, joinedLayers );
|
|
if ( d.exec() == QDialog::Accepted )
|
|
{
|
|
QgsVectorLayerJoinInfo info = d.joinInfo();
|
|
//create attribute index if possible
|
|
if ( d.createAttributeIndex() )
|
|
{
|
|
QgsVectorLayer *joinLayer = info.joinLayer();
|
|
if ( joinLayer )
|
|
{
|
|
joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
|
|
}
|
|
}
|
|
mLayer->addJoin( info );
|
|
addJoinToTreeWidget( info );
|
|
setPbnQueryBuilderEnabled();
|
|
mSourceFieldsPropertiesDialog->init();
|
|
mAttributesFormPropertiesDialog->init();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mButtonEditJoin_clicked()
|
|
{
|
|
QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
|
|
mJoinTreeWidget_itemDoubleClicked( currentJoinItem, 0 );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
|
|
{
|
|
if ( !mLayer || !item )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if current item is a child item, we should use its parent to be able to edit join
|
|
QTreeWidgetItem *currentJoinItem = item;
|
|
if ( item->parent() )
|
|
{
|
|
currentJoinItem = item->parent();
|
|
}
|
|
|
|
|
|
QList<QgsMapLayer *> joinedLayers;
|
|
QString joinLayerId = currentJoinItem->data( 0, Qt::UserRole ).toString();
|
|
const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
|
|
int j = -1;
|
|
for ( int i = 0; i < joins.size(); ++i )
|
|
{
|
|
QgsVectorLayer *joinLayer = joins[i].joinLayer();
|
|
if ( !joinLayer )
|
|
continue; // invalid join (unresolved join layer)
|
|
|
|
if ( joinLayer->id() == joinLayerId )
|
|
{
|
|
j = i;
|
|
}
|
|
else
|
|
{
|
|
// remove already joined layers from possible list to be displayed in dialog
|
|
joinedLayers.append( joinLayer );
|
|
}
|
|
}
|
|
if ( j == -1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QgsJoinDialog d( mLayer, joinedLayers );
|
|
d.setWindowTitle( tr( "Edit Vector Join" ) );
|
|
d.setJoinInfo( joins[j] );
|
|
|
|
if ( d.exec() == QDialog::Accepted )
|
|
{
|
|
QgsVectorLayerJoinInfo info = d.joinInfo();
|
|
|
|
// remove old join
|
|
mLayer->removeJoin( joinLayerId );
|
|
int idx = mJoinTreeWidget->indexOfTopLevelItem( item );
|
|
mJoinTreeWidget->takeTopLevelItem( idx );
|
|
|
|
// add the new edited
|
|
|
|
//create attribute index if possible
|
|
if ( d.createAttributeIndex() )
|
|
{
|
|
QgsVectorLayer *joinLayer = info.joinLayer();
|
|
if ( joinLayer )
|
|
{
|
|
joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
|
|
}
|
|
}
|
|
mLayer->addJoin( info );
|
|
addJoinToTreeWidget( info, idx );
|
|
|
|
setPbnQueryBuilderEnabled();
|
|
mSourceFieldsPropertiesDialog->init();
|
|
mAttributesFormPropertiesDialog->init();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo &join, const int insertIndex )
|
|
{
|
|
QTreeWidgetItem *joinItem = new QTreeWidgetItem();
|
|
joinItem->setFlags( Qt::ItemIsEnabled );
|
|
|
|
QgsVectorLayer *joinLayer = join.joinLayer();
|
|
if ( !mLayer || !joinLayer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
joinItem->setText( 0, tr( "Join layer" ) );
|
|
if ( mLayer->auxiliaryLayer() && mLayer->auxiliaryLayer()->id() == join.joinLayerId() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
joinItem->setText( 1, joinLayer->name() );
|
|
|
|
QFont f = joinItem->font( 0 );
|
|
f.setBold( true );
|
|
joinItem->setFont( 0, f );
|
|
joinItem->setFont( 1, f );
|
|
|
|
joinItem->setData( 0, Qt::UserRole, join.joinLayerId() );
|
|
|
|
QTreeWidgetItem *childJoinField = new QTreeWidgetItem();
|
|
childJoinField->setText( 0, tr( "Join field" ) );
|
|
childJoinField->setText( 1, join.joinFieldName() );
|
|
childJoinField->setFlags( Qt::ItemIsEnabled );
|
|
joinItem->addChild( childJoinField );
|
|
|
|
QTreeWidgetItem *childTargetField = new QTreeWidgetItem();
|
|
childTargetField->setText( 0, tr( "Target field" ) );
|
|
childTargetField->setText( 1, join.targetFieldName() );
|
|
joinItem->addChild( childTargetField );
|
|
|
|
QTreeWidgetItem *childMemCache = new QTreeWidgetItem();
|
|
childMemCache->setText( 0, tr( "Cache join layer in virtual memory" ) );
|
|
if ( join.isUsingMemoryCache() )
|
|
childMemCache->setText( 1, QChar( 0x2714 ) );
|
|
joinItem->addChild( childMemCache );
|
|
|
|
QTreeWidgetItem *childDynForm = new QTreeWidgetItem();
|
|
childDynForm->setText( 0, tr( "Dynamic form" ) );
|
|
if ( join.isDynamicFormEnabled() )
|
|
childDynForm->setText( 1, QChar( 0x2714 ) );
|
|
joinItem->addChild( childDynForm );
|
|
|
|
QTreeWidgetItem *childEditable = new QTreeWidgetItem();
|
|
childEditable->setText( 0, tr( "Editable join layer" ) );
|
|
if ( join.isEditable() )
|
|
childEditable->setText( 1, QChar( 0x2714 ) );
|
|
joinItem->addChild( childEditable );
|
|
|
|
QTreeWidgetItem *childUpsert = new QTreeWidgetItem();
|
|
childUpsert->setText( 0, tr( "Upsert on edit" ) );
|
|
if ( join.hasUpsertOnEdit() )
|
|
childUpsert->setText( 1, QChar( 0x2714 ) );
|
|
joinItem->addChild( childUpsert );
|
|
|
|
QTreeWidgetItem *childCascade = new QTreeWidgetItem();
|
|
childCascade->setText( 0, tr( "Delete cascade" ) );
|
|
if ( join.hasCascadedDelete() )
|
|
childCascade->setText( 1, QChar( 0x2714 ) );
|
|
joinItem->addChild( childCascade );
|
|
|
|
QTreeWidgetItem *childPrefix = new QTreeWidgetItem();
|
|
childPrefix->setText( 0, tr( "Custom field name prefix" ) );
|
|
childPrefix->setText( 1, join.prefix() );
|
|
joinItem->addChild( childPrefix );
|
|
|
|
QTreeWidgetItem *childFields = new QTreeWidgetItem();
|
|
childFields->setText( 0, tr( "Joined fields" ) );
|
|
const QStringList *list = join.joinFieldNamesSubset();
|
|
if ( list )
|
|
childFields->setText( 1, QLocale().toString( list->count() ) );
|
|
else
|
|
childFields->setText( 1, tr( "all" ) );
|
|
joinItem->addChild( childFields );
|
|
|
|
if ( insertIndex >= 0 )
|
|
mJoinTreeWidget->insertTopLevelItem( insertIndex, joinItem );
|
|
else
|
|
mJoinTreeWidget->addTopLevelItem( joinItem );
|
|
|
|
mJoinTreeWidget->setCurrentItem( joinItem );
|
|
mJoinTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
|
|
}
|
|
|
|
QgsExpressionContext QgsVectorLayerProperties::createExpressionContext() const
|
|
{
|
|
return mContext;
|
|
}
|
|
|
|
void QgsVectorLayerProperties::openPanel( QgsPanelWidget *panel )
|
|
{
|
|
QDialog *dlg = new QDialog();
|
|
QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
|
|
QgsSettings settings;
|
|
dlg->restoreGeometry( settings.value( key ).toByteArray() );
|
|
dlg->setWindowTitle( panel->panelTitle() );
|
|
dlg->setLayout( new QVBoxLayout() );
|
|
dlg->layout()->addWidget( panel );
|
|
QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
|
|
connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
|
|
dlg->layout()->addWidget( buttonBox );
|
|
dlg->exec();
|
|
settings.setValue( key, dlg->saveGeometry() );
|
|
panel->acceptPanel();
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mButtonRemoveJoin_clicked()
|
|
{
|
|
QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
|
|
// if current item is a child item, we should use its parent to be able to remove join
|
|
if ( currentJoinItem && currentJoinItem->parent() )
|
|
{
|
|
currentJoinItem = currentJoinItem->parent();
|
|
}
|
|
|
|
if ( !mLayer || !currentJoinItem )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mLayer->removeJoin( currentJoinItem->data( 0, Qt::UserRole ).toString() );
|
|
mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
|
|
setPbnQueryBuilderEnabled();
|
|
mSourceFieldsPropertiesDialog->init();
|
|
mAttributesFormPropertiesDialog->init();
|
|
}
|
|
|
|
|
|
void QgsVectorLayerProperties::mButtonAddWmsDimension_clicked()
|
|
{
|
|
if ( !mLayer )
|
|
return;
|
|
|
|
// get wms dimensions name
|
|
QStringList alreadyDefinedDimensions;
|
|
QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
|
|
const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
|
|
for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : dims )
|
|
{
|
|
alreadyDefinedDimensions << dim.name;
|
|
}
|
|
|
|
QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
|
|
if ( d.exec() == QDialog::Accepted )
|
|
{
|
|
QgsMapLayerServerProperties::WmsDimensionInfo info = d.info();
|
|
// save dimension
|
|
serverProperties->addWmsDimension( info );
|
|
addWmsDimensionInfoToTreeWidget( info );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mButtonEditWmsDimension_clicked()
|
|
{
|
|
QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
|
|
mWmsDimensionsTreeWidget_itemDoubleClicked( currentWmsDimensionItem, 0 );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
|
|
{
|
|
if ( !mLayer || !item )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QString wmsDimName = item->data( 0, Qt::UserRole ).toString();
|
|
QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
|
|
const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
|
|
QStringList alreadyDefinedDimensions;
|
|
int j = -1;
|
|
for ( int i = 0; i < dims.size(); ++i )
|
|
{
|
|
QString dimName = dims[i].name;
|
|
if ( dimName == wmsDimName )
|
|
{
|
|
j = i;
|
|
}
|
|
else
|
|
{
|
|
alreadyDefinedDimensions << dimName;
|
|
}
|
|
}
|
|
if ( j == -1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
|
|
d.setWindowTitle( tr( "Edit WMS Dimension" ) );
|
|
d.setInfo( dims[j] );
|
|
|
|
if ( d.exec() == QDialog::Accepted )
|
|
{
|
|
QgsMapLayerServerProperties::WmsDimensionInfo info = d.info();
|
|
|
|
// remove old
|
|
QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
|
|
serverProperties->removeWmsDimension( wmsDimName );
|
|
int idx = mWmsDimensionsTreeWidget->indexOfTopLevelItem( item );
|
|
mWmsDimensionsTreeWidget->takeTopLevelItem( idx );
|
|
|
|
// save new
|
|
serverProperties->addWmsDimension( info );
|
|
addWmsDimensionInfoToTreeWidget( info, idx );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::addWmsDimensionInfoToTreeWidget( const QgsMapLayerServerProperties::WmsDimensionInfo &wmsDim, const int insertIndex )
|
|
{
|
|
QTreeWidgetItem *wmsDimensionItem = new QTreeWidgetItem();
|
|
wmsDimensionItem->setFlags( Qt::ItemIsEnabled );
|
|
|
|
wmsDimensionItem->setText( 0, tr( "Dimension" ) );
|
|
wmsDimensionItem->setText( 1, wmsDim.name );
|
|
|
|
QFont f = wmsDimensionItem->font( 0 );
|
|
f.setBold( true );
|
|
wmsDimensionItem->setFont( 0, f );
|
|
wmsDimensionItem->setFont( 1, f );
|
|
|
|
wmsDimensionItem->setData( 0, Qt::UserRole, wmsDim.name );
|
|
|
|
QTreeWidgetItem *childWmsDimensionField = new QTreeWidgetItem();
|
|
childWmsDimensionField->setText( 0, tr( "Field" ) );
|
|
childWmsDimensionField->setText( 1, wmsDim.fieldName );
|
|
childWmsDimensionField->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionField );
|
|
|
|
QTreeWidgetItem *childWmsDimensionEndField = new QTreeWidgetItem();
|
|
childWmsDimensionEndField->setText( 0, tr( "End field" ) );
|
|
childWmsDimensionEndField->setText( 1, wmsDim.endFieldName );
|
|
childWmsDimensionEndField->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionEndField );
|
|
|
|
QTreeWidgetItem *childWmsDimensionUnits = new QTreeWidgetItem();
|
|
childWmsDimensionUnits->setText( 0, tr( "Units" ) );
|
|
childWmsDimensionUnits->setText( 1, wmsDim.units );
|
|
childWmsDimensionUnits->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionUnits );
|
|
|
|
QTreeWidgetItem *childWmsDimensionUnitSymbol = new QTreeWidgetItem();
|
|
childWmsDimensionUnitSymbol->setText( 0, tr( "Unit symbol" ) );
|
|
childWmsDimensionUnitSymbol->setText( 1, wmsDim.unitSymbol );
|
|
childWmsDimensionUnitSymbol->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionUnitSymbol );
|
|
|
|
QTreeWidgetItem *childWmsDimensionDefaultValue = new QTreeWidgetItem();
|
|
childWmsDimensionDefaultValue->setText( 0, tr( "Default display" ) );
|
|
childWmsDimensionDefaultValue->setText( 1, QgsMapLayerServerProperties::wmsDimensionDefaultDisplayLabels().value( wmsDim.defaultDisplayType ) );
|
|
childWmsDimensionDefaultValue->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionDefaultValue );
|
|
|
|
QTreeWidgetItem *childWmsDimensionRefValue = new QTreeWidgetItem();
|
|
childWmsDimensionRefValue->setText( 0, tr( "Reference value" ) );
|
|
childWmsDimensionRefValue->setText( 1, wmsDim.referenceValue.toString() );
|
|
childWmsDimensionRefValue->setFlags( Qt::ItemIsEnabled );
|
|
wmsDimensionItem->addChild( childWmsDimensionRefValue );
|
|
|
|
if ( insertIndex >= 0 )
|
|
mWmsDimensionsTreeWidget->insertTopLevelItem( insertIndex, wmsDimensionItem );
|
|
else
|
|
mWmsDimensionsTreeWidget->addTopLevelItem( wmsDimensionItem );
|
|
|
|
mWmsDimensionsTreeWidget->setCurrentItem( wmsDimensionItem );
|
|
mWmsDimensionsTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked()
|
|
{
|
|
QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
|
|
if ( !mLayer || !currentWmsDimensionItem )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
|
|
serverProperties->removeWmsDimension( currentWmsDimensionItem->data( 0, Qt::UserRole ).toString() );
|
|
mWmsDimensionsTreeWidget->takeTopLevelItem( mWmsDimensionsTreeWidget->indexOfTopLevelItem( currentWmsDimensionItem ) );
|
|
}
|
|
|
|
|
|
void QgsVectorLayerProperties::updateSymbologyPage()
|
|
{
|
|
//find out the type of renderer in the vectorlayer, create a dialog with these settings and add it to the form
|
|
delete mRendererDialog;
|
|
mRendererDialog = nullptr;
|
|
|
|
if ( mLayer->renderer() )
|
|
{
|
|
mRendererDialog = new QgsRendererPropertiesDialog( mLayer, QgsStyle::defaultStyle(), true, this );
|
|
mRendererDialog->setDockMode( false );
|
|
QgsSymbolWidgetContext context;
|
|
context.setMapCanvas( mCanvas );
|
|
context.setMessageBar( mMessageBar );
|
|
mRendererDialog->setContext( context );
|
|
connect( mRendererDialog, &QgsRendererPropertiesDialog::showPanel, this, &QgsVectorLayerProperties::openPanel );
|
|
connect( mRendererDialog, &QgsRendererPropertiesDialog::layerVariablesChanged, this, &QgsVectorLayerProperties::updateVariableEditor );
|
|
connect( mRendererDialog, &QgsRendererPropertiesDialog::widgetChanged, this, [this] { updateAuxiliaryStoragePage(); } );
|
|
}
|
|
else
|
|
{
|
|
mOptsPage_Style->setEnabled( false ); // hide symbology item
|
|
}
|
|
|
|
if ( mRendererDialog )
|
|
{
|
|
mRendererDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
widgetStackRenderers->addWidget( mRendererDialog );
|
|
widgetStackRenderers->setCurrentWidget( mRendererDialog );
|
|
widgetStackRenderers->currentWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::setPbnQueryBuilderEnabled()
|
|
{
|
|
pbnQueryBuilder->setEnabled( mLayer && mLayer->dataProvider() && mLayer->dataProvider()->supportsSubsetString() && !mLayer->isEditable() );
|
|
|
|
if ( mLayer && mLayer->isEditable() )
|
|
{
|
|
pbnQueryBuilder->setToolTip( tr( "Stop editing mode to enable this." ) );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::pbnUpdateExtents_clicked()
|
|
{
|
|
mLayer->updateExtents( true ); // force update whatever options activated
|
|
mMetadataFilled = false;
|
|
}
|
|
|
|
void QgsVectorLayerProperties::optionsStackedWidget_CurrentChanged( int index )
|
|
{
|
|
QgsLayerPropertiesDialog::optionsStackedWidget_CurrentChanged( index );
|
|
|
|
if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) && !mMetadataFilled )
|
|
{
|
|
// set the metadata contents (which can be expensive)
|
|
teMetadataViewer->clear();
|
|
teMetadataViewer->setHtml( htmlMetadata() );
|
|
mMetadataFilled = true;
|
|
}
|
|
else if ( index == mOptStackedWidget->indexOf( mOptsPage_SourceFields ) || index == mOptStackedWidget->indexOf( mOptsPage_Joins ) )
|
|
{
|
|
// store any edited attribute form field configuration to prevent loss of edits when adding/removing fields and/or joins
|
|
mAttributesFormPropertiesDialog->store();
|
|
}
|
|
else if ( index == mOptStackedWidget->indexOf( mOptsPage_AttributesForm ) )
|
|
{
|
|
// Refresh actions in Available Widgets panel
|
|
if ( mActionDialog )
|
|
{
|
|
mAttributesFormPropertiesDialog->initAvailableWidgetsActions( mActionDialog->actions() );
|
|
}
|
|
}
|
|
|
|
resizeAlltabs( index );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled( bool checked )
|
|
{
|
|
const QgsVectorDataProvider *provider = mLayer->dataProvider();
|
|
if ( !( provider && ( provider->capabilities() & Qgis::VectorProviderCapability::SimplifyGeometries ) != 0 ) )
|
|
{
|
|
mSimplifyDrawingAtProvider->setEnabled( false );
|
|
}
|
|
else
|
|
{
|
|
mSimplifyDrawingAtProvider->setEnabled( checked );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::updateVariableEditor()
|
|
{
|
|
QgsExpressionContext context;
|
|
mVariableEditor->setContext( &context );
|
|
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
|
|
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
|
|
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
|
|
mVariableEditor->reloadContext();
|
|
mVariableEditor->setEditableScopeIndex( 2 );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::showHelp()
|
|
{
|
|
const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
|
|
|
|
if ( helpPage.isValid() )
|
|
{
|
|
QgsHelp::openHelp( helpPage.toString() );
|
|
}
|
|
else
|
|
{
|
|
QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html" ) );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::updateAuxiliaryStoragePage()
|
|
{
|
|
const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
|
|
if ( alayer )
|
|
{
|
|
// set widgets to enable state
|
|
mAuxiliaryStorageInformationGrpBox->setEnabled( true );
|
|
mAuxiliaryStorageFieldsGrpBox->setEnabled( true );
|
|
|
|
// update key
|
|
mAuxiliaryStorageKeyLineEdit->setText( alayer->joinInfo().targetFieldName() );
|
|
|
|
// update feature count
|
|
const qlonglong features = alayer->featureCount();
|
|
mAuxiliaryStorageFeaturesLineEdit->setText( QLocale().toString( features ) );
|
|
|
|
// update actions
|
|
mAuxiliaryLayerActionClear->setEnabled( true );
|
|
mAuxiliaryLayerActionDelete->setEnabled( true );
|
|
mAuxiliaryLayerActionExport->setEnabled( true );
|
|
mAuxiliaryLayerActionNew->setEnabled( false );
|
|
|
|
const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
if ( alayer )
|
|
{
|
|
const int fields = alayer->auxiliaryFields().count();
|
|
mAuxiliaryStorageFieldsLineEdit->setText( QLocale().toString( fields ) );
|
|
|
|
// add fields
|
|
mAuxiliaryStorageFieldsTree->clear();
|
|
for ( const QgsField &field : alayer->auxiliaryFields() )
|
|
{
|
|
const QgsPropertyDefinition prop = QgsAuxiliaryLayer::propertyDefinitionFromField( field );
|
|
QTreeWidgetItem *item = new QTreeWidgetItem();
|
|
|
|
item->setText( 0, prop.origin() );
|
|
item->setText( 1, prop.name() );
|
|
item->setText( 2, prop.comment() );
|
|
item->setText( 3, field.typeName() );
|
|
item->setText( 4, field.name() );
|
|
|
|
mAuxiliaryStorageFieldsTree->addTopLevelItem( item );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mAuxiliaryStorageInformationGrpBox->setEnabled( false );
|
|
mAuxiliaryStorageFieldsGrpBox->setEnabled( false );
|
|
|
|
mAuxiliaryLayerActionClear->setEnabled( false );
|
|
mAuxiliaryLayerActionDelete->setEnabled( false );
|
|
mAuxiliaryLayerActionExport->setEnabled( false );
|
|
mAuxiliaryLayerActionNew->setEnabled( true );
|
|
|
|
mAuxiliaryStorageFieldsTree->clear();
|
|
mAuxiliaryStorageKeyLineEdit->setText( QString() );
|
|
mAuxiliaryStorageFieldsLineEdit->setText( QString() );
|
|
mAuxiliaryStorageFeaturesLineEdit->setText( QString() );
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::onAuxiliaryLayerNew()
|
|
{
|
|
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
|
|
if ( alayer )
|
|
return;
|
|
|
|
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
|
|
if ( dlg.exec() == QDialog::Accepted )
|
|
{
|
|
updateAuxiliaryStoragePage();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::onAuxiliaryLayerClear()
|
|
{
|
|
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
|
|
if ( !alayer )
|
|
return;
|
|
|
|
const QString msg = tr( "Are you sure you want to clear auxiliary data for %1?" ).arg( mLayer->name() );
|
|
QMessageBox::StandardButton reply;
|
|
reply = QMessageBox::question( this, "Clear Auxiliary Data", msg, QMessageBox::Yes | QMessageBox::No );
|
|
|
|
if ( reply == QMessageBox::Yes )
|
|
{
|
|
QApplication::setOverrideCursor( Qt::WaitCursor );
|
|
alayer->clear();
|
|
QApplication::restoreOverrideCursor();
|
|
updateAuxiliaryStoragePage();
|
|
mLayer->triggerRepaint();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::onAuxiliaryLayerDelete()
|
|
{
|
|
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
if ( !alayer )
|
|
return;
|
|
|
|
const QString msg = tr( "Are you sure you want to delete auxiliary storage for %1?" ).arg( mLayer->name() );
|
|
QMessageBox::StandardButton reply;
|
|
reply = QMessageBox::question( this, "Delete Auxiliary Storage", msg, QMessageBox::Yes | QMessageBox::No );
|
|
|
|
if ( reply == QMessageBox::Yes )
|
|
{
|
|
QApplication::setOverrideCursor( Qt::WaitCursor );
|
|
QgsDataSourceUri uri( alayer->source() );
|
|
|
|
// delete each attribute to correctly update layer settings and data
|
|
// defined buttons
|
|
while ( alayer->auxiliaryFields().size() > 0 )
|
|
{
|
|
QgsField aField = alayer->auxiliaryFields()[0];
|
|
deleteAuxiliaryField( alayer->fields().indexOf( aField.name() ) );
|
|
}
|
|
|
|
mLayer->setAuxiliaryLayer(); // remove auxiliary layer
|
|
QgsAuxiliaryStorage::deleteTable( uri );
|
|
QApplication::restoreOverrideCursor();
|
|
updateAuxiliaryStoragePage();
|
|
mLayer->triggerRepaint();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
|
|
{
|
|
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
if ( !alayer )
|
|
return;
|
|
|
|
QList<QTreeWidgetItem *> items = mAuxiliaryStorageFieldsTree->selectedItems();
|
|
if ( items.count() < 1 )
|
|
return;
|
|
|
|
// get auxiliary field name and index from item
|
|
const QTreeWidgetItem *item = items[0];
|
|
QgsPropertyDefinition def;
|
|
def.setOrigin( item->text( 0 ) );
|
|
def.setName( item->text( 1 ) );
|
|
def.setComment( item->text( 2 ) );
|
|
|
|
const QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def );
|
|
|
|
const int index = mLayer->auxiliaryLayer()->fields().indexOf( fieldName );
|
|
if ( index < 0 )
|
|
return;
|
|
|
|
// should be only 1 field
|
|
const QString msg = tr( "Are you sure you want to delete auxiliary field %1 for %2?" ).arg( item->text( 1 ), item->text( 0 ) );
|
|
|
|
QMessageBox::StandardButton reply;
|
|
const QString title = QObject::tr( "Delete Auxiliary Field" );
|
|
reply = QMessageBox::question( this, title, msg, QMessageBox::Yes | QMessageBox::No );
|
|
|
|
if ( reply == QMessageBox::Yes )
|
|
{
|
|
QApplication::setOverrideCursor( Qt::WaitCursor );
|
|
deleteAuxiliaryField( index );
|
|
mLayer->triggerRepaint();
|
|
QApplication::restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::onAuxiliaryLayerAddField()
|
|
{
|
|
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
|
|
if ( !alayer )
|
|
return;
|
|
|
|
QgsNewAuxiliaryFieldDialog dlg( QgsPropertyDefinition(), mLayer, false );
|
|
if ( dlg.exec() == QDialog::Accepted )
|
|
{
|
|
updateAuxiliaryStoragePage();
|
|
}
|
|
}
|
|
|
|
void QgsVectorLayerProperties::deleteAuxiliaryField( int index )
|
|
{
|
|
if ( !mLayer->auxiliaryLayer() )
|
|
return;
|
|
|
|
int key = mLayer->auxiliaryLayer()->propertyFromIndex( index );
|
|
QgsPropertyDefinition def = mLayer->auxiliaryLayer()->propertyDefinitionFromIndex( index );
|
|
|
|
if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) )
|
|
{
|
|
mLayer->updateFields();
|
|
|
|
// immediately deactivate data defined button
|
|
if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0
|
|
&& labelingDialog
|
|
&& labelingDialog->labelingGui() )
|
|
{
|
|
labelingDialog->labelingGui()->deactivateField( static_cast<QgsPalLayerSettings::Property>( key ) );
|
|
}
|
|
|
|
updateAuxiliaryStoragePage();
|
|
mSourceFieldsPropertiesDialog->init();
|
|
}
|
|
else
|
|
{
|
|
const QString title = QObject::tr( "Delete Auxiliary Field" );
|
|
const QString errors = mLayer->auxiliaryLayer()->commitErrors().join( QLatin1String( "\n " ) );
|
|
const QString msg = QObject::tr( "Unable to remove auxiliary field (%1)" ).arg( errors );
|
|
mMessageBar->pushMessage( title, msg, Qgis::MessageLevel::Warning );
|
|
}
|
|
}
|
|
|
|
bool QgsVectorLayerProperties::eventFilter( QObject *obj, QEvent *ev )
|
|
{
|
|
// If the map tip preview container is resized, resize the map tip
|
|
if ( obj == mMapTipPreviewContainer && ev->type() == QEvent::Resize )
|
|
{
|
|
resizeMapTip();
|
|
}
|
|
return QgsOptionsDialogBase::eventFilter( obj, ev );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::initMapTipPreview()
|
|
{
|
|
// HTML editor and preview are in a splitter. By default, the editor takes 2/3 of the space
|
|
mMapTipSplitter->setSizes( { 400, 200 } );
|
|
// Event filter is used to resize the map tip when the container is resized
|
|
mMapTipPreviewContainer->installEventFilter( this );
|
|
|
|
// Note: there's quite a bit of overlap between this and the code in QgsMapTip::showMapTip
|
|
// Create the WebView
|
|
mMapTipPreview = new QgsWebView( mMapTipPreviewContainer );
|
|
|
|
#if WITH_QTWEBKIT
|
|
mMapTipPreview->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); //Handle link clicks by yourself
|
|
mMapTipPreview->setContextMenuPolicy( Qt::NoContextMenu ); //No context menu is allowed if you don't need it
|
|
connect( mMapTipPreview, &QWebView::loadFinished, this, &QgsVectorLayerProperties::resizeMapTip );
|
|
#endif
|
|
|
|
mMapTipPreview->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
|
|
mMapTipPreview->page()->settings()->setAttribute( QWebSettings::JavascriptEnabled, true );
|
|
mMapTipPreview->page()->settings()->setAttribute( QWebSettings::LocalStorageEnabled, true );
|
|
|
|
// Disable scrollbars, avoid random resizing issues
|
|
mMapTipPreview->page()->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
|
|
mMapTipPreview->page()->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
|
|
|
|
// Update the map tip preview when the expression or the map tip template changes
|
|
connect( mMapTipWidget, &QgsCodeEditorHTML::textChanged, this, &QgsVectorLayerProperties::updateMapTipPreview );
|
|
connect( mDisplayExpressionWidget, qOverload<const QString &>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsVectorLayerProperties::updateMapTipPreview );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::updateMapTipPreview()
|
|
{
|
|
mMapTipPreview->setMaximumSize( mMapTipPreviewContainer->width(), mMapTipPreviewContainer->height() );
|
|
const QString htmlContent = QgsMapTip::vectorMapTipPreviewText( mLayer, mCanvas, mMapTipWidget->text(), mDisplayExpressionWidget->asExpression() );
|
|
mMapTipPreview->setHtml( htmlContent );
|
|
}
|
|
|
|
void QgsVectorLayerProperties::resizeMapTip()
|
|
{
|
|
// Ensure the map tip is not bigger than the container
|
|
mMapTipPreview->setMaximumSize( mMapTipPreviewContainer->width(), mMapTipPreviewContainer->height() );
|
|
#if WITH_QTWEBKIT
|
|
// Get the content size
|
|
const QWebElement container = mMapTipPreview->page()->mainFrame()->findFirstElement(
|
|
QStringLiteral( "#QgsWebViewContainer" )
|
|
);
|
|
const int width = container.geometry().width();
|
|
const int height = container.geometry().height();
|
|
mMapTipPreview->resize( width, height );
|
|
|
|
// Move the map tip to the center of the container
|
|
mMapTipPreview->move( ( mMapTipPreviewContainer->width() - mMapTipPreview->width() ) / 2, ( mMapTipPreviewContainer->height() - mMapTipPreview->height() ) / 2 );
|
|
|
|
#else
|
|
mMapTipPreview->adjustSize();
|
|
#endif
|
|
}
|