1 /*************************************************************************** 2 qgsfieldvalueslineedit.h 3 ----------------------- 4 Date : 20-08-2016 5 Copyright : (C) 2016 by 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 #ifndef QGSFIELDVALUESLINEEDIT_H 16 #define QGSFIELDVALUESLINEEDIT_H 17 18 #include "qgsfilterlineedit.h" 19 #include "qgis_sip.h" 20 #include "qgsfeedback.h" 21 22 #include <QStringListModel> 23 #include <QTreeView> 24 #include <QFocusEvent> 25 #include <QHeaderView> 26 #include <QTimer> 27 #include <QThread> 28 #include <QMutex> 29 30 #include "qgis_gui.h" 31 32 class QgsFloatingWidget; 33 class QgsVectorLayer; 34 35 36 #ifndef SIP_RUN 37 38 // just internal guff - definitely not for exposing to public API! 39 ///@cond PRIVATE 40 41 /** 42 * \class QgsFieldValuesLineEditValuesGatherer 43 * Collates unique values containing a matching substring in a thread. 44 */ 45 class QgsFieldValuesLineEditValuesGatherer: public QThread 46 { 47 Q_OBJECT 48 49 public: QgsFieldValuesLineEditValuesGatherer(QgsVectorLayer * layer,int attributeIndex)50 QgsFieldValuesLineEditValuesGatherer( QgsVectorLayer *layer, int attributeIndex ) 51 : mLayer( layer ) 52 , mAttributeIndex( attributeIndex ) 53 , mWasCanceled( false ) 54 {} 55 56 /** 57 * Sets the substring to find matching values containing 58 */ setSubstring(const QString & string)59 void setSubstring( const QString &string ) { mSubstring = string; } 60 61 void run() override; 62 63 //! Informs the gatherer to immediately stop collecting values 64 void stop(); 65 66 //! Returns TRUE if collection was canceled before completion wasCanceled()67 bool wasCanceled() const { return mWasCanceled; } 68 69 signals: 70 71 /** 72 * Emitted when values have been collected 73 * \param values list of unique matching string values 74 */ 75 void collectedValues( const QStringList &values ); 76 77 private: 78 79 QgsVectorLayer *mLayer = nullptr; 80 int mAttributeIndex; 81 QString mSubstring; 82 QStringList mValues; 83 QgsFeedback *mFeedback = nullptr; 84 QMutex mFeedbackMutex; 85 bool mWasCanceled; 86 }; 87 88 ///@endcond 89 90 #endif 91 92 /** 93 * \class QgsFieldValuesLineEdit 94 * \ingroup gui 95 * \brief A line edit with an autocompleter which takes unique values from a vector layer's fields. 96 * The autocompleter is populated from the vector layer in the background to ensure responsive 97 * interaction with the widget. 98 * \since QGIS 3.0 99 */ 100 class GUI_EXPORT QgsFieldValuesLineEdit: public QgsFilterLineEdit 101 { 102 Q_OBJECT 103 104 Q_PROPERTY( QgsVectorLayer *layer READ layer WRITE setLayer NOTIFY layerChanged ) 105 Q_PROPERTY( int attributeIndex READ attributeIndex WRITE setAttributeIndex NOTIFY attributeIndexChanged ) 106 107 public: 108 109 /** 110 * Constructor for QgsFieldValuesLineEdit 111 * \param parent parent widget 112 */ 113 QgsFieldValuesLineEdit( QWidget *parent SIP_TRANSFERTHIS = nullptr ); 114 115 ~QgsFieldValuesLineEdit() override; 116 117 /** 118 * Sets the layer containing the field that values will be shown from. 119 * \param layer vector layer 120 * \see layer() 121 * \see setAttributeIndex() 122 */ 123 void setLayer( QgsVectorLayer *layer ); 124 125 /** 126 * Returns the layer containing the field that values will be shown from. 127 * \see setLayer() 128 * \see attributeIndex() 129 */ layer()130 QgsVectorLayer *layer() const { return mLayer; } 131 132 /** 133 * Sets the attribute index for the field containing values to show in the widget. 134 * \param index index of attribute 135 * \see attributeIndex() 136 * \see setLayer() 137 */ 138 void setAttributeIndex( int index ); 139 140 /** 141 * Returns the attribute index for the field containing values shown in the widget. 142 * \see setAttributeIndex() 143 * \see layer() 144 */ attributeIndex()145 int attributeIndex() const { return mAttributeIndex; } 146 147 signals: 148 149 /** 150 * Emitted when the layer associated with the widget changes. 151 * \param layer vector layer 152 */ 153 void layerChanged( QgsVectorLayer *layer ); 154 155 /** 156 * Emitted when the field associated with the widget changes. 157 * \param index new attribute index for field 158 */ 159 void attributeIndexChanged( int index ); 160 161 private slots: 162 163 /** 164 * Requests that the autocompleter updates its completion list. The update will not occur immediately 165 * but after a preset timeout to avoid multiple updates while a user is quickly typing. 166 */ 167 void requestCompleterUpdate(); 168 169 /** 170 * Updates the autocompleter list immediately. Calling 171 * this will trigger a background request to the layer to fetch matching unique values. 172 */ 173 void triggerCompleterUpdate(); 174 175 /** 176 * Updates the values shown in the completer list. 177 * \param values list of string values to show 178 */ 179 void updateCompleter( const QStringList &values ); 180 181 /** 182 * Called when the gatherer thread is complete, regardless of whether it finished collecting values. 183 * Cleans up the gatherer thread and triggers a new background thread if the widget's text has changed 184 * in the meantime. 185 */ 186 void gathererThreadFinished(); 187 188 private: 189 190 QgsVectorLayer *mLayer = nullptr; 191 int mAttributeIndex = -1; 192 193 //! Will be TRUE when a background update of the completer values is occurring 194 bool mUpdateRequested = false; 195 196 //! Timer to prevent multiple updates of autocomplete list 197 QTimer mShowPopupTimer; 198 199 //! Background value gatherer thread 200 QgsFieldValuesLineEditValuesGatherer *mGatherer = nullptr; 201 202 //! Will be set to the latest completion text string which should be requested 203 QString mRequestedCompletionText; 204 205 //! Kicks off the gathering of completer text values for a specified substring 206 void updateCompletionList( const QString &substring ); 207 208 }; 209 210 211 #endif //QGSFIELDVALUESLINEEDIT_H 212