6#include <QStyleOptionFrame>
7#include <QLoggingCategory>
9#include "AutoCompleteLineEdit.h"
11static Q_LOGGING_CATEGORY(log,
"Web.LineEdit")
18CAutoCompleteLineEdit::CAutoCompleteLineEdit(
const QString &contents, QWidget *parent)
19 : QLineEdit(contents, parent)
24void CAutoCompleteLineEdit::initTimer()
27 m_updateTimer.setSingleShot(
true);
28 m_updateTimer.setInterval(100);
30 connect(
this, &QLineEdit::textChanged,
this, [
this]() {
31 m_updateTimer.start();
34 connect(&m_updateTimer, &QTimer::timeout,
this, &CAutoCompleteLineEdit::updateCompletion);
36 QPalette palette = QApplication::palette();
37 m_suggestionColor = palette.color(QPalette::HighlightedText);
38 m_suggestionBackground = palette.color(QPalette::Highlight);
41void CAutoCompleteLineEdit::setCompletions(
const QStringList &completions)
43 m_completions = completions;
44 m_currentSuggestion.clear();
47void CAutoCompleteLineEdit::keyPressEvent(QKeyEvent *event)
49 switch (event->key()) {
62 QLineEdit::keyPressEvent(event);
66void CAutoCompleteLineEdit::focusInEvent(QFocusEvent *event)
68 QLineEdit::focusInEvent(event);
69 if (!text().isEmpty()) {
74void CAutoCompleteLineEdit::focusOutEvent(QFocusEvent *event)
77 QLineEdit::focusOutEvent(event);
80void CAutoCompleteLineEdit::updateCompletion()
82 QString input = text();
84 if (input.isEmpty()) {
89 QString suggestion = findBestMatch(input);
90 if (!suggestion.isEmpty() && suggestion != input) {
91 m_currentSuggestion = suggestion;
98QColor CAutoCompleteLineEdit::GetSuggestionColor()
const
100 return m_suggestionColor;
103void CAutoCompleteLineEdit::SetSuggestionColor(
const QColor &newSuggestionColor)
105 m_suggestionColor = newSuggestionColor;
108QColor CAutoCompleteLineEdit::GetSuggestionBackground()
const
110 return m_suggestionBackground;
113void CAutoCompleteLineEdit::SetSuggestionBackground(
const QColor &newSuggestionBackground)
115 m_suggestionBackground = newSuggestionBackground;
118QString CAutoCompleteLineEdit::findBestMatch(
const QString &input)
const
120 if (m_completions.isEmpty()) {
124 QString lowerInput = input.toLower();
127 for (
const QString &completion : m_completions) {
128 if (completion.toLower().startsWith(lowerInput)) {
134 for (
const QString &completion : m_completions) {
135 if (completion.toLower().contains(lowerInput)) {
143void CAutoCompleteLineEdit::showSuggestion()
145 if (m_currentSuggestion.isEmpty() || m_currentSuggestion == text()) {
149 QString currentText = text();
150 QString suggestion = m_currentSuggestion;
153 QString complement = suggestion.mid(currentText.length());
155 if (!complement.isEmpty()) {
157 QString displayText = currentText +
158 QString(
"<span style='color: gray; background-color: #f0f0f0;'>%1</span>")
159 .arg(complement.toHtmlEscaped());
166void CAutoCompleteLineEdit::hideSuggestion()
168 m_currentSuggestion.clear();
172void CAutoCompleteLineEdit::acceptSuggestion()
174 if (!m_currentSuggestion.isEmpty()) {
175 setText(m_currentSuggestion);
177 emit editingFinished();
181void CAutoCompleteLineEdit::paintEvent(QPaintEvent *event)
184 QLineEdit::paintEvent(event);
186 if (m_currentSuggestion.isEmpty() || !hasFocus())
189 QPainter painter(
this);
190 painter.setRenderHint(QPainter::Antialiasing);
193 QString currentText = text();
194 if (currentText.isEmpty() || currentText == m_currentSuggestion) {
199 QString complement = m_currentSuggestion;
200 if (complement.isEmpty()) {
205 QFontMetrics fm(font());
206 int textWidth = fm.horizontalAdvance(currentText);
207 int textHeight = fm.height();
210 int cursorPos = cursorPosition();
211 QString textBeforeCursor = currentText.left(cursorPos);
212 int cursorX = fm.horizontalAdvance(textBeforeCursor);
215 QRect contentRect = contentsRect();
220 Qt::Alignment alignment = this->alignment();
221 if (alignment & Qt::AlignHCenter) {
222 leftMargin = (contentRect.width() - fm.horizontalAdvance(currentText + complement)) / 2;
223 }
else if (alignment & Qt::AlignRight) {
224 leftMargin = contentRect.width() - fm.horizontalAdvance(currentText + complement);
230 painter.setPen(m_suggestionColor);
232 int left = height() + fm.horizontalAdvance(
"W") + leftMargin + textWidth;
235 QRect rBackground(left,
236 (height() - textHeight) / 2,
237 fm.horizontalAdvance(complement),
239 painter.fillRect(rBackground,
240 m_suggestionBackground);
242 qDebug(log) <<
"currentText width:" << textWidth <<
"; height:" << textHeight
243 << currentText <<
"Background:" << rBackground
244 <<
"; cursorX:" << cursorX <<
"; cursorPos:" << cursorPos;
246 painter.drawText(left,
247 (height() + fm.ascent() - fm.descent()) / 2,