QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsfieldvalueslineedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfieldvalueslineedit.cpp
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 
16 #include "qgsfieldvalueslineedit.h"
17 #include "qgsvectorlayer.h"
18 #include "qgsfloatingwidget.h"
19 
20 #include <QCompleter>
21 #include <QStringListModel>
22 #include <QTimer>
23 #include <QHBoxLayout>
24 
26  : QgsFilterLineEdit( parent )
27 {
28  QCompleter *c = new QCompleter( this );
29  c->setCaseSensitivity( Qt::CaseInsensitive );
30  c->setFilterMode( Qt::MatchContains );
31  setCompleter( c );
32  connect( this, &QgsFieldValuesLineEdit::textEdited, this, &QgsFieldValuesLineEdit::requestCompleterUpdate );
33  mShowPopupTimer.setSingleShot( true );
34  mShowPopupTimer.setInterval( 100 );
35  connect( &mShowPopupTimer, &QTimer::timeout, this, &QgsFieldValuesLineEdit::triggerCompleterUpdate );
36 }
37 
39 {
40  if ( mGatherer )
41  {
42  mGatherer->stop();
43  mGatherer->wait(); // mGatherer is deleted when wait completes
44  }
45 }
46 
48 {
49  if ( mLayer == layer )
50  return;
51 
52  mLayer = layer;
53  emit layerChanged( layer );
54 }
55 
57 {
58  if ( mAttributeIndex == index )
59  return;
60 
61  mAttributeIndex = index;
62  emit attributeIndexChanged( index );
63 }
64 
65 void QgsFieldValuesLineEdit::requestCompleterUpdate()
66 {
67  mUpdateRequested = true;
68  mShowPopupTimer.start();
69 }
70 
71 void QgsFieldValuesLineEdit::triggerCompleterUpdate()
72 {
73  mShowPopupTimer.stop();
74  QString currentText = text();
75 
76  if ( currentText.isEmpty() )
77  {
78  if ( mGatherer )
79  mGatherer->stop();
80  return;
81  }
82 
83  updateCompletionList( currentText );
84 }
85 
86 void QgsFieldValuesLineEdit::updateCompletionList( const QString &text )
87 {
88  if ( text.isEmpty() )
89  {
90  if ( mGatherer )
91  mGatherer->stop();
92  return;
93  }
94 
95  mUpdateRequested = true;
96  if ( mGatherer )
97  {
98  mRequestedCompletionText = text;
99  mGatherer->stop();
100  return;
101  }
102 
103  mGatherer = new QgsFieldValuesLineEditValuesGatherer( mLayer, mAttributeIndex );
104  mGatherer->setSubstring( text );
105 
106  connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::collectedValues, this, &QgsFieldValuesLineEdit::updateCompleter );
107  connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::finished, this, &QgsFieldValuesLineEdit::gathererThreadFinished );
108 
109  mGatherer->start();
110 }
111 
112 void QgsFieldValuesLineEdit::gathererThreadFinished()
113 {
114  bool wasCanceled = mGatherer->wasCanceled();
115 
116  delete mGatherer;
117  mGatherer = nullptr;
118 
119  if ( wasCanceled )
120  {
121  QString text = mRequestedCompletionText;
122  mRequestedCompletionText.clear();
123  updateCompletionList( text );
124  return;
125  }
126 }
127 
128 void QgsFieldValuesLineEdit::updateCompleter( const QStringList &values )
129 {
130  mUpdateRequested = false;
131  completer()->setModel( new QStringListModel( values ) );
132  completer()->complete();
133 }
134 
135 
136 // just internal guff - definitely not for exposing to public API!
138 
139 void QgsFieldValuesLineEditValuesGatherer::run()
140 {
141  mWasCanceled = false;
142  if ( mSubstring.isEmpty() )
143  {
144  emit collectedValues( QStringList() );
145  return;
146  }
147 
148  // allow responsive cancellation
149  mFeedback = new QgsFeedback();
150  // just get 100 values... maybe less/more would be useful?
151  mValues = mLayer->uniqueStringsMatching( mAttributeIndex, mSubstring, 100, mFeedback );
152 
153  // be overly cautious - it's *possible* stop() might be called between deleting mFeedback and nulling it
154  mFeedbackMutex.lock();
155  delete mFeedback;
156  mFeedback = nullptr;
157  mFeedbackMutex.unlock();
158 
159  emit collectedValues( mValues );
160 }
161 
162 void QgsFieldValuesLineEditValuesGatherer::stop()
163 {
164  // be cautious, in case gatherer stops naturally just as we are canceling it and mFeedback gets deleted
165  mFeedbackMutex.lock();
166  if ( mFeedback )
167  mFeedback->cancel();
168  mFeedbackMutex.unlock();
169 
170  mWasCanceled = true;
171 }
172 
QgsFieldValuesLineEdit::layer
QgsVectorLayer * layer
Definition: qgsfieldvalueslineedit.h:104
QgsFieldValuesLineEdit::setAttributeIndex
void setAttributeIndex(int index)
Sets the attribute index for the field containing values to show in the widget.
Definition: qgsfieldvalueslineedit.cpp:56
QgsFilterLineEdit
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Definition: qgsfilterlineedit.h:40
QgsFieldValuesLineEdit::QgsFieldValuesLineEdit
QgsFieldValuesLineEdit(QWidget *parent=nullptr)
Constructor for QgsFieldValuesLineEdit.
Definition: qgsfieldvalueslineedit.cpp:25
QgsFieldValuesLineEdit::~QgsFieldValuesLineEdit
~QgsFieldValuesLineEdit() override
Definition: qgsfieldvalueslineedit.cpp:38
QgsFieldValuesLineEdit::setLayer
void setLayer(QgsVectorLayer *layer)
Sets the layer containing the field that values will be shown from.
Definition: qgsfieldvalueslineedit.cpp:47
qgsfloatingwidget.h
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsFieldValuesLineEdit::layerChanged
void layerChanged(QgsVectorLayer *layer)
Emitted when the layer associated with the widget changes.
QgsFieldValuesLineEdit::attributeIndexChanged
void attributeIndexChanged(int index)
Emitted when the field associated with the widget changes.
qgsfieldvalueslineedit.h
qgsvectorlayer.h
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387