QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgstexteditwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstexteditwrapper.cpp
3  --------------------------------------
4  Date : 5.1.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias at opengis dot ch
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 "qgstexteditwrapper.h"
17 
18 #include "qgsfields.h"
19 #include "qgsfieldvalidator.h"
20 #include "qgsfilterlineedit.h"
21 #include "qgsapplication.h"
22 
23 #include <QSettings>
24 
25 QgsTextEditWrapper::QgsTextEditWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
26  : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
27 
28 {
29 }
30 
31 QVariant QgsTextEditWrapper::value() const
32 {
33  QString v;
34 
35  if ( mTextEdit )
36  {
37  if ( config( QStringLiteral( "UseHtml" ) ).toBool() )
38  {
39  v = mTextEdit->toHtml();
40  }
41  else
42  {
43  v = mTextEdit->toPlainText();
44  }
45  }
46 
47  if ( mPlainTextEdit )
48  {
49  v = mPlainTextEdit->toPlainText();
50  }
51 
52  if ( mLineEdit )
53  {
54  v = mLineEdit->text();
55  }
56 
57  if ( ( v.isEmpty() && ( field().type() == QVariant::Int || field().type() == QVariant::Double || field().type() == QVariant::LongLong || field().type() == QVariant::Date ) ) ||
59  return QVariant( field().type() );
60 
61  if ( !defaultValue().isNull() && v == defaultValue().toString() )
62  {
63  return defaultValue();
64  }
65 
66  QVariant res( v );
67  if ( field().convertCompatible( res ) )
68  {
69  return res;
70  }
71  else if ( field().type() == QVariant::String && field().length() > 0 )
72  {
73  // for string fields convertCompatible may return false due to field length limit - in this case just truncate
74  // input rather then discarding it entirely
75  return QVariant( v.left( field().length() ) );
76  }
77  else
78  {
79  return QVariant( field().type() );
80  }
81 }
82 
83 QWidget *QgsTextEditWrapper::createWidget( QWidget *parent )
84 {
85  if ( config( QStringLiteral( "IsMultiline" ) ).toBool() )
86  {
87  if ( config( QStringLiteral( "UseHtml" ) ).toBool() )
88  {
89  return new QTextBrowser( parent );
90  }
91  else
92  {
93  return new QPlainTextEdit( parent );
94  }
95  }
96  else
97  {
98  return new QgsFilterLineEdit( parent );
99  }
100 }
101 
102 void QgsTextEditWrapper::initWidget( QWidget *editor )
103 {
104  mTextBrowser = qobject_cast<QTextBrowser *>( editor );
105  mTextEdit = qobject_cast<QTextEdit *>( editor );
106  mPlainTextEdit = qobject_cast<QPlainTextEdit *>( editor );
107  mLineEdit = qobject_cast<QLineEdit *>( editor );
108 
109  if ( mTextEdit )
110  connect( mTextEdit, &QTextEdit::textChanged, this, &QgsEditorWidgetWrapper::emitValueChanged );
111 
112  if ( mPlainTextEdit )
113  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, &QgsEditorWidgetWrapper::emitValueChanged );
114 
115  if ( mLineEdit )
116  {
117  mLineEdit->setValidator( new QgsFieldValidator( mLineEdit, field(), defaultValue().toString() ) );
118 
119  QVariant defVal = defaultValue();
120  if ( defVal.isNull() )
121  {
123  }
124 
125  QgsFilterLineEdit *fle = qobject_cast<QgsFilterLineEdit *>( mLineEdit );
126  if ( field().type() == QVariant::Int || field().type() == QVariant::Double || field().type() == QVariant::LongLong || field().type() == QVariant::Date )
127  {
128  mPlaceholderText = defVal.toString();
129  mLineEdit->setPlaceholderText( mPlaceholderText );
130  }
131  else if ( fle )
132  {
133  fle->setNullValue( defVal.toString() );
134  }
135 
136  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & value ) { emit valueChanged( value ); } );
137  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsTextEditWrapper::textChanged );
138 
139  mWritablePalette = mLineEdit->palette();
140  mReadOnlyPalette = mLineEdit->palette();
141  }
142 }
143 
145 {
146  return mLineEdit || mTextEdit || mPlainTextEdit;
147 }
148 
150 {
151  //note - this is deliberately a zero length string, not a null string!
152  if ( mTextEdit )
153  mTextEdit->blockSignals( true );
154  if ( mPlainTextEdit )
155  mPlainTextEdit->blockSignals( true );
156  if ( mLineEdit )
157  {
158  mLineEdit->blockSignals( true );
159  // for interdeminate state we need to clear the placeholder text - we want an empty line edit, not
160  // one showing the default value (e.g., "NULL")
161  mLineEdit->setPlaceholderText( QString() );
162  }
163 
164  setWidgetValue( QString() );
165 
166  if ( mTextEdit )
167  mTextEdit->blockSignals( false );
168  if ( mPlainTextEdit )
169  mPlainTextEdit->blockSignals( false );
170  if ( mLineEdit )
171  mLineEdit->blockSignals( false );
172 }
173 
174 void QgsTextEditWrapper::setValue( const QVariant &val )
175 {
176  if ( mLineEdit )
177  {
178  //restore placeholder text, which may have been removed by showIndeterminateState()
179  mLineEdit->setPlaceholderText( mPlaceholderText );
180  }
181  setWidgetValue( val );
182 }
183 
184 void QgsTextEditWrapper::setEnabled( bool enabled )
185 {
186  if ( mTextEdit )
187  mTextEdit->setReadOnly( !enabled );
188 
189  if ( mPlainTextEdit )
190  mPlainTextEdit->setReadOnly( !enabled );
191 
192  if ( mLineEdit )
193  {
194  mLineEdit->setReadOnly( !enabled );
195  if ( enabled )
196  mLineEdit->setPalette( mWritablePalette );
197  else
198  {
199  mLineEdit->setPalette( mReadOnlyPalette );
200  // removing frame + setting transparent background to distinguish the readonly lineEdit from a normal one
201  // did not get this working via the Palette:
202  mLineEdit->setStyleSheet( QStringLiteral( "background-color: rgba(255, 255, 255, 75%);" ) );
203  }
204  mLineEdit->setFrame( enabled );
205  }
206 }
207 
208 void QgsTextEditWrapper::textChanged( const QString & )
209 {
210  if ( mLineEdit )
211  {
212  //restore placeholder text, which may have been removed by showIndeterminateState()
213  mLineEdit->setPlaceholderText( mPlaceholderText );
214  }
215 }
216 
217 void QgsTextEditWrapper::setWidgetValue( const QVariant &val )
218 {
219  QString v;
220  if ( val.isNull() )
221  {
222  if ( !( field().type() == QVariant::Int || field().type() == QVariant::Double || field().type() == QVariant::LongLong || field().type() == QVariant::Date ) )
224  }
225  else
226  {
227  v = field().displayString( val );
228  }
229 
230  // For numbers, remove the group separator that might cause validation errors
231  // when the user is editing the field value.
232  // We are checking for editable layer because in the form field context we do not
233  // want to strip the separator unless the layer is editable.
234  // Also check that we have something like a number in the value to avoid
235  // stripping out dots from nextval when we have a schema: see https://github.com/qgis/QGIS/issues/28021
236  // "Wrong sequence detection with Postgres"
237  bool canConvertToDouble;
238  QLocale().toDouble( v, &canConvertToDouble );
239  if ( canConvertToDouble && layer() && layer()->isEditable() && ! QLocale().groupSeparator().isNull() && field().isNumeric() )
240  {
241  v = v.remove( QLocale().groupSeparator() );
242  }
243 
244  if ( mTextEdit )
245  {
246  if ( val != value() )
247  {
248  if ( config( QStringLiteral( "UseHtml" ) ).toBool() )
249  {
250  mTextEdit->setHtml( v );
251  if ( mTextBrowser )
252  {
253  mTextBrowser->setTextInteractionFlags( Qt::LinksAccessibleByMouse );
254  mTextBrowser->setOpenExternalLinks( true );
255  }
256  }
257  else
258  mTextEdit->setPlainText( v );
259  }
260  }
261 
262  if ( mPlainTextEdit )
263  {
264  if ( val != value() )
265  mPlainTextEdit->setPlainText( v );
266  }
267 
268  if ( mLineEdit )
269  mLineEdit->setText( v );
270 }
271 
272 void QgsTextEditWrapper::setHint( const QString &hintText )
273 {
274  if ( hintText.isNull() )
275  mPlaceholderText = mPlaceholderTextBackup;
276  else
277  {
278  mPlaceholderTextBackup = mPlaceholderText;
279  mPlaceholderText = hintText;
280  }
281 
282  mLineEdit->setPlaceholderText( mPlaceholderText );
283 }
void setEnabled(bool enabled) override
void emitValueChanged()
Will call the value() method to determine the emitted value.
QgsField field() const
Access the field.
Manages an editor widget Widget and wrapper share the same parent.
QgsTextEditWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor=nullptr, QWidget *parent=nullptr)
Constructor for QgsTextEditWrapper.
QVariantMap config() const
Returns the whole config.
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
QVariant value() const override
Will be used to access the widget&#39;s value.
QVariant defaultValue() const
Access the default value of the field.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QString displayString(const QVariant &v) const
Formats string for display.
Definition: qgsfield.cpp:211
bool valid() const override
Returns true if the widget has been properly initialized.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void setValue(const QVariant &value) override
void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
void setNullValue(const QString &nullValue)
Sets the string representation for null values in the widget.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Represents a vector layer which manages a vector based data sets.
QVariant::Type type
Definition: qgsfield.h:56
void setHint(const QString &hintText) override
Add a hint text on the widget.