1 /***************************************************************************
2 qgsdefaultsearchwidgettwrapper.cpp
3 --------------------------------------
4 Date : 31.5.2015
5 Copyright : (C) 2015 Karolina Alexiou (carolinux)
6 Email : carolinegr 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 "qgsdefaultsearchwidgetwrapper.h"
17
18 #include "qgsfields.h"
19 #include "qgsfieldvalidator.h"
20 #include "qgsexpression.h"
21 #include "qgsfieldvalueslineedit.h"
22 #include "qgssettings.h"
23 #include "qgsapplication.h"
24
25 #include <QHBoxLayout>
26
QgsDefaultSearchWidgetWrapper(QgsVectorLayer * vl,int fieldIdx,QWidget * parent)27 QgsDefaultSearchWidgetWrapper::QgsDefaultSearchWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
28 : QgsSearchWidgetWrapper( vl, fieldIdx, parent )
29 , mCaseString( QStringLiteral( "LIKE" ) )
30 {
31 }
32
expression() const33 QString QgsDefaultSearchWidgetWrapper::expression() const
34 {
35 return mExpression;
36 }
37
setCaseString(int caseSensitiveCheckState)38 void QgsDefaultSearchWidgetWrapper::setCaseString( int caseSensitiveCheckState )
39 {
40 if ( caseSensitiveCheckState == Qt::Checked )
41 {
42 mCaseString = QStringLiteral( "LIKE" );
43 }
44 else
45 {
46 mCaseString = QStringLiteral( "ILIKE" );
47 }
48 // need to update also the line edit
49 setExpression( mLineEdit->text() );
50
51 if ( applyDirectly() )
52 emit expressionChanged( mExpression );
53 }
54
setExpression(const QString & expression)55 void QgsDefaultSearchWidgetWrapper::setExpression( const QString &expression )
56 {
57 QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
58 bool numeric = ( fldType == QVariant::Int || fldType == QVariant::Double || fldType == QVariant::LongLong );
59
60 QString exp = expression;
61 QString nullValue = QgsApplication::nullRepresentation();
62 QString fieldName = layer()->fields().at( mFieldIdx ).name();
63 QString str;
64 if ( exp == nullValue )
65 {
66 str = QStringLiteral( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
67 }
68 else
69 {
70 str = QStringLiteral( "%1 %2 '%3'" )
71 .arg( QgsExpression::quotedColumnRef( fieldName ),
72 numeric ? QStringLiteral( "=" ) : mCaseString,
73 numeric ?
74 exp.replace( '\'', QLatin1String( "''" ) )
75 :
76 '%' + exp.replace( '\'', QLatin1String( "''" ) ) + '%' ); // escape quotes
77 }
78 mExpression = str;
79 }
80
createWidget(QWidget * parent)81 QWidget *QgsDefaultSearchWidgetWrapper::createWidget( QWidget *parent )
82 {
83 return new QWidget( parent );
84 }
85
applyDirectly()86 bool QgsDefaultSearchWidgetWrapper::applyDirectly()
87 {
88 return false;
89 }
90
supportedFlags() const91 QgsSearchWidgetWrapper::FilterFlags QgsDefaultSearchWidgetWrapper::supportedFlags() const
92 {
93 FilterFlags flags = EqualTo | NotEqualTo | IsNull | IsNotNull;
94
95 QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
96 switch ( fldType )
97 {
98 case QVariant::Int:
99 case QVariant::UInt:
100 case QVariant::Double:
101 case QVariant::LongLong:
102 case QVariant::ULongLong:
103 case QVariant::Date:
104 case QVariant::DateTime:
105 case QVariant::Time:
106 flags |= GreaterThan | LessThan | GreaterThanOrEqualTo | LessThanOrEqualTo | Between | IsNotBetween;
107 break;
108
109 case QVariant::String:
110 flags |= Contains | DoesNotContain | StartsWith | EndsWith;
111 break;
112
113 default:
114 break;
115 }
116 return flags;
117 }
118
defaultFlags() const119 QgsSearchWidgetWrapper::FilterFlags QgsDefaultSearchWidgetWrapper::defaultFlags() const
120 {
121 QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
122 switch ( fldType )
123 {
124 case QVariant::Int:
125 case QVariant::UInt:
126 case QVariant::Double:
127 case QVariant::LongLong:
128 case QVariant::ULongLong:
129 //numeric
130 return EqualTo;
131
132 case QVariant::Date:
133 case QVariant::DateTime:
134 case QVariant::Time:
135 return EqualTo;
136
137 case QVariant::String:
138 return Contains;
139
140 default:
141 break;
142 }
143 return EqualTo;
144 }
145
createExpression(QgsSearchWidgetWrapper::FilterFlags flags) const146 QString QgsDefaultSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper::FilterFlags flags ) const
147 {
148 //clear any unsupported flags
149 flags &= supportedFlags();
150
151 QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
152 QString fieldName = createFieldIdentifier();
153
154 if ( flags & IsNull )
155 return fieldName + " IS NULL";
156 if ( flags & IsNotNull )
157 return fieldName + " IS NOT NULL";
158
159 switch ( fldType )
160 {
161 case QVariant::Int:
162 case QVariant::UInt:
163 case QVariant::Double:
164 case QVariant::LongLong:
165 case QVariant::ULongLong:
166 {
167 if ( flags & EqualTo )
168 return fieldName + '=' + mLineEdit->text();
169 else if ( flags & NotEqualTo )
170 return fieldName + "<>" + mLineEdit->text();
171 else if ( flags & GreaterThan )
172 return fieldName + '>' + mLineEdit->text();
173 else if ( flags & LessThan )
174 return fieldName + '<' + mLineEdit->text();
175 else if ( flags & GreaterThanOrEqualTo )
176 return fieldName + ">=" + mLineEdit->text();
177 else if ( flags & LessThanOrEqualTo )
178 return fieldName + "<=" + mLineEdit->text();
179 break;
180 }
181
182 case QVariant::Date:
183 case QVariant::DateTime:
184 case QVariant::Time:
185 {
186 if ( flags & EqualTo )
187 return fieldName + "='" + mLineEdit->text() + '\'';
188 else if ( flags & NotEqualTo )
189 return fieldName + "<>'" + mLineEdit->text() + '\'';
190 else if ( flags & GreaterThan )
191 return fieldName + ">'" + mLineEdit->text() + '\'';
192 else if ( flags & LessThan )
193 return fieldName + "<'" + mLineEdit->text() + '\'';
194 else if ( flags & GreaterThanOrEqualTo )
195 return fieldName + ">='" + mLineEdit->text() + '\'';
196 else if ( flags & LessThanOrEqualTo )
197 return fieldName + "<='" + mLineEdit->text() + '\'';
198 break;
199 }
200
201 case QVariant::String:
202 {
203 // case insensitive!
204 if ( flags & EqualTo || flags & NotEqualTo )
205 {
206 if ( mCheckbox && mCheckbox->isChecked() )
207 return fieldName + ( ( flags & EqualTo ) ? "=" : "<>" )
208 + QgsExpression::quotedString( mLineEdit->text() );
209 else
210 return QStringLiteral( "lower(%1)" ).arg( fieldName )
211 + ( ( flags & EqualTo ) ? "=" : "<>" ) +
212 QStringLiteral( "lower(%1)" ).arg( QgsExpression::quotedString( mLineEdit->text() ) );
213 }
214 else if ( flags & Contains || flags & DoesNotContain || flags & StartsWith || flags & EndsWith )
215 {
216 QString exp = fieldName + ( mCheckbox && mCheckbox->isChecked() ? " LIKE " : " ILIKE " );
217 QString value = QgsExpression::quotedString( mLineEdit->text() );
218 value.chop( 1 );
219 value = value.remove( 0, 1 );
220 exp += '\'';
221 if ( !flags.testFlag( StartsWith ) )
222 exp += '%';
223 exp += value;
224 if ( !flags.testFlag( EndsWith ) )
225 exp += '%';
226 exp += '\'';
227 if ( flags & DoesNotContain )
228 exp.prepend( "NOT (" ).append( ')' );
229 return exp;
230 }
231
232 break;
233 }
234
235 default:
236 break;
237 }
238
239 return QString();
240 }
241
clearWidget()242 void QgsDefaultSearchWidgetWrapper::clearWidget()
243 {
244 mLineEdit->setText( QString() );
245 }
246
setEnabled(bool enabled)247 void QgsDefaultSearchWidgetWrapper::setEnabled( bool enabled )
248 {
249 mLineEdit->setEnabled( enabled );
250 if ( mCheckbox )
251 mCheckbox->setEnabled( enabled );
252 }
253
initWidget(QWidget * widget)254 void QgsDefaultSearchWidgetWrapper::initWidget( QWidget *widget )
255 {
256 mContainer = widget;
257 mContainer->setLayout( new QHBoxLayout() );
258 mContainer->layout()->setContentsMargins( 0, 0, 0, 0 );
259 QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
260
261 if ( fldType == QVariant::String )
262 {
263 mLineEdit = new QgsFieldValuesLineEdit();
264 static_cast< QgsFieldValuesLineEdit * >( mLineEdit )->setLayer( layer() );
265 static_cast< QgsFieldValuesLineEdit * >( mLineEdit )->setAttributeIndex( mFieldIdx );
266 }
267 else
268 {
269 mLineEdit = new QgsFilterLineEdit();
270 }
271 mContainer->layout()->addWidget( mLineEdit );
272 mContainer->setFocusProxy( mLineEdit );
273
274 if ( fldType == QVariant::String )
275 {
276 mCheckbox = new QCheckBox( QStringLiteral( "Case sensitive" ) );
277 mContainer->layout()->addWidget( mCheckbox );
278 connect( mCheckbox, &QCheckBox::stateChanged, this, &QgsDefaultSearchWidgetWrapper::setCaseString );
279 mCheckbox->setChecked( Qt::Unchecked );
280 }
281
282 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsDefaultSearchWidgetWrapper::textChanged );
283 connect( mLineEdit, &QLineEdit::returnPressed, this, &QgsDefaultSearchWidgetWrapper::filterChanged );
284 connect( mLineEdit, &QLineEdit::textEdited, this, &QgsSearchWidgetWrapper::valueChanged );
285
286 mCaseString = QStringLiteral( "ILIKE" );
287 }
288
valid() const289 bool QgsDefaultSearchWidgetWrapper::valid() const
290 {
291 return true;
292 }
293
lineEdit()294 QgsFilterLineEdit *QgsDefaultSearchWidgetWrapper::lineEdit()
295 {
296 return mLineEdit;
297 }
298
caseSensitiveCheckBox()299 QCheckBox *QgsDefaultSearchWidgetWrapper::caseSensitiveCheckBox()
300 {
301 return mCheckbox;
302 }
303
filterChanged()304 void QgsDefaultSearchWidgetWrapper::filterChanged()
305 {
306 emit expressionChanged( mExpression );
307 }
308
textChanged(const QString & text)309 void QgsDefaultSearchWidgetWrapper::textChanged( const QString &text )
310 {
311 if ( text.isEmpty() )
312 emit valueCleared();
313
314 setExpression( text );
315 }
316