QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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 <QToolButton>
34#include <QUrl>
35
36#include "moc_qgsexternalstoragefilewidget.cpp"
37
38#define FILEPATH_VARIABLE "selected_file_path"
39
41 : QgsFileWidget( parent )
42{
43 mProgressLabel = new QLabel( this );
44 mLayout->addWidget( mProgressLabel );
45 mProgressLabel->hide();
46
47 mProgressBar = new QProgressBar( this );
48 mLayout->addWidget( mProgressBar );
49 mProgressBar->hide();
50
51 mCancelButton = new QToolButton( this );
52 mLayout->addWidget( mCancelButton );
53 mCancelButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mTaskCancel.svg" ) ) );
54 mCancelButton->hide();
55
56 updateAcceptDrops();
57}
58
60{
61 if ( storageType.isEmpty() )
62 mExternalStorage = nullptr;
63
64 else
65 {
67 if ( !mExternalStorage )
68 {
69 QgsDebugError( QStringLiteral( "Invalid storage type: %1" ).arg( storageType ) );
70 }
71 else
72 {
74 }
75 }
76
77 updateAcceptDrops();
78}
79
81{
83 updateAcceptDrops();
84}
85
86void QgsExternalStorageFileWidget::updateAcceptDrops()
87{
88 setAcceptDrops( !mReadOnly && mExternalStorage );
89}
90
92{
93 return mExternalStorage ? mExternalStorage->type() : QString();
94}
95
97{
98 return mExternalStorage;
99}
100
102{
103 mAuthCfg = authCfg;
104}
105
107{
108 return mAuthCfg;
109}
110
112{
113 mStorageUrlExpression = std::make_unique<QgsExpression>( urlExpression );
114}
115
117{
118 return mStorageUrlExpression.get();
119}
120
122{
123 return mStorageUrlExpression ? mStorageUrlExpression->expression() : QString();
124}
125
126
128{
129 mScope = nullptr; // deleted by old context when we override it with the new one
130 mExpressionContext = context;
132}
133
135{
136 if ( !mExternalStorage || mScope )
137 return;
138
139 mScope = createFileWidgetScope();
140 mExpressionContext << mScope;
141}
142
144{
145 QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "FileWidget" ) );
147 QStringLiteral( FILEPATH_VARIABLE ),
148 QString(), true, false, tr( "User selected absolute filepath" )
149 ) );
150 return scope;
151}
152
154{
155 return mExpressionContext;
156}
157
158
163
165{
166 return mMessageBar;
167}
168
170{
171 mProgressLabel->setVisible( mStoreInProgress );
172 mProgressBar->setVisible( mStoreInProgress );
173 mCancelButton->setVisible( mStoreInProgress );
174
175 const bool linkVisible = mUseLink && !mIsLinkEdited;
176
177 mLineEdit->setVisible( !mStoreInProgress && !linkVisible );
178 mLinkLabel->setVisible( !mStoreInProgress && linkVisible );
179 mLinkEditButton->setVisible( !mStoreInProgress && mUseLink && !mReadOnly );
180
181 mFileWidgetButton->setVisible( mButtonVisible && !mStoreInProgress );
182 mFileWidgetButton->setEnabled( !mReadOnly );
183 mLineEdit->setEnabled( !mReadOnly );
184
185 mLinkEditButton->setIcon( linkVisible && !mReadOnly ? QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) : QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
186}
187
189{
190 Q_ASSERT( fileNames.count() );
191
192 // store files first, update filePath later
193 if ( mExternalStorage )
194 {
195 if ( !mStorageUrlExpression->prepare( &mExpressionContext ) )
196 {
197 if ( messageBar() )
198 {
199 messageBar()->pushWarning( tr( "Storing External resource" ), tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
200 }
201
202 QgsDebugError( QStringLiteral( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
203 return;
204 }
205
206 storeExternalFiles( fileNames );
207 }
208 else
209 {
211 }
212}
213
214void QgsExternalStorageFileWidget::storeExternalFiles( QStringList fileNames, QStringList storedUrls )
215{
216 if ( fileNames.isEmpty() )
217 return;
218
219 const QString filePath = fileNames.takeFirst();
220
221 mProgressLabel->setText( tr( "Storing file %1 ..." ).arg( QFileInfo( filePath ).fileName() ) );
222 mStoreInProgress = true;
223 mProgressBar->setValue( 0 );
224 updateLayout();
225
226 Q_ASSERT( mScope );
227 mScope->setVariable( QStringLiteral( FILEPATH_VARIABLE ), filePath );
228
229 QVariant url = mStorageUrlExpression->evaluate( &mExpressionContext );
230 if ( !url.isValid() )
231 {
232 if ( messageBar() )
233 {
234 messageBar()->pushWarning( tr( "Storing External resource" ), tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
235 }
236
237 mStoreInProgress = false;
238 updateLayout();
239
240 return;
241 }
242
243 QgsExternalStorageStoredContent *storedContent = mExternalStorage->store( filePath, url.toString(), mAuthCfg );
244
245 connect( storedContent, &QgsExternalStorageStoredContent::progressChanged, mProgressBar, &QProgressBar::setValue );
246 connect( mCancelButton, &QToolButton::clicked, storedContent, &QgsExternalStorageStoredContent::cancel );
247
248 auto onStoreFinished = [this, storedContent, fileNames, storedUrls, filePath, url] {
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" ), tr( "Storing file '%1' to url '%2' has failed : %3" ).arg( filePath, url.toString(), storedContent->errorString() ) );
256 }
257
258 if ( storedContent->status() != Qgis::ContentStatus::Finished )
259 return;
260
261 QStringList newStoredUrls = storedUrls;
262 newStoredUrls << storedContent->url();
263
264 // every thing has been stored, we update filepath
265 if ( fileNames.isEmpty() )
266 {
267 setFilePaths( newStoredUrls );
268 }
269 else
270 storeExternalFiles( fileNames, newStoredUrls );
271 };
272
273 connect( storedContent, &QgsExternalStorageStoredContent::stored, onStoreFinished );
274 connect( storedContent, &QgsExternalStorageStoredContent::canceled, onStoreFinished );
275 connect( storedContent, &QgsExternalStorageStoredContent::errorOccurred, onStoreFinished );
276
277 storedContent->store();
278}
279
281{
282 const QStringList filePaths = mLineEdit->acceptableFilePaths( event );
283 if ( !filePaths.isEmpty() )
284 {
285 event->acceptProposedAction();
286 }
287 else
288 {
289 event->ignore();
290 }
291}
292
294{
295 storeExternalFiles( mLineEdit->acceptableFilePaths( event ) );
296 event->acceptProposedAction();
297}
@ Finished
Content fetching/storing is finished and successful.
Definition qgis.h:1848
@ Failed
Content fetching/storing has failed.
Definition qgis.h:1849
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:57
Single variable definition for use within a QgsExpressionContextScope.