QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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  c->setCompletionMode( QCompleter::UnfilteredPopupCompletion );
32  setCompleter( c );
33  connect( this, &QgsFieldValuesLineEdit::textEdited, this, &QgsFieldValuesLineEdit::requestCompleterUpdate );
34  mShowPopupTimer.setSingleShot( true );
35  mShowPopupTimer.setInterval( 100 );
36  connect( &mShowPopupTimer, &QTimer::timeout, this, &QgsFieldValuesLineEdit::triggerCompleterUpdate );
37 }
38 
40 {
41  if ( mGatherer )
42  {
43  mGatherer->stop();
44  mGatherer->wait(); // mGatherer is deleted when wait completes
45  }
46 }
47 
49 {
50  if ( mLayer == layer )
51  return;
52 
53  mLayer = layer;
54  emit layerChanged( layer );
55 }
56 
58 {
59  if ( mAttributeIndex == index )
60  return;
61 
62  mAttributeIndex = index;
63  emit attributeIndexChanged( index );
64 }
65 
66 void QgsFieldValuesLineEdit::requestCompleterUpdate()
67 {
68  mUpdateRequested = true;
69  mShowPopupTimer.start();
70 }
71 
72 void QgsFieldValuesLineEdit::triggerCompleterUpdate()
73 {
74  mShowPopupTimer.stop();
75  const QString currentText = text();
76 
77  if ( currentText.isEmpty() )
78  {
79  if ( mGatherer )
80  mGatherer->stop();
81  return;
82  }
83 
84  updateCompletionList( currentText );
85 }
86 
87 void QgsFieldValuesLineEdit::updateCompletionList( const QString &text )
88 {
89  if ( text.isEmpty() )
90  {
91  if ( mGatherer )
92  mGatherer->stop();
93  return;
94  }
95 
96  mUpdateRequested = true;
97  if ( mGatherer )
98  {
99  mRequestedCompletionText = text;
100  mGatherer->stop();
101  return;
102  }
103 
104  mGatherer = new QgsFieldValuesLineEditValuesGatherer( mLayer, mAttributeIndex );
105  mGatherer->setSubstring( text );
106 
107  connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::collectedValues, this, &QgsFieldValuesLineEdit::updateCompleter );
108  connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::finished, this, &QgsFieldValuesLineEdit::gathererThreadFinished );
109 
110  mGatherer->start();
111 }
112 
113 void QgsFieldValuesLineEdit::gathererThreadFinished()
114 {
115  const bool wasCanceled = mGatherer->wasCanceled();
116 
117  delete mGatherer;
118  mGatherer = nullptr;
119 
120  if ( wasCanceled )
121  {
122  const QString text = mRequestedCompletionText;
123  mRequestedCompletionText.clear();
124  updateCompletionList( text );
125  return;
126  }
127 }
128 
129 void QgsFieldValuesLineEdit::updateCompleter( const QStringList &values )
130 {
131  mUpdateRequested = false;
132  completer()->setModel( new QStringListModel( values ) );
133  completer()->complete();
134 }
135 
136 
137 // just internal guff - definitely not for exposing to public API!
139 
140 void QgsFieldValuesLineEditValuesGatherer::run()
141 {
142  mWasCanceled = false;
143  if ( mSubstring.isEmpty() )
144  {
145  emit collectedValues( QStringList() );
146  return;
147  }
148 
149  // allow responsive cancellation
150  mFeedback = new QgsFeedback();
151  // just get 100 values... maybe less/more would be useful?
152  mValues = mLayer->uniqueStringsMatching( mAttributeIndex, mSubstring, 100, mFeedback );
153 
154  // be overly cautious - it's *possible* stop() might be called between deleting mFeedback and nulling it
155  mFeedbackMutex.lock();
156  delete mFeedback;
157  mFeedback = nullptr;
158  mFeedbackMutex.unlock();
159 
160  emit collectedValues( mValues );
161 }
162 
163 void QgsFieldValuesLineEditValuesGatherer::stop()
164 {
165  // be cautious, in case gatherer stops naturally just as we are canceling it and mFeedback gets deleted
166  mFeedbackMutex.lock();
167  if ( mFeedback )
168  mFeedback->cancel();
169  mFeedbackMutex.unlock();
170 
171  mWasCanceled = true;
172 }
173 
QgsFieldValuesLineEdit::setAttributeIndex
void setAttributeIndex(int index)
Sets the attribute index for the field containing values to show in the widget.
Definition: qgsfieldvalueslineedit.cpp:57
QgsFilterLineEdit
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Definition: qgsfilterlineedit.h:39
QgsFieldValuesLineEdit::QgsFieldValuesLineEdit
QgsFieldValuesLineEdit(QWidget *parent=nullptr)
Constructor for QgsFieldValuesLineEdit.
Definition: qgsfieldvalueslineedit.cpp:25
QgsFieldValuesLineEdit::~QgsFieldValuesLineEdit
~QgsFieldValuesLineEdit() override
Definition: qgsfieldvalueslineedit.cpp:39
QgsFieldValuesLineEdit::setLayer
void setLayer(QgsVectorLayer *layer)
Sets the layer containing the field that values will be shown from.
Definition: qgsfieldvalueslineedit.cpp:48
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::layer
QgsVectorLayer layer
Definition: qgsfieldvalueslineedit.h:104
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:391