1 #include "searchlineedit.h"
2 #include "autocomplete.h"
3 #include "iconutils.h"
4 
5 class SearchButton : public QAbstractButton {
6 public:
7     SearchButton(QWidget *parent = nullptr);
8     QMenu *m_menu;
9 
10 protected:
11     void paintEvent(QPaintEvent *e);
12     void mousePressEvent(QMouseEvent *e);
13 };
14 
SearchButton(QWidget * parent)15 SearchButton::SearchButton(QWidget *parent) : QAbstractButton(parent), m_menu(nullptr) {
16     setObjectName(QLatin1String("SearchButton"));
17     setCursor(Qt::ArrowCursor);
18     setFocusPolicy(Qt::NoFocus);
19 }
20 
mousePressEvent(QMouseEvent * e)21 void SearchButton::mousePressEvent(QMouseEvent *e) {
22     if (m_menu && e->button() == Qt::LeftButton) {
23         QWidget *p = parentWidget();
24         if (p) {
25             QPoint r = p->mapToGlobal(QPoint(0, p->height()));
26             m_menu->exec(QPoint(r.x() + height() / 2, r.y()));
27         }
28         e->accept();
29     }
30     QAbstractButton::mousePressEvent(e);
31 }
32 
paintEvent(QPaintEvent * e)33 void SearchButton::paintEvent(QPaintEvent *e) {
34     Q_UNUSED(e);
35     QPainter painter(this);
36     const int h = height();
37     int iconSize = 16;
38     if (h > 32) iconSize = 22;
39     QPixmap p = IconUtils::icon("edit-find").pixmap(iconSize, iconSize);
40     int x = (width() - p.width() / p.devicePixelRatio()) / 2;
41     int y = (h - p.height() / p.devicePixelRatio()) / 2;
42     painter.drawPixmap(x, y, p);
43 }
44 
SearchLineEdit(QWidget * parent)45 SearchLineEdit::SearchLineEdit(QWidget *parent)
46     : ExLineEdit(parent), searchButton(new SearchButton(this)) {
47     connect(m_lineEdit, SIGNAL(textChanged(const QString &)), SIGNAL(textChanged(const QString &)));
48     connect(m_lineEdit, SIGNAL(textEdited(const QString &)), SIGNAL(textEdited(const QString &)));
49     connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(returnPressed()));
50 
51     setLeftWidget(searchButton);
52     inactiveText = tr("Search");
53 
54     QSizePolicy policy = sizePolicy();
55     setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy());
56 
57     // completion
58     autoComplete = new AutoComplete(this, m_lineEdit);
59     connect(autoComplete, SIGNAL(suggestionAccepted(Suggestion *)),
60             SIGNAL(suggestionAccepted(Suggestion *)));
61 }
62 
paintEvent(QPaintEvent * e)63 void SearchLineEdit::paintEvent(QPaintEvent *e) {
64     ExLineEdit::paintEvent(e);
65     if (m_lineEdit->text().isEmpty() && !hasFocus() && !inactiveText.isEmpty()) {
66         QStyleOptionFrame panel;
67         initStyleOption(&panel);
68         QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
69         QFontMetrics fm = fontMetrics();
70         int horizontalMargin = m_lineEdit->x();
71         QRect lineRect(horizontalMargin + r.x(), r.y() + (r.height() - fm.height() + 1) / 2,
72                        r.width() - 2 * horizontalMargin, fm.height());
73         QPainter painter(this);
74         painter.setPen(palette().brush(QPalette::Disabled, QPalette::Text).color());
75         painter.drawText(lineRect, Qt::AlignLeft | Qt::AlignVCenter, inactiveText);
76     }
77 }
78 
resizeEvent(QResizeEvent * e)79 void SearchLineEdit::resizeEvent(QResizeEvent *e) {
80     updateGeometries();
81     ExLineEdit::resizeEvent(e);
82 }
83 
updateGeometries()84 void SearchLineEdit::updateGeometries() {
85     int menuHeight = height();
86     int menuWidth = menuHeight + 1;
87     if (!searchButton->m_menu) menuWidth = (menuHeight / 5) * 4;
88     searchButton->resize(QSize(menuWidth, menuHeight));
89 }
90 
setInactiveText(const QString & text)91 void SearchLineEdit::setInactiveText(const QString &text) {
92     inactiveText = text;
93 }
94 
setText(const QString & text)95 void SearchLineEdit::setText(const QString &text) {
96     m_lineEdit->setText(text);
97 }
98 
getAutoComplete()99 AutoComplete *SearchLineEdit::getAutoComplete() {
100     return autoComplete;
101 }
102 
setMenu(QMenu * menu)103 void SearchLineEdit::setMenu(QMenu *menu) {
104     if (searchButton->m_menu) searchButton->m_menu->deleteLater();
105     searchButton->m_menu = menu;
106     updateGeometries();
107 }
108 
menu() const109 QMenu *SearchLineEdit::menu() const {
110     if (!searchButton->m_menu) {
111         searchButton->m_menu = new QMenu(searchButton);
112         if (isVisible()) (const_cast<SearchLineEdit *>(this))->updateGeometries();
113     }
114     return searchButton->m_menu;
115 }
116 
returnPressed()117 void SearchLineEdit::returnPressed() {
118     QString text = m_lineEdit->text().simplified();
119     if (!text.isEmpty()) {
120         autoComplete->preventSuggest();
121         emit search(text);
122     }
123 }
124 
enableSuggest()125 void SearchLineEdit::enableSuggest() {
126     autoComplete->enableSuggest();
127 }
128 
preventSuggest()129 void SearchLineEdit::preventSuggest() {
130     autoComplete->preventSuggest();
131 }
132 
selectAll()133 void SearchLineEdit::selectAll() {
134     m_lineEdit->selectAll();
135 }
136 
setSuggester(Suggester * suggester)137 void SearchLineEdit::setSuggester(Suggester *suggester) {
138     autoComplete->setSuggester(suggester);
139 }
140 
focusInEvent(QFocusEvent * e)141 void SearchLineEdit::focusInEvent(QFocusEvent *e) {
142     ExLineEdit::focusInEvent(e);
143     enableSuggest();
144 }
145 
emitTextChanged(const QString & text)146 void SearchLineEdit::emitTextChanged(const QString &text) {
147     autoComplete->enableSuggest();
148     emit textEdited(text);
149 }
150 
text()151 QString SearchLineEdit::text() {
152     return m_lineEdit->text();
153 }
154 
getLineEdit()155 QLineEdit *SearchLineEdit::getLineEdit() {
156     return m_lineEdit;
157 }
158 
setEnabled(bool enabled)159 void SearchLineEdit::setEnabled(bool enabled) {
160     ExLineEdit::setEnabled(enabled);
161     emit enabledChanged(enabled);
162 }
163