QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
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
66void QgsFieldValuesLineEdit::requestCompleterUpdate()
67{
68 mUpdateRequested = true;
69 mShowPopupTimer.start();
70}
71
72void 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
87void 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
113void 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
129void 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
140void 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
163void 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
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
void attributeIndexChanged(int index)
Emitted when the field associated with the widget changes.
QgsFieldValuesLineEdit(QWidget *parent=nullptr)
Constructor for QgsFieldValuesLineEdit.
void setLayer(QgsVectorLayer *layer)
Sets the layer containing the field that values will be shown from.
void layerChanged(QgsVectorLayer *layer)
Emitted when the layer associated with the widget changes.
void setAttributeIndex(int index)
Sets the attribute index for the field containing values to show in the widget.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Represents a vector layer which manages a vector based data sets.
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