1 /* apply_lineedit.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9 
10 #include <ui/qt/widgets/apply_line_edit.h>
11 
12 #include <epan/prefs.h>
13 
14 #include <ui/qt/utils/color_utils.h>
15 
16 #include <QRegExp>
17 #include <QRegExpValidator>
18 #include <QStyle>
19 
ApplyLineEdit(QString linePlaceholderText,QWidget * parent)20 ApplyLineEdit::ApplyLineEdit(QString linePlaceholderText, QWidget * parent)
21 : QLineEdit(parent),
22   apply_button_(0)
23 {
24     emptyAllowed_ = false;
25     regex_ = QString();
26 
27     apply_button_ = new StockIconToolButton(parent, "x-filter-apply");
28     apply_button_->setCursor(Qt::ArrowCursor);
29     apply_button_->setEnabled(false);
30     apply_button_->setToolTip(tr("Apply changes"));
31     apply_button_->setIconSize(QSize(24, 14));
32     apply_button_->setMaximumWidth(30);
33     apply_button_->setStyleSheet(
34             "QToolButton {"
35             "  border: none;"
36             "  background: transparent;" // Disables platform style on Windows.
37             "  padding: 0 0 0 0;"
38             "}"
39             );
40 
41 #ifdef Q_OS_MAC
42     setAttribute(Qt::WA_MacSmallSize, true);
43     apply_button_->setAttribute(Qt::WA_MacSmallSize, true);
44 #endif
45 
46     setPlaceholderText(linePlaceholderText);
47 
48     connect(this, &ApplyLineEdit::textEdited, this, &ApplyLineEdit::onTextEdited);
49     connect(this, &ApplyLineEdit::textChanged, this, &ApplyLineEdit::onTextChanged);
50 
51     connect(this, &ApplyLineEdit::returnPressed, this, &ApplyLineEdit::onSubmitContent);
52     connect(apply_button_, &StockIconToolButton::clicked, this, &ApplyLineEdit::onSubmitContent);
53 
54     handleValidation(QString(linePlaceholderText));
55 
56     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
57 }
58 
~ApplyLineEdit()59 ApplyLineEdit::~ApplyLineEdit() {}
60 
setRegEx(QString regex)61 void ApplyLineEdit::setRegEx(QString regex)
62 {
63     regex_ = regex;
64 }
65 
regex()66 QString ApplyLineEdit::regex()
67 {
68     return regex_;
69 }
70 
setEmptyAllowed(bool emptyAllowed)71 void ApplyLineEdit::setEmptyAllowed(bool emptyAllowed)
72 {
73     emptyAllowed_ = emptyAllowed;
74 }
75 
emptyAllowed()76 bool ApplyLineEdit::emptyAllowed()
77 {
78     return emptyAllowed_;
79 }
80 
isValidText(QString & text,bool ignoreEmptyCheck)81 bool ApplyLineEdit::isValidText(QString & text, bool ignoreEmptyCheck)
82 {
83     if (text.length() == 0)
84     {
85         if (! ignoreEmptyCheck && ! emptyAllowed_)
86             return false;
87         else if (ignoreEmptyCheck)
88             return true;
89     }
90 
91     if (regex_.length() > 0)
92     {
93         QRegExp rx (regex_);
94         QRegExpValidator v(rx, 0);
95 
96         int pos = 0;
97         if (! rx.isValid() || v.validate(text, pos) != QValidator::Acceptable)
98             return false;
99     }
100 
101     return true;
102 }
103 
onTextEdited(const QString & text)104 void ApplyLineEdit::onTextEdited(const QString & text)
105 {
106     QString newText = QString(text);
107     apply_button_->setEnabled(isValidText(newText));
108     handleValidation(newText);
109 }
110 
onTextChanged(const QString & text)111 void ApplyLineEdit::onTextChanged(const QString & text)
112 {
113     handleValidation(QString(text));
114 }
115 
handleValidation(QString newText)116 void ApplyLineEdit::handleValidation(QString newText)
117 {
118     int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
119 
120     QString style_sheet = QString(
121             "ApplyLineEdit {"
122             "  padding-left: %1px;"
123             "  padding-right: %2px;"
124             "  background-color: %3;"
125             "}"
126             )
127             .arg(frameWidth + 1)
128             .arg(apply_button_->sizeHint().width() + frameWidth)
129             .arg(isValidText(newText, true) ? QString("") : ColorUtils::fromColorT(prefs.gui_text_invalid).name());
130 
131     setStyleSheet(style_sheet);
132 }
133 
resizeEvent(QResizeEvent *)134 void ApplyLineEdit::resizeEvent(QResizeEvent *)
135 {
136     int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
137     QSize apsz = apply_button_->sizeHint();
138 
139     apply_button_->move((contentsRect().right() + pos().x()) - (frameWidth + apsz.width()) - 2,
140                         contentsRect().top() + pos().y());
141 
142     apply_button_->setMinimumHeight(height());
143     apply_button_->setMaximumHeight(height());
144 }
145 
onSubmitContent()146 void ApplyLineEdit::onSubmitContent()
147 {
148     QString data = text();
149     if (! isValidText(data))
150         return;
151 
152     /* Freeze apply button to signal the text has been sent. Will be unfreezed, if the text in the textbox changes again */
153     apply_button_->setEnabled(false);
154 
155     emit textApplied();
156 }
157