QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsbinarywidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsbinarywidgetwrapper.cpp
3  -------------------------
4  Date : November 2018
5  Copyright : (C) 2018 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 "qgsbinarywidgetwrapper.h"
17 #include "qgsvectorlayer.h"
18 #include "qgsvectordataprovider.h"
19 #include "qgsfileutils.h"
20 #include "qgsfocuskeeper.h"
21 #include "qgssettings.h"
22 #include "qgsmessagebar.h"
23 #include "qgsapplication.h"
24 #include <QHBoxLayout>
25 #include <QFileDialog>
26 #include <QLabel>
27 #include <QToolButton>
28 #include <QAction>
29 #include <QMenu>
30 #include <QMessageBox>
31 #include <QUrl>
32 
33 QgsBinaryWidgetWrapper::QgsBinaryWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent, QgsMessageBar *messageBar )
34  : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
35  , mMessageBar( messageBar )
36 {
37 }
38 
39 
41 {
42  return mValue.isEmpty() || mValue.isNull() ? QVariant( QVariant::ByteArray ) : mValue;
43 }
44 
46 {
47  if ( mLabel )
48  mLabel->clear();
49 }
50 
52 {
53  if ( mSetAction )
54  mSetAction->setEnabled( enabled );
55  if ( mClearAction )
56  mClearAction->setEnabled( enabled && !mValue.isEmpty() );
57 }
58 
59 QWidget *QgsBinaryWidgetWrapper::createWidget( QWidget *parent )
60 {
61  QWidget *container = new QWidget( parent );
62  QHBoxLayout *layout = new QHBoxLayout();
63  container->setLayout( layout );
64  layout->setContentsMargins( 0, 0, 0, 0 );
65 
66  QLabel *label = new QLabel();
67  layout->addWidget( label, 1 );
68 
69  QToolButton *button = new QToolButton();
70  button->setText( QChar( 0x2026 ) );
71  layout->addWidget( button, 0 );
72 
73  container->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
74  return container;
75 }
76 
77 void QgsBinaryWidgetWrapper::initWidget( QWidget *editor )
78 {
79  mLabel = editor->findChild<QLabel *>();
80  mButton = editor->findChild<QToolButton *>();
81 
82  if ( mLabel )
83  {
84  QFont f = mLabel->font();
85  f.setItalic( true );
86  mLabel->setFont( f );
87  }
88 
89  if ( mButton )
90  {
91  mButton->setPopupMode( QToolButton::InstantPopup );
92 
93  mSetAction = new QAction( tr( "Embed File…" ), mButton );
94  connect( mSetAction, &QAction::triggered, this, &QgsBinaryWidgetWrapper::setContent );
95  mClearAction = new QAction( tr( "Clear Contents…" ), mButton );
96  connect( mClearAction, &QAction::triggered, this, &QgsBinaryWidgetWrapper::clear );
97  mSaveAction = new QAction( tr( "Save Contents to File…" ), mButton );
98  connect( mSaveAction, &QAction::triggered, this, &QgsBinaryWidgetWrapper::saveContent );
99  QMenu *menu = new QMenu( mButton );
100  menu->addAction( mSetAction );
101  menu->addAction( mClearAction );
102  menu->addSeparator();
103  menu->addAction( mSaveAction );
104  mButton->setMenu( menu );
105  }
106 }
107 
109 {
110  return mLabel && mButton;
111 }
112 
113 void QgsBinaryWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
114 {
115  mValue = value.isValid() && !value.isNull() && value.canConvert< QByteArray >() ? value.toByteArray() : QByteArray();
116  if ( mValue.length() == 0 )
117  mValue = QByteArray();
118 
119  if ( mLabel )
120  {
121  if ( !mValue.isEmpty() )
122  {
123  mLabel->setText( tr( "Binary (%1)" ).arg( QgsFileUtils::representFileSize( mValue.size() ) ) );
124  }
125  else
126  {
127  mLabel->setText( QgsApplication::nullRepresentation() );
128  }
129  }
130  if ( mSaveAction )
131  mSaveAction->setEnabled( !mValue.isEmpty() );
132  if ( mClearAction )
133  mClearAction->setEnabled( !mValue.isEmpty() );
134 }
135 
136 void QgsBinaryWidgetWrapper::saveContent()
137 {
138  QgsSettings s;
139 
140  QString file;
141  {
142  QgsFocusKeeper focusKeeper;
143 
144  file = QFileDialog::getSaveFileName( nullptr,
145  tr( "Save Contents to File" ),
146  defaultPath(),
147  tr( "All files" ) + " (*.*)" );
148  }
149  if ( file.isEmpty() )
150  {
151  return;
152  }
153 
154  QFileInfo fi( file );
155  s.setValue( QStringLiteral( "/UI/lastBinaryDir" ), fi.absolutePath() );
156 
157  QFile fileOut( file );
158  fileOut.open( QIODevice::WriteOnly );
159  fileOut.write( mValue );
160  fileOut.close();
161 
162  if ( mMessageBar )
163  mMessageBar->pushSuccess( QString(), tr( "Saved content to <a href=\"%1\">%2</a>" ).arg(
164  QUrl::fromLocalFile( file ).toString(), QDir::toNativeSeparators( file ) ) );
165 }
166 
167 void QgsBinaryWidgetWrapper::setContent()
168 {
169  QgsSettings s;
170 
171  QString file;
172  {
173  QgsFocusKeeper focusKeeper;
174 
175  file = QFileDialog::getOpenFileName( nullptr,
176  tr( "Embed File" ),
177  defaultPath(),
178  tr( "All files" ) + " (*.*)" );
179  }
180 
181  QFileInfo fi( file );
182  if ( file.isEmpty() || !fi.exists() )
183  {
184  return;
185  }
186 
187  s.setValue( QStringLiteral( "/UI/lastBinaryDir" ), fi.absolutePath() );
188 
189  QFile fileSource( file );
190  if ( !fileSource.open( QIODevice::ReadOnly ) )
191  {
192  return;
193  }
194 
195  updateValues( fileSource.readAll() );
197 }
198 
199 void QgsBinaryWidgetWrapper::clear()
200 {
201  {
202  QgsFocusKeeper focusKeeper;
203  if ( QMessageBox::question( nullptr, tr( "Clear Contents" ), tr( "Are you sure you want the clear this field's content?" ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
204  return;
205  }
206 
207  updateValues( QByteArray() );
209 }
210 
211 QString QgsBinaryWidgetWrapper::defaultPath()
212 {
213  return QgsSettings().value( QStringLiteral( "/UI/lastBinaryDir" ), QDir::homePath() ).toString();
214 }
215 
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
QVariant value() const override
Will be used to access the widget's value.
QgsBinaryWidgetWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor=nullptr, QWidget *parent=nullptr, QgsMessageBar *messageBar=nullptr)
Constructor for QgsBinaryWidgetWrapper.
bool valid() const override
Returns true if the widget has been properly initialized.
Manages an editor widget Widget and wrapper share the same parent.
void emitValueChanged()
Will call the value() method to determine the emitted value.
static QString representFileSize(qint64 bytes)
Returns the human size from bytes.
Trick to keep a widget focused and avoid QT crashes.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushSuccess(const QString &title, const QString &message)
Pushes a success message with default timeout to the message bar.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
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.
Represents a vector layer which manages a vector based data sets.