1 /***************************************************************************
2     qgssearchwidgetwrapper.h
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 #ifndef QGSSEARCHWIDGETWRAPPER_H
17 #define QGSSEARCHWIDGETWRAPPER_H
18 
19 #include <QObject>
20 #include "qgis_sip.h"
21 #include <QMap>
22 #include <QVariant>
23 
24 class QgsVectorLayer;
25 class QgsField;
26 
27 #include "qgsattributeeditorcontext.h"
28 #include "qgswidgetwrapper.h"
29 #include "qgis_gui.h"
30 
31 #ifdef SIP_RUN
32 % MappedType QList<QgsSearchWidgetWrapper::FilterFlag>
33 {
34   % TypeHeaderCode
35 #include <QList>
36   % End
37 
38   % ConvertFromTypeCode
39   // Create the list.
40   PyObject *l;
41 
42   if ( ( l = PyList_New( sipCpp->size() ) ) == NULL )
43     return NULL;
44 
45   // Set the list elements.
46   QList<QgsSearchWidgetWrapper::FilterFlag>::iterator it = sipCpp->begin();
47   for ( int i = 0; it != sipCpp->end(); ++it, ++i )
48   {
49     PyObject *tobj;
50 
51     if ( ( tobj = sipConvertFromEnum( *it, sipType_QgsSearchWidgetWrapper_FilterFlag ) ) == NULL )
52     {
53       Py_DECREF( l );
54       return NULL;
55     }
56     PyList_SET_ITEM( l, i, tobj );
57   }
58 
59   return l;
60   % End
61 
62   % ConvertToTypeCode
63   // Check the type if that is all that is required.
64   if ( sipIsErr == NULL )
65     return PyList_Check( sipPy );
66 
67   QList<QgsSearchWidgetWrapper::FilterFlag> *qlist = new QList<QgsSearchWidgetWrapper::FilterFlag>;
68 
69   for ( int i = 0; i < PyList_GET_SIZE( sipPy ); ++i )
70   {
71     *qlist << ( QgsSearchWidgetWrapper::FilterFlag )SIPLong_AsLong( PyList_GET_ITEM( sipPy, i ) );
72   }
73 
74   *sipCppPtr = qlist;
75   return sipGetState( sipTransferObj );
76   % End
77 };
78 #endif
79 
80 /**
81  * \ingroup gui
82  *
83  * \brief Shows a search widget on a filter form.
84  */
85 class GUI_EXPORT QgsSearchWidgetWrapper : public QgsWidgetWrapper
86 {
87     Q_OBJECT
88   public:
89 
90     /**
91      * Flags which indicate what types of filtering and searching is possible using the widget
92      * \since QGIS 2.16
93      */
94     enum FilterFlag
95     {
96       EqualTo = 1 << 1, //!< Supports equal to
97       NotEqualTo = 1 << 2, //!< Supports not equal to
98       GreaterThan = 1 << 3, //!< Supports greater than
99       LessThan = 1 << 4, //!< Supports less than
100       GreaterThanOrEqualTo = 1 << 5, //!< Supports >=
101       LessThanOrEqualTo = 1 << 6, //!< Supports <=
102       Between = 1 << 7, //!< Supports searches between two values
103       CaseInsensitive = 1 << 8, //!< Supports case insensitive searching
104       Contains = 1 << 9, //!< Supports value "contains" searching
105       DoesNotContain = 1 << 10, //!< Supports value does not contain searching
106       IsNull = 1 << 11, //!< Supports searching for null values
107       IsNotBetween = 1 << 12, //!< Supports searching for values outside of a set range
108       IsNotNull = 1 << 13, //!< Supports searching for non-null values
109       StartsWith = 1 << 14, //!< Supports searching for strings that start with
110       EndsWith = 1 << 15, //!< Supports searching for strings that end with
111     };
112     Q_DECLARE_FLAGS( FilterFlags, FilterFlag )
113 
114     /**
115      * Returns a list of exclusive filter flags, which cannot be combined with other flags (e.g., EqualTo/NotEqualTo)
116      * \see nonExclusiveFilterFlags()
117      * \since QGIS 2.16
118      */
119     static QList< QgsSearchWidgetWrapper::FilterFlag > exclusiveFilterFlags();
120 
121     /**
122      * Returns a list of non-exclusive filter flags, which can be combined with other flags (e.g., CaseInsensitive)
123      * \see exclusiveFilterFlags()
124      * \since QGIS 2.16
125      */
126     static QList< QgsSearchWidgetWrapper::FilterFlag > nonExclusiveFilterFlags();
127 
128     /**
129      * Returns a translated string representing a filter flag.
130      * \param flag flag to convert to string
131      * \since QGIS 2.16
132      */
133     static QString toString( QgsSearchWidgetWrapper::FilterFlag flag );
134 
135     /**
136      * Create a new widget wrapper
137      *
138      * \param vl        The layer on which the field is
139      * \param fieldIdx  The field which will be controlled
140      * \param parent    A parent widget for this widget wrapper and the created widget.
141      */
142     explicit QgsSearchWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *parent SIP_TRANSFERTHIS = nullptr );
143 
144     /**
145      * Returns filter flags supported by the search widget.
146      * \see defaultFlags()
147      * \since QGIS 2.16
148      */
149     virtual FilterFlags supportedFlags() const;
150 
151     /**
152      * Returns the filter flags which should be set by default for the search widget.
153      * \see supportedFlags()
154      * \since QGIS 2.16
155      */
156     virtual FilterFlags defaultFlags() const;
157 
158     /**
159      * Will be used to access the widget's value. Read the value from the widget and
160      * return it properly formatted to be saved in the attribute.
161      *
162      * If an invalid variant is returned this will be interpreted as no change.
163      * Be sure to return a NULL QVariant if it should be set to NULL.
164      *
165      * \returns The current value the widget represents
166      */
167     virtual QString expression() const = 0;
168 
169     /**
170      * If this is TRUE, then this search widget should take effect directly
171      * when its expression changes
172      */
173     virtual bool applyDirectly() = 0;
174 
175     // TODO QGIS 4.0 - make pure virtual
176 
177     /**
178      * Creates a filter expression based on the current state of the search widget
179      * and the specified filter flags.
180      * \param flags filter flags
181      * \returns filter expression
182      * \since QGIS 2.16
183      */
createExpression(FilterFlags flags)184     virtual QString createExpression( FilterFlags flags ) const { Q_UNUSED( flags ) return QStringLiteral( "TRUE" ); }
185 
186     /**
187      * Gets a field name or expression to use as field comparison.
188      * If in SearchMode returns a quoted field identifier.
189      * If in AggregateSearchMode returns an appropriate aggregate expression.
190      *
191      * \since QGIS 3.0
192      */
193     QString createFieldIdentifier() const;
194 
195     /**
196      * If in AggregateSearch mode, which aggregate should be used to construct
197      * the filter expression. Is a Null String if none.
198      *
199      * \since QGIS 3.0
200      */
201     QString aggregate() const;
202 
203     /**
204      * If in AggregateSearch mode, which aggregate should be used to construct
205      * the filter expression. Is a Null String if none.
206      *
207      * \since QGIS 3.0
208      */
209     void setAggregate( const QString &aggregate );
210 
211     /**
212      * Returns the field index
213      * \since QGIS 3.10
214      */
215     int fieldIndex() const;
216 
217   public slots:
218 
219     /**
220      * Clears the widget's current value and resets it back to the default state
221      * \since QGIS 2.16
222      */
clearWidget()223     virtual void clearWidget() {}
224 
225     /**
226      * Toggles whether the search widget is enabled or disabled.
227      * \param enabled set to TRUE to enable widget
228      */
setEnabled(bool enabled)229     void setEnabled( bool enabled ) override { Q_UNUSED( enabled ) }
230 
231   signals:
232 
233     /**
234      * Emitted whenever the expression changes
235      * \param exp The new search expression
236      */
237     void expressionChanged( const QString &exp );
238 
239     /**
240      * Emitted when a user changes the value of the search widget.
241      * \since QGIS 2.16
242      */
243     void valueChanged();
244 
245     /**
246      * Emitted when a user changes the value of the search widget back
247      * to an empty, default state.
248      * \since QGIS 2.16
249      */
250     void valueCleared();
251 
252   protected slots:
253 
254     /**
255      * Set the \a expression which is currently used as filter for this widget.
256      */
257     virtual void setExpression( const QString &expression ) = 0;
258 
259     void setFeature( const QgsFeature &feature ) override;
260 
261   protected:
262     //! clears the expression to search for all features
263     void clearExpression();
264 
265     QString mExpression;
266     int mFieldIdx;
267 
268   private:
269     QString mAggregate;
270     QgsRelation mAggregateRelation;
271 };
272 // We'll use this class inside a QVariant in the widgets properties
273 Q_DECLARE_METATYPE( QgsSearchWidgetWrapper * )
274 
275 Q_DECLARE_OPERATORS_FOR_FLAGS( QgsSearchWidgetWrapper::FilterFlags )
276 
277 #endif // QGSSEARCHWIDGETWRAPPER_H
278