QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 "qgssettings.h"
28 #include "qgsfilterlineedit.h"
29 #include "qgsfocuskeeper.h"
30 #include "qgslogger.h"
31 #include "qgsproject.h"
32 #include "qgsapplication.h"
33 #include "qgsfileutils.h"
34 #include "qgsmimedatautils.h"
35 #include "qgsexternalstorage.h"
37 #include "qgsmessagebar.h"
38 
39 #define FILEPATH_VARIABLE "selected_file_path"
40 
42  : QgsFileWidget( parent )
43 {
44  mProgressLabel = new QLabel( this );
45  mLayout->addWidget( mProgressLabel );
46  mProgressLabel->hide();
47 
48  mProgressBar = new QProgressBar( this );
49  mLayout->addWidget( mProgressBar );
50  mProgressBar->hide();
51 
52  mCancelButton = new QToolButton( this );
53  mLayout->addWidget( mCancelButton );
54  mCancelButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mTaskCancel.svg" ) ) );
55  mCancelButton->hide();
56 
57  updateAcceptDrops();
58 }
59 
60 void QgsExternalStorageFileWidget::setStorageType( const QString &storageType )
61 {
62  if ( storageType.isEmpty() )
63  mExternalStorage = nullptr;
64 
65  else
66  {
68  if ( !mExternalStorage )
69  {
70  QgsDebugMsg( QStringLiteral( "Invalid storage type: %1" ).arg( storageType ) );
71  }
72  else
73  {
75  }
76  }
77 
78  updateAcceptDrops();
79 }
80 
82 {
83  QgsFileWidget::setReadOnly( readOnly );
84  updateAcceptDrops();
85 }
86 
87 void QgsExternalStorageFileWidget::updateAcceptDrops()
88 {
89  setAcceptDrops( !mReadOnly && mExternalStorage );
90 }
91 
93 {
94  return mExternalStorage ? mExternalStorage->type() : QString();
95 }
96 
98 {
99  return mExternalStorage;
100 }
101 
103 {
104  mAuthCfg = authCfg;
105 }
106 
108 {
109  return mAuthCfg;
110 }
111 
112 void QgsExternalStorageFileWidget::setStorageUrlExpression( const QString &urlExpression )
113 {
114  mStorageUrlExpression.reset( new QgsExpression( urlExpression ) );
115 }
116 
118 {
119  return mStorageUrlExpression.get();
120 }
121 
123 {
124  return mStorageUrlExpression ? mStorageUrlExpression->expression() : QString();
125 }
126 
127 
129 {
130  mScope = nullptr; // deleted by old context when we override it with the new one
131  mExpressionContext = context;
133 }
134 
136 {
137  if ( !mExternalStorage || mScope )
138  return;
139 
140  mScope = createFileWidgetScope();
141  mExpressionContext << mScope;
142 }
143 
145 {
146  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "FileWidget" ) );
148  QStringLiteral( FILEPATH_VARIABLE ),
149  QString(), true, false, tr( "User selected absolute filepath" ) ) );
150  return scope;
151 }
152 
154 {
155  return mExpressionContext;
156 }
157 
158 
160 {
161  mMessageBar = messageBar;
162 }
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 ?
186  QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) :
187  QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
188 }
189 
191 {
192  Q_ASSERT( fileNames.count() );
193 
194  // store files first, update filePath later
195  if ( mExternalStorage )
196  {
197  if ( !mStorageUrlExpression->prepare( &mExpressionContext ) )
198  {
199  if ( messageBar() )
200  {
201  messageBar()->pushWarning( tr( "Storing External resource" ),
202  tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
203  }
204 
205  QgsDebugMsg( tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
206  return;
207  }
208 
209  storeExternalFiles( fileNames );
210  }
211  else
212  {
214  }
215 }
216 
217 void 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" ),
238  tr( "Storage URL expression is invalid : %1" ).arg( mStorageUrlExpression->evalErrorString() ) );
239  }
240 
241  mStoreInProgress = false;
242  updateLayout();
243 
244  return;
245  }
246 
247  QgsExternalStorageStoredContent *storedContent = mExternalStorage->store( filePath, url.toString(), mAuthCfg );
248 
249  connect( storedContent, &QgsExternalStorageStoredContent::progressChanged, mProgressBar, &QProgressBar::setValue );
250  connect( mCancelButton, &QToolButton::clicked, storedContent, &QgsExternalStorageStoredContent::cancel );
251 
252  auto onStoreFinished = [ = ]
253  {
254  mStoreInProgress = false;
255  updateLayout();
256  storedContent->deleteLater();
257 
258  if ( storedContent->status() == Qgis::ContentStatus::Failed && messageBar() )
259  {
260  messageBar()->pushWarning( tr( "Storing External resource" ),
261  tr( "Storing file '%1' to url '%2' has failed : %3" ).arg( filePath, url.toString(), storedContent->errorString() ) );
262  }
263 
264  if ( storedContent->status() != Qgis::ContentStatus::Finished )
265  return;
266 
267  QStringList newStoredUrls = storedUrls;
268  newStoredUrls << storedContent->url();
269 
270  // every thing has been stored, we update filepath
271  if ( fileNames.isEmpty() )
272  {
273  setFilePaths( newStoredUrls );
274  }
275  else
276  storeExternalFiles( fileNames, newStoredUrls );
277  };
278 
279  connect( storedContent, &QgsExternalStorageStoredContent::stored, onStoreFinished );
280  connect( storedContent, &QgsExternalStorageStoredContent::canceled, onStoreFinished );
281  connect( storedContent, &QgsExternalStorageStoredContent::errorOccurred, onStoreFinished );
282 
283  storedContent->store();
284 }
285 
286 void QgsExternalStorageFileWidget::dragEnterEvent( QDragEnterEvent *event )
287 {
288  const QStringList filePaths = mLineEdit->acceptableFilePaths( event );
289  if ( !filePaths.isEmpty() )
290  {
291  event->acceptProposedAction();
292  }
293  else
294  {
295  event->ignore();
296  }
297 }
298 
300 {
301  storeExternalFiles( mLineEdit->acceptableFilePaths( event ) );
302  event->acceptProposedAction();
303 }
QgsExternalStorageRegistry::externalStorageFromType
QgsExternalStorage * externalStorageFromType(const QString &type) const
Returns external storage implementation if the storage type matches one.
Definition: qgsexternalstorageregistry.cpp:33
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsExternalStorageFileWidget::setStorageUrlExpression
void setStorageUrlExpression(const QString &urlExpression)
Set urlExpression expression, which once evaluated, provide the URL used to store selected documents.
Definition: qgsexternalstoragefilewidget.cpp:112
QgsExternalStorageFileWidget::createFileWidgetScope
static QgsExpressionContextScope * createFileWidgetScope()
Creates and Returns an expression context scope specific to QgsExternalStorageFileWidget It defines t...
Definition: qgsexternalstoragefilewidget.cpp:144
QgsFileWidget::mIsLinkEdited
bool mIsLinkEdited
Definition: qgsfilewidget.h:330
QgsExternalStorageStoredContent::stored
void stored()
The signal is emitted when the resource has successfully been stored.
FILEPATH_VARIABLE
#define FILEPATH_VARIABLE
Definition: qgsexternalstoragefilewidget.cpp:39
QgsExpressionContextScope::setVariable
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.
Definition: qgsexpressioncontext.cpp:83
QgsExternalStorageFileWidget::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Set expression context to be used when for storage URL expression evaluation.
Definition: qgsexternalstoragefilewidget.cpp:128
Qgis::ContentStatus::Failed
@ Failed
Content fetching/storing has failed.
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:97
QgsFileWidget::mReadOnly
bool mReadOnly
Definition: qgsfilewidget.h:329
QgsExternalStorage::store
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.
Definition: qgsexternalstorage.cpp:35
QgsFileWidget::mLineEdit
QgsFileDropEdit * mLineEdit
Definition: qgsfilewidget.h:341
qgsfilterlineedit.h
qgsmimedatautils.h
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsExternalStorageFileWidget::QgsExternalStorageFileWidget
QgsExternalStorageFileWidget(QWidget *parent=nullptr)
QgsExternalStorageFileWidget creates a widget for selecting a file or a folder.
Definition: qgsexternalstoragefilewidget.cpp:41
qgsapplication.h
qgsexternalstorageregistry.h
QgsExternalStorageFileWidget::externalStorage
QgsExternalStorage * externalStorage() const
Returns external storage used to store selected file names, nullptr if none have been defined.
Definition: qgsexternalstoragefilewidget.cpp:97
QgsExternalStorageFileWidget::storageType
QString storageType
Definition: qgsexternalstoragefilewidget.h:52
qgsfocuskeeper.h
QgsExternalStorageContent::canceled
void canceled()
The signal is emitted when content fetching/storing has been canceled.
QgsFileWidget::mLinkEditButton
QToolButton * mLinkEditButton
Definition: qgsfilewidget.h:342
qgsexternalstorage.h
QgsExternalStorageFileWidget::storageUrlExpressionString
QString storageUrlExpressionString() const
Returns the original, unmodified expression string, which once evaluated, provide the URL used to sto...
Definition: qgsexternalstoragefilewidget.cpp:122
QgsExternalStorageFileWidget::setReadOnly
void setReadOnly(bool readOnly) override
Sets whether the widget should be read only.
Definition: qgsexternalstoragefilewidget.cpp:81
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:60
QgsExternalStorageFileWidget::addFileWidgetScope
void addFileWidgetScope()
Add file widget specific scope to expression context.
Definition: qgsexternalstoragefilewidget.cpp:135
QgsExternalStorageFileWidget::storageUrlExpression
QString storageUrlExpression
Definition: qgsexternalstoragefilewidget.h:54
qgsmessagebar.h
QgsFileWidget::mUseLink
bool mUseLink
Definition: qgsfilewidget.h:327
QgsFileWidget::mFileWidgetButton
QToolButton * mFileWidgetButton
Definition: qgsfilewidget.h:343
QgsFileWidget::mButtonVisible
bool mButtonVisible
Definition: qgsfilewidget.h:326
qgsexternalstoragefilewidget.h
qgsfileutils.h
QgsExternalStorageFileWidget::setMessageBar
void setMessageBar(QgsMessageBar *messageBar)
Set messageBar to report messages.
Definition: qgsexternalstoragefilewidget.cpp:159
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsExternalStorageFileWidget::dragEnterEvent
void dragEnterEvent(QDragEnterEvent *event) override
Definition: qgsexternalstoragefilewidget.cpp:286
QgsExternalStorageStoredContent
Class for QgsExternalStorage stored content.
Definition: qgsexternalstorage.h:200
QgsFileWidget::setFilePaths
void setFilePaths(const QStringList &filePaths)
Update filePath according to filePaths list.
Definition: qgsfilewidget.cpp:385
QgsFileWidget::setReadOnly
virtual void setReadOnly(bool readOnly)
Sets whether the widget should be read only.
Definition: qgsfilewidget.cpp:109
QgsExternalStorageStoredContent::store
virtual void store()=0
Starts storing.
QgsExternalStorageStoredContent::url
virtual QString url() const =0
Returns stored resource URL.
QgsExternalStorageFileWidget::dropEvent
void dropEvent(QDropEvent *event) override
Definition: qgsexternalstoragefilewidget.cpp:299
QgsExternalStorageFileWidget::setSelectedFileNames
void setSelectedFileNames(QStringList fileNames) override
Called whenever user select fileNames from dialog.
Definition: qgsexternalstoragefilewidget.cpp:190
QgsExternalStorage
Abstract interface for external storage - to be implemented by various backends and registered in Qgs...
Definition: qgsexternalstorage.h:36
QgsFileWidget::mLayout
QHBoxLayout * mLayout
Definition: qgsfilewidget.h:344
QgsExternalStorageFileWidget::messageBar
QgsMessageBar * messageBar() const
Returns message bar used to report messages.
Definition: qgsexternalstoragefilewidget.cpp:164
QgsExternalStorageContent::errorOccurred
void errorOccurred(const QString &errorString)
The signal is emitted when an error occurred.
QgsFileWidget::setSelectedFileNames
virtual void setSelectedFileNames(QStringList fileNames)
Called whenever user select fileNames from dialog.
Definition: qgsfilewidget.cpp:372
QgsApplication::externalStorageRegistry
static QgsExternalStorageRegistry * externalStorageRegistry()
Returns registry of available external storage implementations.
Definition: qgsapplication.cpp:2505
qgssettings.h
QgsExternalStorageFileWidget::expressionContext
const QgsExpressionContext & expressionContext() const
Returns expression context used for storage url expression evaluation.
Definition: qgsexternalstoragefilewidget.cpp:153
QgsMessageBar::pushWarning
void pushWarning(const QString &title, const QString &message)
Pushes a warning message that must be manually dismissed by the user.
Definition: qgsmessagebar.cpp:205
QgsExternalStorageFileWidget::setStorageAuthConfigId
void setStorageAuthConfigId(const QString &authCfg)
Sets the authentication configuration ID to be used for the current external storage (if defined)
Definition: qgsexternalstoragefilewidget.cpp:102
QgsExternalStorageFileWidget::updateLayout
void updateLayout() override
Update buttons visibility.
Definition: qgsexternalstoragefilewidget.cpp:169
QgsFileWidget::mLinkLabel
QLabel * mLinkLabel
Definition: qgsfilewidget.h:340
QgsExternalStorageContent::errorString
const QString & errorString() const
Returns error textual description if an error occurred and status() returns Failed.
Definition: qgsexternalstorage.cpp:30
QgsExternalStorageContent::status
Qgis::ContentStatus status() const
Returns content status.
Definition: qgsexternalstorage.cpp:25
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
Qgis::ContentStatus::Finished
@ Finished
Content fetching/storing is finished and successful.
qgslogger.h
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsFileWidget
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:38
QgsExternalStorage::type
virtual QString type() const =0
Unique identifier of the external storage type.
qgsproject.h
QgsExternalStorageFileWidget::storageAuthConfigId
const QString & storageAuthConfigId() const
Returns the authentication configuration ID used for the current external storage (if defined)
Definition: qgsexternalstoragefilewidget.cpp:107
QgsFileWidget::filePath
QString filePath()
Returns the current file path(s).
Definition: qgsfilewidget.cpp:77
QgsExternalStorageContent::progressChanged
void progressChanged(double progress)
The signal is emitted whenever content fetching/storing estimated progression value progress has chan...
QgsExternalStorageContent::cancel
virtual void cancel()
Cancels content fetching/storing.
Definition: qgsexternalstorage.h:132
QgsExternalStorageFileWidget::setStorageType
void setStorageType(const QString &storageType)
Set storageType storage type unique identifier as defined in QgsExternalStorageRegistry or null QStri...
Definition: qgsexternalstoragefilewidget.cpp:60