QGIS API Documentation  3.27.0-Master (597e8eebd4)
qgsexternalresourceconfigdlg.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexternalresourceconfigdlg.cpp
3  --------------------------------------
4  Date : 2015-11-26
5  Copyright : (C) 2015 Médéric Ribreux
6  Email : mederic.ribreux at medspx dot fr
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 
18 #include "qgsproject.h"
19 #include "qgssettings.h"
21 #include "qgsapplication.h"
22 #include "qgsvectorlayer.h"
24 #include "qgseditorwidgetwrapper.h"
25 #include "qgsexternalstorage.h"
29 
30 #include <QFileDialog>
31 #include <QComboBox>
32 
34 
36  : QgsEditorConfigWidget( vl, fieldIdx, parent )
37 {
38  setupUi( this );
39 
40  mStorageType->addItem( tr( "Select Existing file" ), QString() );
41  for ( QgsExternalStorage *storage : QgsApplication::externalStorageRegistry()->externalStorages() )
42  {
43  mStorageType->addItem( storage->displayName(), storage->type() );
44  }
45 
46  mExternalStorageGroupBox->setVisible( false );
47 
48  initializeDataDefinedButton( mStorageUrlPropertyOverrideButton, QgsEditorWidgetWrapper::StorageUrl );
49  mStorageUrlPropertyOverrideButton->registerVisibleWidget( mStorageUrlExpression );
50  mStorageUrlPropertyOverrideButton->registerExpressionWidget( mStorageUrlExpression );
51  mStorageUrlPropertyOverrideButton->registerVisibleWidget( mStorageUrl, false );
52  mStorageUrlPropertyOverrideButton->registerExpressionContextGenerator( this );
53 
54  // By default, uncheck some options
55  mUseLink->setChecked( false );
56  mFullUrl->setChecked( false );
57 
58  const QString defpath = QgsProject::instance()->fileName().isEmpty() ? QDir::homePath() : QFileInfo( QgsProject::instance()->absoluteFilePath() ).path();
59 
60  mRootPath->setPlaceholderText( QgsSettings().value( QStringLiteral( "/UI/lastExternalResourceWidgetDefaultPath" ), QDir::toNativeSeparators( QDir::cleanPath( defpath ) ) ).toString() );
61 
62  connect( mRootPathButton, &QToolButton::clicked, this, &QgsExternalResourceConfigDlg::chooseDefaultPath );
63 
64  initializeDataDefinedButton( mRootPathPropertyOverrideButton, QgsEditorWidgetWrapper::RootPath );
65  mRootPathPropertyOverrideButton->registerVisibleWidget( mRootPathExpression );
66  mRootPathPropertyOverrideButton->registerExpressionWidget( mRootPathExpression );
67  mRootPathPropertyOverrideButton->registerVisibleWidget( mRootPath, false );
68  mRootPathPropertyOverrideButton->registerEnabledWidget( mRootPathButton, false );
69 
70  initializeDataDefinedButton( mDocumentViewerContentPropertyOverrideButton, QgsEditorWidgetWrapper::DocumentViewerContent );
71  mDocumentViewerContentPropertyOverrideButton->registerVisibleWidget( mDocumentViewerContentExpression );
72  mDocumentViewerContentPropertyOverrideButton->registerExpressionWidget( mDocumentViewerContentExpression );
73  mDocumentViewerContentPropertyOverrideButton->registerEnabledWidget( mDocumentViewerContentComboBox, false );
74 
75  // Activate Relative Default Path option only if Default Path is set
76  connect( mRootPath, &QLineEdit::textChanged, this, &QgsExternalResourceConfigDlg::enableRelativeDefault );
77  connect( mRootPathExpression, &QLineEdit::textChanged, this, &QgsExternalResourceConfigDlg::enableRelativeDefault );
78 
79  // Add storage modes
80  mStorageModeCbx->addItem( tr( "File Paths" ), QgsFileWidget::GetFile );
81  mStorageModeCbx->addItem( tr( "Directory Paths" ), QgsFileWidget::GetDirectory );
82 
83  // Add storage path options
84  mStoragePathCbx->addItem( tr( "Absolute Path" ), QgsFileWidget::Absolute );
85  mStoragePathCbx->addItem( tr( "Relative to Project Path" ), QgsFileWidget::RelativeProject );
86  mStoragePathCbx->addItem( tr( "Relative to Default Path" ), QgsFileWidget::RelativeDefaultPath );
87  enableCbxItem( mStoragePathCbx, 2, false );
88 
89  connect( mStorageType, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsExternalResourceConfigDlg::changeStorageType );
90  connect( mFileWidgetGroupBox, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
91  connect( mFileWidgetButtonGroupBox, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
92  connect( mFileWidgetFilterLineEdit, &QLineEdit::textChanged, this, &QgsEditorConfigWidget::changed );
93  connect( mUseLink, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
94  connect( mFullUrl, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
95  connect( mRootPath, &QLineEdit::textChanged, this, &QgsEditorConfigWidget::changed );
96  connect( mStorageModeCbx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditorConfigWidget::changed );
97  connect( mStoragePathCbx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditorConfigWidget::changed );
98  connect( mDocumentViewerGroupBox, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
99  connect( mDocumentViewerContentComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [ = ]( int idx )
100  { mDocumentViewerContentSettingsWidget->setEnabled( ( QgsExternalResourceWidget::DocumentViewerContent )idx != QgsExternalResourceWidget::NoContent ); } );
101  connect( mDocumentViewerHeight, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsEditorConfigWidget::changed );
102  connect( mDocumentViewerWidth, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsEditorConfigWidget::changed );
103  connect( mStorageUrlExpression, &QLineEdit::textChanged, this, &QgsEditorConfigWidget::changed );
104 
105  mDocumentViewerContentComboBox->addItem( tr( "No Content" ), QgsExternalResourceWidget::NoContent );
106  mDocumentViewerContentComboBox->addItem( tr( "Image" ), QgsExternalResourceWidget::Image );
107  mDocumentViewerContentComboBox->addItem( tr( "Web View" ), QgsExternalResourceWidget::Web );
108 }
109 
110 void QgsExternalResourceConfigDlg::chooseDefaultPath()
111 {
112  QString dir;
113  if ( !mRootPath->text().isEmpty() )
114  {
115  dir = mRootPath->text();
116  }
117  else
118  {
119  const QString path = QFileInfo( QgsProject::instance()->absoluteFilePath() ).path();
120  dir = QgsSettings().value( QStringLiteral( "/UI/lastExternalResourceWidgetDefaultPath" ), QDir::toNativeSeparators( QDir::cleanPath( path ) ) ).toString();
121  }
122 
123  const QString rootName = QFileDialog::getExistingDirectory( this, tr( "Select a Directory" ), dir, QFileDialog::Options() );
124 
125  if ( !rootName.isNull() )
126  mRootPath->setText( rootName );
127 }
128 
129 void QgsExternalResourceConfigDlg::enableCbxItem( QComboBox *comboBox, int index, bool enabled )
130 {
131  // https://stackoverflow.com/a/62261745
132  const auto *model = qobject_cast<QStandardItemModel *>( comboBox->model() );
133  assert( model );
134  if ( !model )
135  return;
136 
137  auto *item = model->item( index );
138  assert( item );
139  if ( !item )
140  return;
141  item->setEnabled( enabled );
142 }
143 
144 void QgsExternalResourceConfigDlg::enableRelativeDefault()
145 {
146  bool relativePathActive = false;
147 
148  if ( mRootPathPropertyOverrideButton->isActive() )
149  {
150  if ( !mRootPathExpression->text().isEmpty() )
151  relativePathActive = true;
152  }
153  else
154  {
155  if ( !mRootPath->text().isEmpty() )
156  relativePathActive = true;
157  }
158  // Activate (or not) the RelativeDefault item if default path
159  enableCbxItem( mStoragePathCbx, 2, relativePathActive );
160 }
161 
163 {
164  QVariantMap cfg;
165 
166  cfg.insert( QStringLiteral( "StorageType" ), mStorageType->currentData() );
167  cfg.insert( QStringLiteral( "StorageAuthConfigId" ), mAuthSettingsProtocol->configId() );
168  if ( !mStorageUrl->text().isEmpty() )
169  cfg.insert( QStringLiteral( "StorageUrl" ), mStorageUrl->text() );
170 
171  cfg.insert( QStringLiteral( "FileWidget" ), mFileWidgetGroupBox->isChecked() );
172  cfg.insert( QStringLiteral( "FileWidgetButton" ), mFileWidgetButtonGroupBox->isChecked() );
173  cfg.insert( QStringLiteral( "FileWidgetFilter" ), mFileWidgetFilterLineEdit->text() );
174 
175  if ( mUseLink->isChecked() )
176  {
177  cfg.insert( QStringLiteral( "UseLink" ), mUseLink->isChecked() );
178  if ( mFullUrl->isChecked() )
179  cfg.insert( QStringLiteral( "FullUrl" ), mFullUrl->isChecked() );
180  }
181 
182  cfg.insert( QStringLiteral( "PropertyCollection" ), mPropertyCollection.toVariant( QgsWidgetWrapper::propertyDefinitions() ) );
183 
184  if ( !mRootPath->text().isEmpty() )
185  cfg.insert( QStringLiteral( "DefaultRoot" ), mRootPath->text() );
186 
187  if ( !mStorageType->currentIndex() )
188  {
189  // Save Storage Mode
190  cfg.insert( QStringLiteral( "StorageMode" ), mStorageModeCbx->currentData().toInt() );
191  // Save Relative Paths option
192  cfg.insert( QStringLiteral( "RelativeStorage" ), mStoragePathCbx->currentData().toInt() );
193  }
194  else
195  {
196  // Only file mode and absolute paths are supported for external storage
197  cfg.insert( QStringLiteral( "StorageMode" ), static_cast<int>( QgsFileWidget::GetFile ) );
198  cfg.insert( QStringLiteral( "RelativeStorage" ), static_cast<int>( QgsFileWidget::Absolute ) );
199  }
200 
201  cfg.insert( QStringLiteral( "DocumentViewer" ), mDocumentViewerContentComboBox->currentData().toInt() );
202  cfg.insert( QStringLiteral( "DocumentViewerHeight" ), mDocumentViewerHeight->value() );
203  cfg.insert( QStringLiteral( "DocumentViewerWidth" ), mDocumentViewerWidth->value() );
204 
205  return cfg;
206 }
207 
208 
210 {
211  if ( config.contains( QStringLiteral( "StorageType" ) ) )
212  {
213  const int index = mStorageType->findData( config.value( QStringLiteral( "StorageType" ) ) );
214  if ( index >= 0 )
215  mStorageType->setCurrentIndex( index );
216  }
217 
218  mAuthSettingsProtocol->setConfigId( config.value( QStringLiteral( "StorageAuthConfigId" ) ).toString() );
219  mStorageUrl->setText( config.value( QStringLiteral( "StorageUrl" ) ).toString() );
220 
221  if ( config.contains( QStringLiteral( "FileWidget" ) ) )
222  {
223  mFileWidgetGroupBox->setChecked( config.value( QStringLiteral( "FileWidget" ) ).toBool() );
224  }
225  if ( config.contains( QStringLiteral( "FileWidget" ) ) )
226  {
227  mFileWidgetButtonGroupBox->setChecked( config.value( QStringLiteral( "FileWidgetButton" ) ).toBool() );
228  }
229  if ( config.contains( QStringLiteral( "FileWidgetFilter" ) ) )
230  {
231  mFileWidgetFilterLineEdit->setText( config.value( QStringLiteral( "FileWidgetFilter" ) ).toString() );
232  }
233 
234  if ( config.contains( QStringLiteral( "UseLink" ) ) )
235  {
236  mUseLink->setChecked( config.value( QStringLiteral( "UseLink" ) ).toBool() );
237  if ( config.contains( QStringLiteral( "FullUrl" ) ) )
238  mFullUrl->setChecked( true );
239  }
240 
241  mPropertyCollection.loadVariant( config.value( QStringLiteral( "PropertyCollection" ) ), QgsWidgetWrapper::propertyDefinitions() );
243 
244  mRootPath->setText( config.value( QStringLiteral( "DefaultRoot" ) ).toString() );
245 
246  // relative storage
247  if ( config.contains( QStringLiteral( "RelativeStorage" ) ) )
248  {
249  const int relative = config.value( QStringLiteral( "RelativeStorage" ) ).toInt();
250  mStoragePathCbx->setCurrentIndex( relative );
251  }
252 
253  // set storage mode
254  if ( config.contains( QStringLiteral( "StorageMode" ) ) )
255  {
256  const int mode = config.value( QStringLiteral( "StorageMode" ) ).toInt();
257  mStorageModeCbx->setCurrentIndex( mode );
258  }
259 
260  // Document viewer
261  if ( config.contains( QStringLiteral( "DocumentViewer" ) ) )
262  {
263  const QgsExternalResourceWidget::DocumentViewerContent content = ( QgsExternalResourceWidget::DocumentViewerContent )config.value( QStringLiteral( "DocumentViewer" ) ).toInt();
264  const int idx = mDocumentViewerContentComboBox->findData( content );
265  if ( idx >= 0 )
266  {
267  mDocumentViewerContentComboBox->setCurrentIndex( idx );
268  }
269  if ( config.contains( QStringLiteral( "DocumentViewerHeight" ) ) )
270  {
271  mDocumentViewerHeight->setValue( config.value( QStringLiteral( "DocumentViewerHeight" ) ).toInt() );
272  }
273  if ( config.contains( QStringLiteral( "DocumentViewerWidth" ) ) )
274  {
275  mDocumentViewerWidth->setValue( config.value( QStringLiteral( "DocumentViewerWidth" ) ).toInt() );
276  }
277  }
278 }
279 
281 {
285 
287  context << fileWidgetScope;
288 
289  context.setHighlightedVariables( fileWidgetScope->variableNames() );
290  return context;
291 }
292 
293 void QgsExternalResourceConfigDlg::changeStorageType( int storageTypeIndex )
294 {
295  // first one in combo box is not an external storage
296  mExternalStorageGroupBox->setVisible( storageTypeIndex > 0 );
297 
298  // for now, we store only files in external storage
299  mStorageModeCbx->setVisible( !storageTypeIndex );
300  mStorageModeLbl->setVisible( !storageTypeIndex );
301 
302  // Absolute path are mandatory when using external storage
303  mStoragePathCbx->setVisible( !storageTypeIndex );
304  mStoragePathLbl->setVisible( !storageTypeIndex );
305 
306  emit changed();
307 }
static QgsExternalStorageRegistry * externalStorageRegistry()
Returns registry of available external storage implementations.
This class should be subclassed for every configurable editor widget type.
void updateDataDefinedButtons()
Updates all property override buttons to reflect the widgets's current properties.
QgsPropertyCollection mPropertyCollection
Temporary property collection for config widgets.
void initializeDataDefinedButton(QgsPropertyOverrideButton *button, QgsWidgetWrapper::Property key)
Registers a property override button, setting up its initial value, connections and description.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void changed()
Emitted when the configuration of the widget is changed.
int fieldIdx() const
Access the field index.
Single scope for storing variables and functions for use within a QgsExpressionContext.
QStringList variableNames() const
Returns a list of variable names contained within the scope.
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
QVariantMap config() override
Create a configuration from the current GUI state.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsExternalResourceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)
Constructor for QgsExternalResourceConfigDlg.
QVariant value() const override
Will be used to access the widget's value.
static QgsExpressionContextScope * createFileWidgetScope()
Creates and Returns an expression context scope specific to QgsExternalStorageFileWidget It defines t...
Abstract interface for external storage - to be implemented by various backends and registered in Qgs...
@ GetFile
Select a single file.
Definition: qgsfilewidget.h:68
@ GetDirectory
Select a directory.
Definition: qgsfilewidget.h:69
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:479
QString fileName
Definition: qgsproject.h:107
bool loadVariant(const QVariant &configuration, const QgsPropertiesDefinition &definitions) override
Loads this property collection from a QVariantMap, wrapped in a QVariant.
QVariant toVariant(const QgsPropertiesDefinition &definitions) const override
Saves this property collection to a QVariantMap, wrapped in a QVariant.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Represents a vector layer which manages a vector based data sets.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the editor widget property definitions.
@ DocumentViewerContent
Document type for external resource.
@ RootPath
Root path for external resource.
@ StorageUrl
Storage URL for external resource.
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
QVariantMap config() const
Returns the whole config.