QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
18#include "qgsfloatingwidget.h"
19#include "qgsvectorlayer.h"
20
21#include <QCompleter>
22#include <QHBoxLayout>
23#include <QStringListModel>
24#include <QTimer>
25
26#include "moc_qgsfieldvalueslineedit.cpp"
27
29 : QgsFilterLineEdit( parent )
30{
31 QCompleter *c = new QCompleter( this );
32 c->setCaseSensitivity( Qt::CaseInsensitive );
33 c->setFilterMode( Qt::MatchContains );
34 c->setCompletionMode( QCompleter::UnfilteredPopupCompletion );
35 setCompleter( c );
36 connect( this, &QgsFieldValuesLineEdit::textEdited, this, &QgsFieldValuesLineEdit::requestCompleterUpdate );
37 mShowPopupTimer.setSingleShot( true );
38 mShowPopupTimer.setInterval( 100 );
39 connect( &mShowPopupTimer, &QTimer::timeout, this, &QgsFieldValuesLineEdit::triggerCompleterUpdate );
40}
41
43{
44 if ( mGatherer )
45 {
46 mGatherer->stop();
47 mGatherer->wait(); // mGatherer is deleted when wait completes
48 }
49}
50
52{
53 if ( mLayer == layer )
54 return;
55
56 mLayer = layer;
57 emit layerChanged( layer );
58}
59
61{
62 if ( mAttributeIndex == index )
63 return;
64
65 mAttributeIndex = index;
66 emit attributeIndexChanged( index );
67}
68
69void QgsFieldValuesLineEdit::requestCompleterUpdate()
70{
71 mUpdateRequested = true;
72 mShowPopupTimer.start();
73}
74
75void QgsFieldValuesLineEdit::triggerCompleterUpdate()
76{
77 mShowPopupTimer.stop();
78 const QString currentText = text();
79
80 if ( currentText.isEmpty() )
81 {
82 if ( mGatherer )
83 mGatherer->stop();
84 return;
85 }
86
87 updateCompletionList( currentText );
88}
89
90void QgsFieldValuesLineEdit::updateCompletionList( const QString &text )
91{
92 if ( text.isEmpty() )
93 {
94 if ( mGatherer )
95 mGatherer->stop();
96 return;
97 }
98
99 mUpdateRequested = true;
100 if ( mGatherer )
101 {
102 mRequestedCompletionText = text;
103 mGatherer->stop();
104 return;
105 }
106
107 mGatherer = new QgsFieldValuesLineEditValuesGatherer( mLayer, mAttributeIndex );
108 mGatherer->setSubstring( text );
109
110 connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::collectedValues, this, &QgsFieldValuesLineEdit::updateCompleter );
111 connect( mGatherer, &QgsFieldValuesLineEditValuesGatherer::finished, this, &QgsFieldValuesLineEdit::gathererThreadFinished );
112
113 mGatherer->start();
114}
115
116void QgsFieldValuesLineEdit::gathererThreadFinished()
117{
118 const bool wasCanceled = mGatherer->wasCanceled();
119
120 delete mGatherer;
121 mGatherer = nullptr;
122
123 if ( wasCanceled )
124 {
125 const QString text = mRequestedCompletionText;
126 mRequestedCompletionText.clear();
127 updateCompletionList( text );
128 return;
129 }
130}
131
132void QgsFieldValuesLineEdit::updateCompleter( const QStringList &values )
133{
134 mUpdateRequested = false;
135 completer()->setModel( new QStringListModel( values ) );
136 completer()->complete();
137}
138
139
140// just internal guff - definitely not for exposing to public API!
142
143void QgsFieldValuesLineEditValuesGatherer::run()
144{
145 mWasCanceled = false;
146 if ( mSubstring.isEmpty() )
147 {
148 emit collectedValues( QStringList() );
149 return;
150 }
151
152 // allow responsive cancellation
153 mFeedback = new QgsFeedback();
154 // just get 100 values... maybe less/more would be useful?
155 mValues = mLayer->uniqueStringsMatching( mAttributeIndex, mSubstring, 100, mFeedback );
156
157 // be overly cautious - it's *possible* stop() might be called between deleting mFeedback and nulling it
158 mFeedbackMutex.lock();
159 delete mFeedback;
160 mFeedback = nullptr;
161 mFeedbackMutex.unlock();
162
163 emit collectedValues( mValues );
164}
165
166void QgsFieldValuesLineEditValuesGatherer::stop()
167{
168 // be cautious, in case gatherer stops naturally just as we are canceling it and mFeedback gets deleted
169 mFeedbackMutex.lock();
170 if ( mFeedback )
171 mFeedback->cancel();
172 mFeedbackMutex.unlock();
173
174 mWasCanceled = true;
175}
176
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.
QgsFilterLineEdit(QWidget *parent=nullptr, const QString &nullValue=QString())
Constructor for QgsFilterLineEdit.
Represents a vector layer which manages a vector based dataset.
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