QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsfilecontentsourcelineedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfilecontentsourcelineedit.cpp
3  -----------------------
4  begin : July 2018
5  copyright : (C) 2018 by Nyall Dawson
6  email : nyall dot dawson at gmail 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 #include "qgssettings.h"
18 #include "qgsmessagebar.h"
19 #include "qgsfilterlineedit.h"
20 #include <QMenu>
21 #include <QLineEdit>
22 #include <QToolButton>
23 #include <QHBoxLayout>
24 #include <QFileDialog>
25 #include <QInputDialog>
26 
27 //
28 // QgsAbstractFileContentSourceLineEdit
29 //
30 
32  : QWidget( parent )
33 {
34  QHBoxLayout *layout = new QHBoxLayout( this );
35  mFileLineEdit = new QgsFilterLineEdit( this );
36  mFileLineEdit->setShowClearButton( true );
37  mFileToolButton = new QToolButton( this );
38  mFileToolButton->setText( tr( "…" ) );
39  layout->addWidget( mFileLineEdit, 1 );
40  layout->addWidget( mFileToolButton );
41  setLayout( layout );
42 
43  QMenu *sourceMenu = new QMenu( mFileToolButton );
44 
45  QAction *selectFileAction = new QAction( tr( "Select File…" ), sourceMenu );
46  connect( selectFileAction, &QAction::triggered, this, &QgsAbstractFileContentSourceLineEdit::selectFile );
47  sourceMenu->addAction( selectFileAction );
48 
49  QAction *embedFileAction = new QAction( tr( "Embed File…" ), sourceMenu );
50  connect( embedFileAction, &QAction::triggered, this, &QgsAbstractFileContentSourceLineEdit::embedFile );
51  sourceMenu->addAction( embedFileAction );
52 
53  QAction *extractFileAction = new QAction( tr( "Extract Embedded File…" ), sourceMenu );
54  connect( extractFileAction, &QAction::triggered, this, &QgsAbstractFileContentSourceLineEdit::extractFile );
55  sourceMenu->addAction( extractFileAction );
56 
57  connect( sourceMenu, &QMenu::aboutToShow, this, [this, extractFileAction]
58  {
59  extractFileAction->setEnabled( mMode == ModeBase64 );
60  } );
61 
62  QAction *enterUrlAction = new QAction( tr( "From URL…" ), sourceMenu );
63  connect( enterUrlAction, &QAction::triggered, this, &QgsAbstractFileContentSourceLineEdit::selectUrl );
64  sourceMenu->addAction( enterUrlAction );
65 
66  mFileToolButton->setMenu( sourceMenu );
67  mFileToolButton->setPopupMode( QToolButton::MenuButtonPopup );
68  connect( mFileToolButton, &QToolButton::clicked, this, &QgsAbstractFileContentSourceLineEdit::selectFile );
69 
70  connect( mFileLineEdit, &QLineEdit::textEdited, this, &QgsAbstractFileContentSourceLineEdit::mFileLineEdit_textEdited );
71  connect( mFileLineEdit, &QgsFilterLineEdit::cleared, this, [ = ]
72  {
73  mMode = ModeFile;
74  mFileLineEdit->setPlaceholderText( QString() );
75  mBase64.clear();
76  emit sourceChanged( QString() );
77  } );
78 
79 }
80 
82 {
83  switch ( mMode )
84  {
85  case ModeFile:
86  return mFileLineEdit->text();
87 
88  case ModeBase64:
89  return mBase64;
90  }
91 
92  return QString();
93 }
94 
96 {
97  mLastPathKey = key;
98 }
99 
101 {
102  const bool isBase64 = source.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive );
103 
104  if ( ( !isBase64 && source == mFileLineEdit->text() && mBase64.isEmpty() ) || ( isBase64 && source == mBase64 ) )
105  return;
106 
107  if ( isBase64 )
108  {
109  mMode = ModeBase64;
110  mBase64 = source;
111  mFileLineEdit->clear();
112  mFileLineEdit->setPlaceholderText( tr( "Embedded file" ) );
113  }
114  else
115  {
116  mMode = ModeFile;
117  mBase64.clear();
118  mFileLineEdit->setText( source );
119  mFileLineEdit->setPlaceholderText( QString() );
120  }
121 
122  emit sourceChanged( source );
123 }
124 
125 void QgsAbstractFileContentSourceLineEdit::selectFile()
126 {
127  QgsSettings s;
128  QString file = QFileDialog::getOpenFileName( nullptr,
129  selectFileTitle(),
130  defaultPath(),
131  fileFilter() );
132  QFileInfo fi( file );
133  if ( file.isEmpty() || !fi.exists() || file == source() )
134  {
135  return;
136  }
137  mMode = ModeFile;
138  mBase64.clear();
139  mFileLineEdit->setText( file );
140  mFileLineEdit->setPlaceholderText( QString() );
141  s.setValue( settingsKey(), fi.absolutePath() );
142  emit sourceChanged( mFileLineEdit->text() );
143 }
144 
145 void QgsAbstractFileContentSourceLineEdit::selectUrl()
146 {
147  bool ok = false;
148  const QString path = QInputDialog::getText( this, fileFromUrlTitle(), fileFromUrlText(), QLineEdit::Normal, mFileLineEdit->text(), &ok );
149  if ( ok && path != source() )
150  {
151  mMode = ModeFile;
152  mBase64.clear();
153  mFileLineEdit->setText( path );
154  mFileLineEdit->setPlaceholderText( QString() );
155  emit sourceChanged( mFileLineEdit->text() );
156  }
157 }
158 
159 void QgsAbstractFileContentSourceLineEdit::embedFile()
160 {
161  QgsSettings s;
162  QString file = QFileDialog::getOpenFileName( nullptr,
163  embedFileTitle(),
164  defaultPath(),
165  fileFilter() );
166  QFileInfo fi( file );
167  if ( file.isEmpty() || !fi.exists() )
168  {
169  return;
170  }
171 
172  s.setValue( settingsKey(), fi.absolutePath() );
173 
174  // encode file as base64
175  QFile fileSource( file );
176  if ( !fileSource.open( QIODevice::ReadOnly ) )
177  {
178  return;
179  }
180 
181  QByteArray blob = fileSource.readAll();
182  QByteArray encoded = blob.toBase64();
183 
184  QString path( encoded );
185  path.prepend( QLatin1String( "base64:" ) );
186  if ( path == source() )
187  return;
188 
189  mBase64 = path;
190  mMode = ModeBase64;
191 
192  mFileLineEdit->clear();
193  mFileLineEdit->setPlaceholderText( tr( "Embedded file" ) );
194 
195  emit sourceChanged( path );
196 }
197 
198 void QgsAbstractFileContentSourceLineEdit::extractFile()
199 {
200  QgsSettings s;
201  QString file = QFileDialog::getSaveFileName( nullptr,
202  extractFileTitle(),
203  defaultPath(),
204  fileFilter() );
205  if ( file.isEmpty() )
206  {
207  return;
208  }
209 
210  QFileInfo fi( file );
211  s.setValue( settingsKey(), fi.absolutePath() );
212 
213  // decode current base64 embedded file
214  QByteArray base64 = mBase64.mid( 7 ).toLocal8Bit(); // strip 'base64:' prefix
215  QByteArray decoded = QByteArray::fromBase64( base64, QByteArray::OmitTrailingEquals );
216 
217  QFile fileOut( file );
218  fileOut.open( QIODevice::WriteOnly );
219  fileOut.write( decoded );
220  fileOut.close();
221 
222  if ( mMessageBar )
223  {
224  mMessageBar->pushMessage( extractFileTitle(),
225  tr( "Successfully extracted file to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( file ).toString(), QDir::toNativeSeparators( file ) ),
226  Qgis::Success, 0 );
227  }
228 }
229 
230 void QgsAbstractFileContentSourceLineEdit::mFileLineEdit_textEdited( const QString &text )
231 {
232  mFileLineEdit->setPlaceholderText( QString() );
233  mBase64.clear();
234  mMode = ModeFile;
235  if ( !text.isEmpty() && !QFileInfo::exists( text ) )
236  {
237  QUrl url( text );
238  if ( !url.isValid() )
239  {
240  return;
241  }
242  }
243  emit sourceChanged( text );
244 }
245 
246 QString QgsAbstractFileContentSourceLineEdit::defaultPath() const
247 {
248  if ( QFileInfo::exists( source() ) )
249  return source();
250 
251  return QgsSettings().value( settingsKey(), QDir::homePath() ).toString();
252 }
253 
254 QString QgsAbstractFileContentSourceLineEdit::settingsKey() const
255 {
256  return mLastPathKey.isEmpty() ? defaultSettingsKey() : mLastPathKey;
257 }
258 
259 //
260 // QgsSvgSourceLineEdit
261 //
262 
264 
265 QString QgsSvgSourceLineEdit::fileFilter() const
266 {
267  return tr( "SVG files" ) + " (*.svg)";
268 }
269 
270 QString QgsSvgSourceLineEdit::selectFileTitle() const
271 {
272  return tr( "Select SVG File" );
273 }
274 
275 QString QgsSvgSourceLineEdit::fileFromUrlTitle() const
276 {
277  return tr( "SVG From URL" );
278 }
279 
280 QString QgsSvgSourceLineEdit::fileFromUrlText() const
281 {
282  return tr( "Enter SVG URL" );
283 }
284 
285 QString QgsSvgSourceLineEdit::embedFileTitle() const
286 {
287  return tr( "Embed SVG File" );
288 }
289 
290 QString QgsSvgSourceLineEdit::extractFileTitle() const
291 {
292  return tr( "Extract SVG File" );
293 }
294 
295 QString QgsSvgSourceLineEdit::defaultSettingsKey() const
296 {
297  return QStringLiteral( "/UI/lastSVGDir" );
298 }
300 
301 //
302 // QgsImageSourceLineEdit
303 //
304 
306 
307 QString QgsImageSourceLineEdit::fileFilter() const
308 {
309  return tr( "All files" ) + " (*.*)";
310 }
311 
312 QString QgsImageSourceLineEdit::selectFileTitle() const
313 {
314  return tr( "Select Image File" );
315 }
316 
317 QString QgsImageSourceLineEdit::fileFromUrlTitle() const
318 {
319  return tr( "Image From URL" );
320 }
321 
322 QString QgsImageSourceLineEdit::fileFromUrlText() const
323 {
324  return tr( "Enter image URL" );
325 }
326 
327 QString QgsImageSourceLineEdit::embedFileTitle() const
328 {
329  return tr( "Embed Image File" );
330 }
331 
332 QString QgsImageSourceLineEdit::extractFileTitle() const
333 {
334  return tr( "Extract Image File" );
335 }
336 
337 QString QgsImageSourceLineEdit::defaultSettingsKey() const
338 {
339  return QStringLiteral( "/UI/lastImageDir" );
340 }
341 
343 
345 {
346  mMessageBar = bar;
347 }
348 
350 {
351  return mMessageBar;
352 }
QgsAbstractFileContentSourceLineEdit(QWidget *parent=nullptr)
Constructor for QgsAbstractFileContentSourceLineEdit, with the specified parent widget.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setSource(const QString &source)
Sets a new source to show in the widget.
void setLastPathSettingsKey(const QString &key)
Sets a specific settings key to use when storing the last used path for the file source.
void sourceChanged(const QString &source)
Emitted whenever the file source is changed in the widget.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=5)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:88
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void cleared()
Emitted when the widget is cleared.
void setShowClearButton(bool visible)
Sets whether the widget&#39;s clear button is visible.
QString source() const
Returns the current file source.