QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsvectortilelayerproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectortilelayerproperties.cpp
3 --------------------------------------
4 Date : May 2020
5 Copyright : (C) 2020 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsapplication.h"
20#include "qgsgui.h"
21#include "qgshelp.h"
22#include "qgsjsonutils.h"
27#include "qgsmetadatawidget.h"
32#include "qgsvectortilelayer.h"
33#include "qgsvectortileutils.h"
34
35#include <QDesktopServices>
36#include <QFileDialog>
37#include <QMenu>
38#include <QMessageBox>
39#include <QTextStream>
40
41#include "moc_qgsvectortilelayerproperties.cpp"
42
43QgsVectorTileLayerProperties::QgsVectorTileLayerProperties( QgsVectorTileLayer *lyr, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent, Qt::WindowFlags flags )
44 : QgsLayerPropertiesDialog( lyr, canvas, QStringLiteral( "VectorTileLayerProperties" ), parent, flags )
45 , mLayer( lyr )
46{
47 setupUi( this );
48
49 mRendererWidget = new QgsVectorTileBasicRendererWidget( nullptr, canvas, messageBar, this );
50 mOptsPage_Style->layout()->addWidget( mRendererWidget );
51 mOptsPage_Style->layout()->setContentsMargins( 0, 0, 0, 0 );
52
53 mLabelingWidget = new QgsVectorTileBasicLabelingWidget( nullptr, canvas, messageBar, this );
54 mOptsPage_Labeling->layout()->addWidget( mLabelingWidget );
55 mOptsPage_Labeling->layout()->setContentsMargins( 0, 0, 0, 0 );
56
57 connect( this, &QDialog::accepted, this, &QgsVectorTileLayerProperties::apply );
58 connect( this, &QDialog::rejected, this, &QgsVectorTileLayerProperties::rollback );
59 connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsVectorTileLayerProperties::apply );
60 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorTileLayerProperties::showHelp );
61
62 connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsVectorTileLayerProperties::crsChanged );
63
64 // scale based layer visibility related widgets
65 mScaleRangeWidget->setMapCanvas( mCanvas );
66
67 // QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
68 // switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
69 // and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
70 initOptionsBase( false );
71
72 mSourceGroupBox->hide();
73
74#ifdef WITH_QTWEBKIT
75 // Setup information tab
76
77 const int horizontalDpi = logicalDpiX();
78
79 // Adjust zoom: text is ok, but HTML seems rather big at least on Linux/KDE
80 if ( horizontalDpi > 96 )
81 {
82 mMetadataViewer->setZoomFactor( mMetadataViewer->zoomFactor() * 0.9 );
83 }
84 mMetadataViewer->page()->setLinkDelegationPolicy( QWebPage::LinkDelegationPolicy::DelegateAllLinks );
85 connect( mMetadataViewer->page(), &QWebPage::linkClicked, this, &QgsVectorTileLayerProperties::openUrl );
86 mMetadataViewer->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
87 mMetadataViewer->page()->settings()->setAttribute( QWebSettings::JavascriptEnabled, true );
88
89#endif
90 mOptsPage_Information->setContentsMargins( 0, 0, 0, 0 );
91
92 QVBoxLayout *layout = new QVBoxLayout( metadataFrame );
93 layout->setContentsMargins( 0, 0, 0, 0 );
94 metadataFrame->setContentsMargins( 0, 0, 0, 0 );
95 mMetadataWidget = new QgsMetadataWidget( this, mLayer );
96 mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
97 mMetadataWidget->setMapCanvas( mCanvas );
98 layout->addWidget( mMetadataWidget );
99 metadataFrame->setLayout( layout );
100 mOptsPage_Metadata->setContentsMargins( 0, 0, 0, 0 );
101
102 setMetadataWidget( mMetadataWidget, mOptsPage_Metadata );
103
104 mMapLayerServerPropertiesWidget->setHasWfsTitle( false );
105
106 // update based on lyr's current state
107 syncToLayer();
108
109 QgsSettings settings;
110 // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
111 // this will be read by restoreOptionsBaseUi()
112 if ( !settings.contains( QStringLiteral( "/Windows/VectorTileLayerProperties/tab" ) ) )
113 {
114 settings.setValue( QStringLiteral( "Windows/VectorTileLayerProperties/tab" ), mOptStackedWidget->indexOf( mOptsPage_Style ) );
115 }
116
117 mBtnStyle = new QPushButton( tr( "Style" ) );
118 QMenu *menuStyle = new QMenu( this );
119 menuStyle->addAction( tr( "Load Style…" ), this, &QgsVectorTileLayerProperties::loadStyle );
120 menuStyle->addAction( tr( "Save Style…" ), this, &QgsVectorTileLayerProperties::saveStyleToFile );
121 menuStyle->addSeparator();
122 menuStyle->addAction( tr( "Save as Default" ), this, &QgsVectorTileLayerProperties::saveStyleAsDefault );
123 menuStyle->addAction( tr( "Restore Default" ), this, &QgsVectorTileLayerProperties::loadDefaultStyle );
124 mBtnStyle->setMenu( menuStyle );
125 connect( menuStyle, &QMenu::aboutToShow, this, &QgsVectorTileLayerProperties::aboutToShowStyleMenu );
126
127 buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
128
129 mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
130 QMenu *menuMetadata = new QMenu( this );
131 mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata…" ), this, &QgsVectorTileLayerProperties::loadMetadataFromFile );
132 mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata…" ), this, &QgsVectorTileLayerProperties::saveMetadataToFile );
133 mBtnMetadata->setMenu( menuMetadata );
134 buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
135
136 initialize();
137}
138
140{
141 if ( mSourceWidget )
142 {
143 const QString newSource = mSourceWidget->sourceUri();
144 if ( newSource != mLayer->source() )
145 {
146 mLayer->setDataSource( newSource, mLayer->name(), mLayer->providerType(), QgsDataProvider::ProviderOptions() );
147 }
148 }
149
150 mLayer->setName( mLayerOrigNameLineEd->text() );
151 mLayer->setCrs( mCrsSelector->crs() );
152
153 mRendererWidget->apply();
154 mLabelingWidget->apply();
155 mMetadataWidget->acceptMetadata();
156
157 mLayer->setScaleBasedVisibility( chkUseScaleDependentRendering->isChecked() );
158 mLayer->setMinimumScale( mScaleRangeWidget->minimumScale() );
159 mLayer->setMaximumScale( mScaleRangeWidget->maximumScale() );
160
161 mMapLayerServerPropertiesWidget->save();
162}
163
165{
166 if ( !mLayer )
167 return;
168
169 /*
170 * Information Tab
171 */
173 // Inject the stylesheet
174 const QString html { mLayer->htmlMetadata().replace( QLatin1String( "<head>" ), QStringLiteral( R"raw(<head><style type="text/css">%1</style>)raw" ) ).arg( myStyle ) };
175 mMetadataViewer->setHtml( html );
176
177 /*
178 * Source
179 */
180
181 mLayerOrigNameLineEd->setText( mLayer->name() );
182 mCrsSelector->setCrs( mLayer->crs() );
183
184 if ( !mSourceWidget )
185 {
186 mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mLayer );
187 if ( mSourceWidget )
188 {
189 QHBoxLayout *layout = new QHBoxLayout();
190 layout->addWidget( mSourceWidget );
191 mSourceGroupBox->setLayout( layout );
192 if ( !mSourceWidget->groupTitle().isEmpty() )
193 mSourceGroupBox->setTitle( mSourceWidget->groupTitle() );
194 mSourceGroupBox->show();
195
196 connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [this]( bool isValid ) {
197 buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
198 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
199 } );
200 }
201 }
202
203 if ( mSourceWidget )
204 {
205 mSourceWidget->setMapCanvas( mCanvas );
206 mSourceWidget->setSourceUri( mLayer->source() );
207 }
208
209 /*
210 * Symbology Tab
211 */
212 mRendererWidget->syncToLayer( mLayer );
213
214 /*
215 * Labels Tab
216 */
217 mLabelingWidget->setLayer( mLayer );
218
219 /*
220 * Rendering
221 */
222 chkUseScaleDependentRendering->setChecked( mLayer->hasScaleBasedVisibility() );
223 mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
224
225 mMapLayerServerPropertiesWidget->setServerProperties( mLayer->serverProperties() );
226}
227
232
234{
235 const QgsSettings settings; // where we keep last used filter in persistent state
236
237 QgsMapLayerLoadStyleDialog dlg( mLayer );
238
239 if ( dlg.exec() )
240 {
241 mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
242 const QgsMapLayer::StyleCategories categories = dlg.styleCategories();
243 const QString type = dlg.fileExtension();
244 if ( type.compare( QLatin1String( "qml" ), Qt::CaseInsensitive ) == 0 )
245 {
246 QString message;
247 bool defaultLoadedFlag = false;
248 const QString filePath = dlg.filePath();
249 message = mLayer->loadNamedStyle( filePath, defaultLoadedFlag, categories );
250
251 //reset if the default style was loaded OK only
252 if ( defaultLoadedFlag )
253 {
254 syncToLayer();
255 }
256 else
257 {
258 //let the user know what went wrong
259 QMessageBox::warning( this, tr( "Load Style" ), message );
260 }
261 }
262 else if ( type.compare( QLatin1String( "json" ), Qt::CaseInsensitive ) == 0 )
263 {
264 QFile file( dlg.filePath() );
265 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
266 {
267 QMessageBox::warning( this, tr( "Load Style" ), tr( "Could not read %1" ).arg( QDir::toNativeSeparators( dlg.filePath() ) ) );
268 }
269 else
270 {
271 QTextStream in( &file );
272#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
273 in.setCodec( "UTF-8" );
274#endif
275 const QString content = in.readAll();
276
278 // convert automatically from pixel sizes to millimeters, because pixel sizes
279 // are a VERY edge case in QGIS and don't play nice with hidpi map renders or print layouts
281 //assume source uses 96 dpi
282 context.setPixelSizeConversionFactor( 25.4 / 96.0 );
283
284 //load sprites
285 QVariantMap styleDefinition = QgsJsonUtils::parseJson( content ).toMap();
286
287 QFileInfo fi( dlg.filePath() );
288 QgsVectorTileUtils::loadSprites( styleDefinition, context, QStringLiteral( "file://" ) + fi.absolutePath() );
289
291
292 if ( converter.convert( content, &context ) != QgsMapBoxGlStyleConverter::Success )
293 {
294 QMessageBox::warning( this, tr( "Load Style" ), converter.errorMessage() );
295 }
296 else
297 {
299 {
300 mLayer->setRenderer( converter.renderer() );
301 }
303 {
304 mLayer->setLabeling( converter.labeling() );
305 }
306 syncToLayer();
307 }
308 }
309 }
310 activateWindow(); // set focus back to properties dialog
311 }
312}
313
318
319void QgsVectorTileLayerProperties::aboutToShowStyleMenu()
320{
321 QMenu *m = qobject_cast<QMenu *>( sender() );
322
324 // re-add style manager actions!
325 m->addSeparator();
327}
328
329void QgsVectorTileLayerProperties::showHelp()
330{
331 const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
332
333 if ( helpPage.isValid() )
334 {
335 QgsHelp::openHelp( helpPage.toString() );
336 }
337 else
338 {
339 QgsHelp::openHelp( QStringLiteral( "working_with_vector_tiles/vector_tiles_properties.html" ) );
340 }
341}
342
343void QgsVectorTileLayerProperties::crsChanged( const QgsCoordinateReferenceSystem &crs )
344{
345 QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation" ) );
346 mLayer->setCrs( crs );
347 mMetadataWidget->crsChanged();
348}
@ Millimeters
Millimeters.
Definition qgis.h:5184
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
@ WebBrowser
StyleSheet for embedded browsers (QtWebKit), supports full standard CSS.
Represents a coordinate reference system (CRS).
static bool run(const QgsCoordinateReferenceSystem &sourceCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr, const QString &windowTitle=QString())
Runs the dialog (if required) prompting for the desired transform to use from sourceCrs to destinatio...
static QgsProviderSourceWidgetProviderRegistry * sourceWidgetProviderRegistry()
Returns the registry of provider source widget providers.
Definition qgsgui.cpp:131
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:38
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
void saveMetadataToFile()
Allows the user to save the layer's metadata as a file.
virtual void rollback()
Rolls back changes made to the layer.
void saveStyleAsDefault()
Saves the current layer style as the default for the layer.
void setMetadataWidget(QgsMetadataWidget *widget, QWidget *page)
Sets the metadata widget and page associated with the dialog.
void loadDefaultStyle()
Reloads the default style for the layer.
virtual void apply()=0
Applies the dialog settings to the layer.
virtual void syncToLayer()=0
Resets the dialog to the current layer state.
void saveStyleToFile()
Allows the user to save the layer's style to a file.
QgsMapCanvas * mCanvas
Associated map canvas.
QgsLayerPropertiesDialog(QgsMapLayer *layer, QgsMapCanvas *canvas, const QString &settingsKey, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), QgsSettings *settings=nullptr)
Constructor for QgsLayerPropertiesDialog.
QgsMapLayerStyle mOldStyle
Previous layer style.
void loadMetadataFromFile()
Allows the user to load layer metadata from a file.
void initialize()
Initialize the dialog.
void openUrl(const QUrl &url)
Handles opening a url from the dialog.
Context for a MapBox GL style conversion operation.
void setTargetUnit(Qgis::RenderUnit targetUnit)
Sets the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
Handles conversion of MapBox GL styles to QGIS vector tile renderers and labeling settings.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
@ Success
Conversion was successful.
QString errorMessage() const
Returns a descriptive error message if an error was encountered during the style conversion,...
Map canvas is a class for displaying all GIS data types on a canvas.
A reusable dialog which allows users to select stored layer styles and categories to load for a map l...
QgsMapLayer::StyleCategories styleCategories() const
Returns the list of selected style categories the user has opted to load.
QString filePath() const
Returns the full path to the selected layer style source file.
QString fileExtension() const
Returns the file extension for the selected layer style source file.
void removesExtraMenuSeparators(QMenu *m)
removes extra separators from the menu
void addStyleManagerActions(QMenu *m, QgsMapLayer *layer)
adds actions to the menu in accordance to the layer
static QgsMapLayerStyleGuiUtils * instance()
returns a singleton instance of this class
QString name
Definition qgsmaplayer.h:84
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QFlags< StyleCategory > StyleCategories
@ Symbology
Symbology.
@ Labeling
Labeling.
A bar for displaying non-blocking messages to the user.
A wizard to edit metadata on a map layer.
QStackedWidget * mOptStackedWidget
void initOptionsBase(bool restoreUi=true, const QString &title=QString())
Set up the base ui connections for vertical tabs.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void crsChanged(const QgsCoordinateReferenceSystem &crs)
Emitted when the selected CRS is changed.
QgsProviderSourceWidget * createWidget(QgsMapLayer *layer, QWidget *parent=nullptr)
Creates a new widget to configure the source of the specified layer.
void validChanged(bool isValid)
Emitted whenever the validation status of the widget changes.
virtual QString sourceUri() const =0
Returns the source URI as currently defined by the widget.
Stores settings for use within QGIS.
Definition qgssettings.h:65
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Q_DECL_DEPRECATED void saveDefaultStyle() SIP_DEPRECATED
Saves the default style when appropriate button is pressed.
Q_DECL_DEPRECATED void saveStyleAs() SIP_DEPRECATED
Saves a style when appriate button is pressed.
void loadStyle()
Loads a saved style when appropriate button is pressed.
QgsVectorTileLayerProperties(QgsVectorTileLayer *lyr, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent=nullptr, Qt::WindowFlags=QgsGuiUtils::ModalDialogFlags)
Constructor.
Implements a map layer that is dedicated to rendering of vector tiles.
static void loadSprites(const QVariantMap &styleDefinition, QgsMapBoxGlStyleConversionContext &context, const QString &styleUrl=QString())
Downloads the sprite image and sets it to the conversion context.
Setting options for creating vector data providers.