1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "filterwidget_p.h"
43 #include "iconloader_p.h"
44
45 #include <QtGui/QVBoxLayout>
46 #include <QtGui/QHBoxLayout>
47 #include <QtGui/QLineEdit>
48 #include <QtGui/QFocusEvent>
49 #include <QtGui/QPalette>
50 #include <QtGui/QCursor>
51 #include <QtGui/QToolButton>
52 #include <QtGui/QPainter>
53 #include <QtGui/QStyle>
54 #include <QtGui/QStyleOption>
55
56 #include <QtCore/QDebug>
57 #include <QtCore/QPropertyAnimation>
58
59 enum { debugFilter = 0 };
60
61 QT_BEGIN_NAMESPACE
62
63 namespace qdesigner_internal {
64
HintLineEdit(QWidget * parent)65 HintLineEdit::HintLineEdit(QWidget *parent) :
66 QLineEdit(parent),
67 m_defaultFocusPolicy(focusPolicy()),
68 m_refuseFocus(false)
69 {
70 }
71
IconButton(QWidget * parent)72 IconButton::IconButton(QWidget *parent)
73 : QToolButton(parent)
74 {
75 #ifndef QT_NO_CURSOR
76 setCursor(Qt::ArrowCursor);
77 #endif
78 }
79
paintEvent(QPaintEvent *)80 void IconButton::paintEvent(QPaintEvent *)
81 {
82 QPainter painter(this);
83 // Note isDown should really use the active state but in most styles
84 // this has no proper feedback
85 QIcon::Mode state = QIcon::Disabled;
86 if (isEnabled())
87 state = isDown() ? QIcon::Selected : QIcon::Normal;
88 QPixmap iconpixmap = icon().pixmap(QSize(ICONBUTTON_SIZE, ICONBUTTON_SIZE),
89 state, QIcon::Off);
90 QRect pixmapRect = QRect(0, 0, iconpixmap.width(), iconpixmap.height());
91 pixmapRect.moveCenter(rect().center());
92 painter.setOpacity(m_fader);
93 painter.drawPixmap(pixmapRect, iconpixmap);
94 }
95
animateShow(bool visible)96 void IconButton::animateShow(bool visible)
97 {
98 if (visible) {
99 QPropertyAnimation *animation = new QPropertyAnimation(this, "fader");
100 animation->setDuration(160);
101 animation->setEndValue(1.0);
102 animation->start(QAbstractAnimation::DeleteWhenStopped);
103 } else {
104 QPropertyAnimation *animation = new QPropertyAnimation(this, "fader");
105 animation->setDuration(160);
106 animation->setEndValue(0.0);
107 animation->start(QAbstractAnimation::DeleteWhenStopped);
108 }
109 }
110
refuseFocus() const111 bool HintLineEdit::refuseFocus() const
112 {
113 return m_refuseFocus;
114 }
115
setRefuseFocus(bool v)116 void HintLineEdit::setRefuseFocus(bool v)
117 {
118 if (v == m_refuseFocus)
119 return;
120 m_refuseFocus = v;
121 setFocusPolicy(m_refuseFocus ? Qt::NoFocus : m_defaultFocusPolicy);
122 }
123
mousePressEvent(QMouseEvent * e)124 void HintLineEdit::mousePressEvent(QMouseEvent *e)
125 {
126 if (debugFilter)
127 qDebug() << Q_FUNC_INFO;
128 // Explicitly focus on click.
129 if (m_refuseFocus && !hasFocus())
130 setFocus(Qt::OtherFocusReason);
131 QLineEdit::mousePressEvent(e);
132 }
133
focusInEvent(QFocusEvent * e)134 void HintLineEdit::focusInEvent(QFocusEvent *e)
135 {
136 if (debugFilter)
137 qDebug() << Q_FUNC_INFO;
138 if (m_refuseFocus) {
139 // Refuse the focus if the mouse it outside. In addition to the mouse
140 // press logic, this prevents a re-focussing which occurs once
141 // we actually had focus
142 const Qt::FocusReason reason = e->reason();
143 if (reason == Qt::ActiveWindowFocusReason || reason == Qt::PopupFocusReason) {
144 const QPoint mousePos = mapFromGlobal(QCursor::pos());
145 const bool refuse = !geometry().contains(mousePos);
146 if (debugFilter)
147 qDebug() << Q_FUNC_INFO << refuse ;
148 if (refuse) {
149 e->ignore();
150 return;
151 }
152 }
153 }
154
155 QLineEdit::focusInEvent(e);
156 }
157
158 // ------------------- FilterWidget
FilterWidget(QWidget * parent,LayoutMode lm)159 FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) :
160 QWidget(parent),
161 m_editor(new HintLineEdit(this)),
162 m_button(new IconButton(m_editor)),
163 m_buttonwidth(0)
164 {
165 m_editor->setPlaceholderText(tr("Filter"));
166
167 // Let the style determine minimum height for our widget
168 QSize size(ICONBUTTON_SIZE + 6, ICONBUTTON_SIZE + 2);
169
170 // Note KDE does not reserve space for the highlight color
171 if (style()->inherits("OxygenStyle")) {
172 size = size.expandedTo(QSize(24, 0));
173 }
174
175 // Make room for clear icon
176 QMargins margins = m_editor->textMargins();
177 if (layoutDirection() == Qt::LeftToRight)
178 margins.setRight(size.width());
179 else
180 margins.setLeft(size.width());
181
182 m_editor->setTextMargins(margins);
183
184 QHBoxLayout *l = new QHBoxLayout(this);
185 l->setMargin(0);
186 l->setSpacing(0);
187 if (lm == LayoutAlignRight)
188 l->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
189
190 l->addWidget(m_editor);
191
192 // KDE has custom icons for this. Notice that icon namings are counter intuitive
193 // If these icons are not avaiable we use the freedesktop standard name before
194 // falling back to a bundled resource
195 QIcon icon = QIcon::fromTheme(layoutDirection() == Qt::LeftToRight ?
196 QLatin1String("edit-clear-locationbar-rtl") :
197 QLatin1String("edit-clear-locationbar-ltr"),
198 QIcon::fromTheme("edit-clear", createIconSet(QLatin1String("cleartext.png"))));
199
200 m_button->setIcon(icon);
201 m_button->setToolTip(tr("Clear text"));
202 connect(m_button, SIGNAL(clicked()), this, SLOT(reset()));
203 connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(checkButton(QString)));
204 connect(m_editor, SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString)));
205 }
206
text() const207 QString FilterWidget::text() const
208 {
209 return m_editor->text();
210 }
211
checkButton(const QString & text)212 void FilterWidget::checkButton(const QString &text)
213 {
214 if (m_oldText.isEmpty() || text.isEmpty())
215 m_button->animateShow(!m_editor->text().isEmpty());
216 m_oldText = text;
217 }
218
reset()219 void FilterWidget::reset()
220 {
221 if (debugFilter)
222 qDebug() << Q_FUNC_INFO;
223
224 if (!m_editor->text().isEmpty()) {
225 // Editor has lost focus once this is pressed
226 m_editor->clear();
227 emit filterChanged(QString());
228 }
229 }
230
resizeEvent(QResizeEvent *)231 void FilterWidget::resizeEvent(QResizeEvent *)
232 {
233 QRect contentRect = m_editor->rect();
234 if (layoutDirection() == Qt::LeftToRight) {
235 const int iconoffset = m_editor->textMargins().right() + 4;
236 m_button->setGeometry(contentRect.adjusted(m_editor->width() - iconoffset, 0, 0, 0));
237 } else {
238 const int iconoffset = m_editor->textMargins().left() + 4;
239 m_button->setGeometry(contentRect.adjusted(0, 0, -m_editor->width() + iconoffset, 0));
240 }
241 }
242
refuseFocus() const243 bool FilterWidget::refuseFocus() const
244 {
245 return m_editor->refuseFocus();
246 }
247
setRefuseFocus(bool v)248 void FilterWidget::setRefuseFocus(bool v)
249 {
250 m_editor->setRefuseFocus(v);
251 }
252 } // namespace qdesigner_internal
253
254 QT_END_NAMESPACE
255