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