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