QGIS API Documentation 3.31.0-Master (d2b117a3c8)
qgsexternalstoragefilewidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsexternalstoragefilewidget.cpp
3 --------------------------------------
4 Date : August 2021
5 Copyright : (C) 2021 by Julien Cabieces
6 Email : julien dot cabieces at oslandia 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 <QLineEdit>
19#include <QToolButton>
20#include <QLabel>
21#include <QGridLayout>
22#include <QUrl>
23#include <QDropEvent>
24#include <QRegularExpression>
25#include <QProgressBar>
26
27#include "qgslogger.h"
28#include "qgsapplication.h"
29#include "qgsexternalstorage.h"
31#include "qgsmessagebar.h"
32#include "qgsexpression.h"
33
34#define FILEPATH_VARIABLE "selected_file_path"
35
37 : QgsFileWidget( parent )
38{
39 mProgressLabel = new QLabel( this );
40 mLayout->addWidget( mProgressLabel );
41 mProgressLabel->hide();
42
43 mProgressBar = new QProgressBar( this );
44 mLayout->addWidget( mProgressBar );
45 mProgressBar->hide();
46
47 mCancelButton = new QToolButton( this );
48 mLayout->addWidget( mCancelButton );
49 mCancelButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mTaskCancel.svg" ) ) );
50 mCancelButton->hide();
51
52 updateAcceptDrops();
53}
54
55void QgsExternalStorageFileWidget::setStorageType( const QString &storageType )
56{
57 if ( storageType.isEmpty() )
58 mExternalStorage = nullptr;
59
60 else
61 {
63 if ( !mExternalStorage )
64 {
65 QgsDebugMsg( QStringLiteral( "Invalid storage type: %1" ).arg( storageType ) );
66 }
67 else
68 {
70 }
71 }
72
73 updateAcceptDrops();
74}
75
77{
79 updateAcceptDrops();
80}
81
82void QgsExternalStorageFileWidget::updateAcceptDrops()
83{
84 setAcceptDrops( !mReadOnly && mExternalStorage );
85}
86
88{
89 return mExternalStorage ? mExternalStorage->type() : QString();
90}
91
93{
94 return mExternalStorage;
95}
96
98{
99 mAuthCfg = authCfg;
100}
101
103{
104 return mAuthCfg;
105}
106
108{
109 mStorageUrlExpression.reset( new QgsExpression( urlExpression ) );
110}
111
113{
114 return mStorageUrlExpression.get();
115}
116
118{
119 return mStorageUrlExpression ? mStorageUrlExpression->expression() : QString();
120}
121
122
124{
125 mScope = nullptr; // deleted by old context when we override it with the new one
126 mExpressionContext = context;
128}
129
131{
132 if ( !mExternalStorage || mScope )
133 return;
134
135 mScope = createFileWidgetScope();
136 mExpressionContext << mScope;
137}
138
140{
141 QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "FileWidget" ) );
143 QStringLiteral( FILEPATH_VARIABLE ),
144 QString(), true, false, tr( "User selected absolute filepath" ) ) );
145 return scope;
146}
147
149{
150 return mExpressionContext;
151}
152
153
155{
156 mMessageBar = messageBar;
157}
158
160{
161 return mMessageBar;
162}
163
165{
166 mProgressLabel->setVisible( mStoreInProgress );
167 mProgressBar->setVisible( mStoreInProgress );
168 mCancelButton->setVisible( mStoreInProgress );
169
170 const bool linkVisible = mUseLink && !mIsLinkEdited;
171
172 mLineEdit->setVisible( !mStoreInProgress && !linkVisible );
173 mLinkLabel->setVisible( !mStoreInProgress && linkVisible );
174 mLinkEditButton->setVisible( !mStoreInProgress && mUseLink && !mReadOnly );
175
176 mFileWidgetButton->setVisible( mButtonVisible && !mStoreInProgress );
177 mFileWidgetButton->setEnabled( !mReadOnly );
178 mLineEdit->setEnabled( !mReadOnly );
179
180 mLinkEditButton->setIcon( linkVisible && !mReadOnly ?
181 QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) :
182 QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
183}
184
186{
187 Q_ASSERT( fileNames.count() );
188
189 // store files first, update filePath later
190 if ( mExternalStorage )
191 {
192 if ( !mStorageUrlExpression->prepare( &mExpressionContext ) )
193 {
194 if ( messageBar() )
195 {
196 messageBar()->pushWarning( tr( "Storing External resource" ),
197 tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
198 }
199
200 QgsDebugMsg( QStringLiteral( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
201 return;
202 }
203
204 storeExternalFiles( fileNames );
205 }
206 else
207 {
209 }
210}
211
212void QgsExternalStorageFileWidget::storeExternalFiles( QStringList fileNames, QStringList storedUrls )
213{
214 if ( fileNames.isEmpty() )
215 return;
216
217 const QString filePath = fileNames.takeFirst();
218
219 mProgressLabel->setText( tr( "Storing file %1 ..." ).arg( QFileInfo( filePath ).fileName() ) );
220 mStoreInProgress = true;
221 mProgressBar->setValue( 0 );
222 updateLayout();
223
224 Q_ASSERT( mScope );
225 mScope->setVariable( QStringLiteral( FILEPATH_VARIABLE ), filePath );
226
227 QVariant url = mStorageUrlExpression->evaluate( &mExpressionContext );
228 if ( !url.isValid() )
229 {
230 if ( messageBar() )
231 {
232 messageBar()->pushWarning( tr( "Storing External resource" ),
233 tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
234 }
235
236 mStoreInProgress = false;
237 updateLayout();
238
239 return;
240 }
241
242 QgsExternalStorageStoredContent *storedContent = mExternalStorage->store( filePath, url.toString(), mAuthCfg );
243
244 connect( storedContent, &QgsExternalStorageStoredContent::progressChanged, mProgressBar, &QProgressBar::setValue );
245 connect( mCancelButton, &QToolButton::clicked, storedContent, &QgsExternalStorageStoredContent::cancel );
246
247 auto onStoreFinished = [ = ]
248 {
249 mStoreInProgress = false;
250 updateLayout();
251 storedContent->deleteLater();
252
253 if ( storedContent->status() == Qgis::ContentStatus::Failed && messageBar() )
254 {
255 messageBar()->pushWarning( tr( "Storing External resource" ),
256 tr( "Storing file '%1' to url '%2' has failed : %3" ).arg( filePath, url.toString(), storedContent->errorString() ) );
257 }
258
259 if ( storedContent->status() != Qgis::ContentStatus::Finished )
260 return;
261
262 QStringList newStoredUrls = storedUrls;
263 newStoredUrls << storedContent->url();
264
265 // every thing has been stored, we update filepath
266 if ( fileNames.isEmpty() )
267 {
268 setFilePaths( newStoredUrls );
269 }
270 else
271 storeExternalFiles( fileNames, newStoredUrls );
272 };
273
274 connect( storedContent, &QgsExternalStorageStoredContent::stored, onStoreFinished );
275 connect( storedContent, &QgsExternalStorageStoredContent::canceled, onStoreFinished );
276 connect( storedContent, &QgsExternalStorageStoredContent::errorOccurred, onStoreFinished );
277
278 storedContent->store();
279}
280
282{
283 const QStringList filePaths = mLineEdit->acceptableFilePaths( event );
284 if ( !filePaths.isEmpty() )
285 {
286 event->acceptProposedAction();
287 }
288 else
289 {
290 event->ignore();
291 }
292}
293
295{
296 storeExternalFiles( mLineEdit->acceptableFilePaths( event ) );
297 event->acceptProposedAction();
298}
@ Finished
Content fetching/storing is finished and successful.
@ Failed
Content fetching/storing has failed.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsExternalStorageRegistry * externalStorageRegistry()
Returns registry of available external storage implementations.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Class for parsing and evaluation of expressions (formerly called "search strings").
void canceled()
The signal is emitted when content fetching/storing has been canceled.
void progressChanged(double progress)
The signal is emitted whenever content fetching/storing estimated progression value progress has chan...
void errorOccurred(const QString &errorString)
The signal is emitted when an error occurred.
Qgis::ContentStatus status() const
Returns content status.
virtual void cancel()
Cancels content fetching/storing.
const QString & errorString() const
Returns error textual description if an error occurred and status() returns Failed.
void updateLayout() override
Update buttons visibility.
void setSelectedFileNames(QStringList fileNames) override
Called whenever user select fileNames from dialog.
void setMessageBar(QgsMessageBar *messageBar)
Set messageBar to report messages.
const QString & storageAuthConfigId() const
Returns the authentication configuration ID used for the current external storage (if defined)
void setStorageType(const QString &storageType)
Set storageType storage type unique identifier as defined in QgsExternalStorageRegistry or null QStri...
void setExpressionContext(const QgsExpressionContext &context)
Set expression context to be used when for storage URL expression evaluation.
QString storageUrlExpressionString() const
Returns the original, unmodified expression string, which once evaluated, provide the URL used to sto...
void setStorageUrlExpression(const QString &urlExpression)
Set urlExpression expression, which once evaluated, provide the URL used to store selected documents.
static QgsExpressionContextScope * createFileWidgetScope()
Creates and Returns an expression context scope specific to QgsExternalStorageFileWidget It defines t...
QgsExternalStorageFileWidget(QWidget *parent=nullptr)
QgsExternalStorageFileWidget creates a widget for selecting a file or a folder.
void setReadOnly(bool readOnly) override
Sets whether the widget should be read only.
QgsExternalStorage * externalStorage() const
Returns external storage used to store selected file names, nullptr if none have been defined.
void setStorageAuthConfigId(const QString &authCfg)
Sets the authentication configuration ID to be used for the current external storage (if defined)
QgsMessageBar * messageBar() const
Returns message bar used to report messages.
void addFileWidgetScope()
Add file widget specific scope to expression context.
void dragEnterEvent(QDragEnterEvent *event) override
const QgsExpressionContext & expressionContext() const
Returns expression context used for storage url expression evaluation.
void dropEvent(QDropEvent *event) override
QgsExternalStorage * externalStorageFromType(const QString &type) const
Returns external storage implementation if the storage type matches one.
Class for QgsExternalStorage stored content.
void stored()
The signal is emitted when the resource has successfully been stored.
virtual QString url() const =0
Returns stored resource URL.
virtual void store()=0
Starts storing.
Abstract interface for external storage - to be implemented by various backends and registered in Qgs...
virtual QString type() const =0
Unique identifier of the external storage type.
QgsExternalStorageStoredContent * store(const QString &filePath, const QString &url, const QString &authCfg=QString(), Qgis::ActionStart storingMode=Qgis::ActionStart::Deferred) const
Stores file filePath to the url for this project external storage.
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:39
QString filePath()
Returns the current file path(s).
void setFilePaths(const QStringList &filePaths)
Update filePath according to filePaths list.
QHBoxLayout * mLayout
virtual void setSelectedFileNames(QStringList fileNames)
Called whenever user select fileNames from dialog.
QgsFileDropEdit * mLineEdit
QToolButton * mLinkEditButton
QToolButton * mFileWidgetButton
QLabel * mLinkLabel
virtual void setReadOnly(bool readOnly)
Sets whether the widget should be read only.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushWarning(const QString &title, const QString &message)
Pushes a warning message that must be manually dismissed by the user.
#define FILEPATH_VARIABLE
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Single variable definition for use within a QgsExpressionContextScope.