QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 )
137  {
139  emit valueChanged( value );
141  emit valuesChanged( value );
142  } );
143  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsTextEditWrapper::textChanged );
144 
145  mWritablePalette = mLineEdit->palette();
146  mReadOnlyPalette = mLineEdit->palette();
147  }
148 }
149 
151 {
152  return mLineEdit || mTextEdit || mPlainTextEdit;
153 }
154 
156 {
157  //note - this is deliberately a zero length string, not a null string!
158  if ( mTextEdit )
159  mTextEdit->blockSignals( true );
160  if ( mPlainTextEdit )
161  mPlainTextEdit->blockSignals( true );
162  if ( mLineEdit )
163  {
164  mLineEdit->blockSignals( true );
165  // for interdeminate state we need to clear the placeholder text - we want an empty line edit, not
166  // one showing the default value (e.g., "NULL")
167  mLineEdit->setPlaceholderText( QString() );
168  }
169 
170  setWidgetValue( QString() );
171 
172  if ( mTextEdit )
173  mTextEdit->blockSignals( false );
174  if ( mPlainTextEdit )
175  mPlainTextEdit->blockSignals( false );
176  if ( mLineEdit )
177  mLineEdit->blockSignals( false );
178 }
179 
180 void QgsTextEditWrapper::updateValues( const QVariant &val, const QVariantList & )
181 {
182  if ( mLineEdit )
183  {
184  //restore placeholder text, which may have been removed by showIndeterminateState()
185  mLineEdit->setPlaceholderText( mPlaceholderText );
186  }
187  setWidgetValue( val );
188 }
189 
190 void QgsTextEditWrapper::setEnabled( bool enabled )
191 {
192  if ( mTextEdit )
193  mTextEdit->setReadOnly( !enabled );
194 
195  if ( mPlainTextEdit )
196  mPlainTextEdit->setReadOnly( !enabled );
197 
198  if ( mLineEdit )
199  {
200  mLineEdit->setReadOnly( !enabled );
201  if ( enabled )
202  mLineEdit->setPalette( mWritablePalette );
203  else
204  {
205  mLineEdit->setPalette( mReadOnlyPalette );
206  // removing frame + setting transparent background to distinguish the readonly lineEdit from a normal one
207  // did not get this working via the Palette:
208  mLineEdit->setStyleSheet( QStringLiteral( "background-color: rgba(255, 255, 255, 75%);" ) );
209  }
210  mLineEdit->setFrame( enabled );
211  }
212 }
213 
214 void QgsTextEditWrapper::textChanged( const QString & )
215 {
216  if ( mLineEdit )
217  {
218  //restore placeholder text, which may have been removed by showIndeterminateState()
219  mLineEdit->setPlaceholderText( mPlaceholderText );
220  }
221 }
222 
223 void QgsTextEditWrapper::setWidgetValue( const QVariant &val )
224 {
225  QString v;
226  if ( val.isNull() )
227  {
228  if ( !( field().type() == QVariant::Int || field().type() == QVariant::Double || field().type() == QVariant::LongLong || field().type() == QVariant::Date ) )
230  }
231  else
232  {
233  v = field().displayString( val );
234  }
235 
236  // For numbers, remove the group separator that might cause validation errors
237  // when the user is editing the field value.
238  // We are checking for editable layer because in the form field context we do not
239  // want to strip the separator unless the layer is editable.
240  // Also check that we have something like a number in the value to avoid
241  // stripping out dots from nextval when we have a schema: see https://github.com/qgis/QGIS/issues/28021
242  // "Wrong sequence detection with Postgres"
243  bool canConvertToDouble;
244  QLocale().toDouble( v, &canConvertToDouble );
245  if ( canConvertToDouble && layer() && layer()->isEditable() && ! QLocale().groupSeparator().isNull() && field().isNumeric() )
246  {
247  v = v.remove( QLocale().groupSeparator() );
248  }
249 
250  if ( mTextEdit )
251  {
252  if ( val != value() )
253  {
254  if ( config( QStringLiteral( "UseHtml" ) ).toBool() )
255  {
256  mTextEdit->setHtml( v );
257  if ( mTextBrowser )
258  {
259  mTextBrowser->setTextInteractionFlags( Qt::LinksAccessibleByMouse );
260  mTextBrowser->setOpenExternalLinks( true );
261  }
262  }
263  else
264  mTextEdit->setPlainText( v );
265  }
266  }
267 
268  if ( mPlainTextEdit )
269  {
270  if ( val != value() )
271  mPlainTextEdit->setPlainText( v );
272  }
273 
274  if ( mLineEdit )
275  mLineEdit->setText( v );
276 }
277 
278 void QgsTextEditWrapper::setHint( const QString &hintText )
279 {
280  if ( hintText.isNull() )
281  mPlaceholderText = mPlaceholderTextBackup;
282  else
283  {
284  mPlaceholderTextBackup = mPlaceholderText;
285  mPlaceholderText = hintText;
286  }
287 
288  mLineEdit->setPlaceholderText( mPlaceholderText );
289 }
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.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:649
QgsTextEditWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor=nullptr, QWidget *parent=nullptr)
Constructor for QgsTextEditWrapper.
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
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.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:650
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.
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
QVariant::Type type
Definition: qgsfield.h:56
void setHint(const QString &hintText) override
Add a hint text on the widget.