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