QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgssvgsourcelineedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssvgsourcelineedit.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 
16 #include "qgssvgsourcelineedit.h"
17 #include "qgssettings.h"
18 #include <QMenu>
19 #include <QLineEdit>
20 #include <QToolButton>
21 #include <QHBoxLayout>
22 #include <QFileDialog>
23 #include <QInputDialog>
24 
26  : QWidget( parent )
27 {
28  QHBoxLayout *layout = new QHBoxLayout( this );
29  mFileLineEdit = new QLineEdit( this );
30  mFileToolButton = new QToolButton( this );
31  mFileToolButton->setText( tr( "…" ) );
32  layout->addWidget( mFileLineEdit, 1 );
33  layout->addWidget( mFileToolButton );
34  setLayout( layout );
35 
36  QMenu *sourceMenu = new QMenu( mFileToolButton );
37 
38  QAction *selectFileAction = new QAction( tr( "Select File…" ), sourceMenu );
39  connect( selectFileAction, &QAction::triggered, this, &QgsSvgSourceLineEdit::selectFile );
40  sourceMenu->addAction( selectFileAction );
41 
42  QAction *embedFileAction = new QAction( tr( "Embed File…" ), sourceMenu );
43  connect( embedFileAction, &QAction::triggered, this, &QgsSvgSourceLineEdit::embedFile );
44  sourceMenu->addAction( embedFileAction );
45 
46  QAction *extractFileAction = new QAction( tr( "Extract Embedded File…" ), sourceMenu );
47  connect( extractFileAction, &QAction::triggered, this, &QgsSvgSourceLineEdit::extractFile );
48  sourceMenu->addAction( extractFileAction );
49 
50  connect( sourceMenu, &QMenu::aboutToShow, this, [this, extractFileAction]
51  {
52  extractFileAction->setEnabled( mFileLineEdit->text().startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) );
53  } );
54 
55  QAction *enterUrlAction = new QAction( tr( "From URL…" ), sourceMenu );
56  connect( enterUrlAction, &QAction::triggered, this, &QgsSvgSourceLineEdit::selectUrl );
57  sourceMenu->addAction( enterUrlAction );
58 
59  mFileToolButton->setMenu( sourceMenu );
60  mFileToolButton->setPopupMode( QToolButton::MenuButtonPopup );
61  connect( mFileToolButton, &QToolButton::clicked, this, &QgsSvgSourceLineEdit::selectFile );
62 
63  connect( mFileLineEdit, &QLineEdit::textEdited, this, &QgsSvgSourceLineEdit::mFileLineEdit_textEdited );
64  connect( mFileLineEdit, &QLineEdit::editingFinished, this, &QgsSvgSourceLineEdit::mFileLineEdit_editingFinished );
65 }
66 
67 QString QgsSvgSourceLineEdit::source() const
68 {
69  return mBase64.isEmpty() ? mFileLineEdit->text() : mBase64;
70 }
71 
73 {
74  mLastPathKey = key;
75 }
76 
78 {
79  const bool isBase64 = source.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive );
80 
81  if ( ( !isBase64 && source == mFileLineEdit->text() ) || ( isBase64 && source == mBase64 ) )
82  return;
83 
84  if ( isBase64 )
85  mBase64 = source;
86  else
87  mBase64.clear();
88 
89  mFileLineEdit->setText( source );
90  emit sourceChanged( source );
91 }
92 
93 void QgsSvgSourceLineEdit::selectFile()
94 {
95  QgsSettings s;
96  QString file = QFileDialog::getOpenFileName( nullptr,
97  tr( "Select SVG file" ),
98  defaultPath(),
99  tr( "SVG files" ) + " (*.svg)" );
100  QFileInfo fi( file );
101  if ( file.isEmpty() || !fi.exists() || file == source() )
102  {
103  return;
104  }
105  mBase64.clear();
106  mFileLineEdit->setText( file );
107  s.setValue( settingsKey(), fi.absolutePath() );
108  emit sourceChanged( mFileLineEdit->text() );
109 }
110 
111 void QgsSvgSourceLineEdit::selectUrl()
112 {
113  bool ok = false;
114  const QString path = QInputDialog::getText( this, tr( "SVG From URL" ), tr( "Enter SVG URL" ), QLineEdit::Normal, mFileLineEdit->text(), &ok );
115  if ( ok && path != source() )
116  {
117  mBase64.clear();
118  mFileLineEdit->setText( path );
119  emit sourceChanged( mFileLineEdit->text() );
120  }
121 }
122 
123 void QgsSvgSourceLineEdit::embedFile()
124 {
125  QgsSettings s;
126  QString file = QFileDialog::getOpenFileName( nullptr,
127  tr( "Embed SVG File" ),
128  defaultPath(),
129  tr( "SVG files" ) + " (*.svg)" );
130  QFileInfo fi( file );
131  if ( file.isEmpty() || !fi.exists() )
132  {
133  return;
134  }
135 
136  s.setValue( settingsKey(), fi.absolutePath() );
137 
138  // encode file as base64
139  QFile fileSource( file );
140  if ( !fileSource.open( QIODevice::ReadOnly ) )
141  {
142  return;
143  }
144 
145  QByteArray blob = fileSource.readAll();
146  QByteArray encoded = blob.toBase64();
147 
148  QString path( encoded );
149  path.prepend( QLatin1String( "base64:" ) );
150  if ( path == source() )
151  return;
152 
153  mBase64 = path;
154  mFileLineEdit->setText( path );
155  emit sourceChanged( path );
156 }
157 
158 void QgsSvgSourceLineEdit::extractFile()
159 {
160  QgsSettings s;
161  QString file = QFileDialog::getSaveFileName( nullptr,
162  tr( "Extract SVG File" ),
163  defaultPath(),
164  tr( "SVG files" ) + " (*.svg)" );
165  if ( file.isEmpty() )
166  {
167  return;
168  }
169 
170  QFileInfo fi( file );
171  s.setValue( settingsKey(), fi.absolutePath() );
172 
173  // decode current base64 embedded file
174  QString path = mFileLineEdit->text().trimmed();
175  if ( path.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) )
176  {
177  QByteArray base64 = mBase64.mid( 7 ).toLocal8Bit(); // strip 'base64:' prefix
178  QByteArray decoded = QByteArray::fromBase64( base64, QByteArray::OmitTrailingEquals );
179 
180  QFile fileOut( file );
181  fileOut.open( QIODevice::WriteOnly );
182  fileOut.write( decoded );
183  fileOut.close();
184  }
185 }
186 
187 void QgsSvgSourceLineEdit::mFileLineEdit_textEdited( const QString &text )
188 {
189  if ( !QFileInfo::exists( text ) )
190  {
191  return;
192  }
193  emit sourceChanged( text );
194 }
195 
196 void QgsSvgSourceLineEdit::mFileLineEdit_editingFinished()
197 {
198  if ( !QFileInfo::exists( mFileLineEdit->text() ) )
199  {
200  QUrl url( mFileLineEdit->text() );
201  if ( !url.isValid() )
202  {
203  return;
204  }
205  }
206 
207  emit sourceChanged( mFileLineEdit->text() );
208 }
209 
210 QString QgsSvgSourceLineEdit::defaultPath() const
211 {
212  if ( QFileInfo::exists( source() ) )
213  return source();
214 
215  return QgsSettings().value( settingsKey(), QDir::homePath() ).toString();
216 }
217 
218 QString QgsSvgSourceLineEdit::settingsKey() const
219 {
220  return mLastPathKey.isEmpty() ? QStringLiteral( "/UI/lastSVGDir" ) : mLastPathKey;
221 }
222 
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QString source() const
Returns the current SVG source.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QgsSvgSourceLineEdit(QWidget *parent=nullptr)
Constructor for QgsSvgSourceLineEdit, with the specified parent widget.
void setSource(const QString &source)
Sets a new source to show in the widget.
void sourceChanged(const QString &source)
Emitted whenever the SVG source is changed in the widget.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setLastPathSettingsKey(const QString &key)
Sets a specific settings key to use when storing the last used path for the SVG source.