QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
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 <memory>
19
20#include "qgsapplication.h"
21#include "qgsexpression.h"
22#include "qgsexternalstorage.h"
24#include "qgslogger.h"
25#include "qgsmessagebar.h"
26
27#include <QDropEvent>
28#include <QGridLayout>
29#include <QLabel>
30#include <QLineEdit>
31#include <QProgressBar>
32#include <QRegularExpression>
33#include <QString>
34#include <QToolButton>
35#include <QUrl>
36
37#include "moc_qgsexternalstoragefilewidget.cpp"
38
39using namespace Qt::StringLiterals;
40
41#define FILEPATH_VARIABLE "selected_file_path"
42
44 : QgsFileWidget( parent )
45{
46 mProgressLabel = new QLabel( this );
47 mLayout->addWidget( mProgressLabel );
48 mProgressLabel->hide();
49
50 mProgressBar = new QProgressBar( this );
51 mLayout->addWidget( mProgressBar );
52 mProgressBar->hide();
53
54 mCancelButton = new QToolButton( this );
55 mLayout->addWidget( mCancelButton );
56 mCancelButton->setIcon( QgsApplication::getThemeIcon( u"/mTaskCancel.svg"_s ) );
57 mCancelButton->hide();
58
59 updateAcceptDrops();
60}
61
63{
64 if ( storageType.isEmpty() )
65 mExternalStorage = nullptr;
66
67 else
68 {
70 if ( !mExternalStorage )
71 {
72 QgsDebugError( u"Invalid storage type: %1"_s.arg( storageType ) );
73 }
74 else
75 {
77 }
78 }
79
80 updateAcceptDrops();
81}
82
84{
86 updateAcceptDrops();
87}
88
89void QgsExternalStorageFileWidget::updateAcceptDrops()
90{
91 setAcceptDrops( !mReadOnly && mExternalStorage );
92}
93
95{
96 return mExternalStorage ? mExternalStorage->type() : QString();
97}
98
100{
101 return mExternalStorage;
102}
103
105{
106 mAuthCfg = authCfg;
107}
108
110{
111 return mAuthCfg;
112}
113
115{
116 mStorageUrlExpression = std::make_unique<QgsExpression>( urlExpression );
117}
118
120{
121 return mStorageUrlExpression.get();
122}
123
125{
126 return mStorageUrlExpression ? mStorageUrlExpression->expression() : QString();
127}
128
129
131{
132 mScope = nullptr; // deleted by old context when we override it with the new one
133 mExpressionContext = context;
135}
136
138{
139 if ( !mExternalStorage || mScope )
140 return;
141
142 mScope = createFileWidgetScope();
143 mExpressionContext << mScope;
144}
145
147{
148 QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "FileWidget" ) );
150 QStringLiteral( FILEPATH_VARIABLE ),
151 QString(), true, false, tr( "User selected absolute filepath" )
152 ) );
153 return scope;
154}
155
157{
158 return mExpressionContext;
159}
160
161
166
168{
169 return mMessageBar;
170}
171
173{
174 mProgressLabel->setVisible( mStoreInProgress );
175 mProgressBar->setVisible( mStoreInProgress );
176 mCancelButton->setVisible( mStoreInProgress );
177
178 const bool linkVisible = mUseLink && !mIsLinkEdited;
179
180 mLineEdit->setVisible( !mStoreInProgress && !linkVisible );
181 mLinkLabel->setVisible( !mStoreInProgress && linkVisible );
182 mLinkEditButton->setVisible( !mStoreInProgress && mUseLink && !mReadOnly );
183
184 mFileWidgetButton->setVisible( mButtonVisible && !mStoreInProgress );
185 mFileWidgetButton->setEnabled( !mReadOnly );
186 mLineEdit->setEnabled( !mReadOnly );
187
188 mLinkEditButton->setIcon( linkVisible && !mReadOnly ? QgsApplication::getThemeIcon( u"/mActionToggleEditing.svg"_s ) : QgsApplication::getThemeIcon( u"/mActionSaveEdits.svg"_s ) );
189}
190
192{
193 Q_ASSERT( fileNames.count() );
194
195 // store files first, update filePath later
196 if ( mExternalStorage )
197 {
198 if ( !mStorageUrlExpression->prepare( &mExpressionContext ) )
199 {
200 if ( messageBar() )
201 {
202 messageBar()->pushWarning( tr( "Storing External resource" ), tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
203 }
204
205 QgsDebugError( u"Storage URL expression is invalid : %1"_s.arg( mStorageUrlExpression->evalErrorString() ) );
206 return;
207 }
208
209 storeExternalFiles( fileNames );
210 }
211 else
212 {
214 }
215}
216
217void QgsExternalStorageFileWidget::storeExternalFiles( QStringList fileNames, QStringList storedUrls )
218{
219 if ( fileNames.isEmpty() )
220 return;
221
222 const QString filePath = fileNames.takeFirst();
223
224 mProgressLabel->setText( tr( "Storing file %1 ..." ).arg( QFileInfo( filePath ).fileName() ) );
225 mStoreInProgress = true;
226 mProgressBar->setValue( 0 );
227 updateLayout();
228
229 Q_ASSERT( mScope );
230 mScope->setVariable( QStringLiteral( FILEPATH_VARIABLE ), filePath );
231
232 QVariant url = mStorageUrlExpression->evaluate( &mExpressionContext );
233 if ( !url.isValid() )
234 {
235 if ( messageBar() )
236 {
237 messageBar()->pushWarning( tr( "Storing External resource" ), tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
238 }
239
240 mStoreInProgress = false;
241 updateLayout();
242
243 return;
244 }
245
246 QgsExternalStorageStoredContent *storedContent = mExternalStorage->store( filePath, url.toString(), mAuthCfg );
247
248 connect( storedContent, &QgsExternalStorageStoredContent::progressChanged, mProgressBar, &QProgressBar::setValue );
249 connect( mCancelButton, &QToolButton::clicked, storedContent, &QgsExternalStorageStoredContent::cancel );
250
251 auto onStoreFinished = [this, storedContent, fileNames, storedUrls, filePath, url] {
252 mStoreInProgress = false;
253 updateLayout();
254 storedContent->deleteLater();
255
256 if ( storedContent->status() == Qgis::ContentStatus::Failed && messageBar() )
257 {
258 messageBar()->pushWarning( tr( "Storing External resource" ), tr( "Storing file '%1' to url '%2' has failed : %3" ).arg( filePath, url.toString(), storedContent->errorString() ) );
259 }
260
261 if ( storedContent->status() != Qgis::ContentStatus::Finished )
262 return;
263
264 QStringList newStoredUrls = storedUrls;
265 newStoredUrls << storedContent->url();
266
267 // every thing has been stored, we update filepath
268 if ( fileNames.isEmpty() )
269 {
270 setFilePaths( newStoredUrls );
271 }
272 else
273 storeExternalFiles( fileNames, newStoredUrls );
274 };
275
276 connect( storedContent, &QgsExternalStorageStoredContent::stored, onStoreFinished );
277 connect( storedContent, &QgsExternalStorageStoredContent::canceled, onStoreFinished );
278 connect( storedContent, &QgsExternalStorageStoredContent::errorOccurred, onStoreFinished );
279
280 storedContent->store();
281}
282
284{
285 const QStringList filePaths = mLineEdit->acceptableFilePaths( event );
286 if ( !filePaths.isEmpty() )
287 {
288 event->acceptProposedAction();
289 }
290 else
291 {
292 event->ignore();
293 }
294}
295
297{
298 storeExternalFiles( mLineEdit->acceptableFilePaths( event ) );
299 event->acceptProposedAction();
300}
@ Finished
Content fetching/storing is finished and successful.
Definition qgis.h:1906
@ Failed
Content fetching/storing has failed.
Definition qgis.h:1907
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...
Handles parsing and evaluation of expressions (formerly called "search strings").
QString expression() const
Returns the original, unmodified expression string.
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 an empty Q...
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.
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...
QgsFileWidget(QWidget *parent=nullptr)
QgsFileWidget creates a widget for selecting a file or a folder.
void setFilePaths(const QStringList &filePaths)
Update filePath according to filePaths list.
QHBoxLayout * mLayout
QString filePath() const
Returns the current file path(s).
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.
void pushWarning(const QString &title, const QString &message)
Pushes a warning message that must be manually dismissed by the user.
#define FILEPATH_VARIABLE
#define QgsDebugError(str)
Definition qgslogger.h:59
Single variable definition for use within a QgsExpressionContextScope.