1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Solutions component.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 ** of its contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41
42 #include "qtpropertybrowserutils_p.h"
43 #include <QApplication>
44 #include <QPainter>
45 #include <QHBoxLayout>
46 #include <QMouseEvent>
47 #include <QCheckBox>
48 #include <QLineEdit>
49 #include <QMenu>
50 #include <QStyleOption>
51
52 #if QT_VERSION >= 0x040400
53 QT_BEGIN_NAMESPACE
54 #endif
55
QtCursorDatabase()56 QtCursorDatabase::QtCursorDatabase()
57 {
58 appendCursor(Qt::ArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Arrow"),
59 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-arrow.png")));
60 appendCursor(Qt::UpArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Up Arrow"),
61 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-uparrow.png")));
62 appendCursor(Qt::CrossCursor, QCoreApplication::translate("QtCursorDatabase", "Cross"),
63 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-cross.png")));
64 appendCursor(Qt::WaitCursor, QCoreApplication::translate("QtCursorDatabase", "Wait"),
65 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-wait.png")));
66 appendCursor(Qt::IBeamCursor, QCoreApplication::translate("QtCursorDatabase", "IBeam"),
67 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-ibeam.png")));
68 appendCursor(Qt::SizeVerCursor, QCoreApplication::translate("QtCursorDatabase", "Size Vertical"),
69 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizev.png")));
70 appendCursor(Qt::SizeHorCursor, QCoreApplication::translate("QtCursorDatabase", "Size Horizontal"),
71 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeh.png")));
72 appendCursor(Qt::SizeFDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Backslash"),
73 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizef.png")));
74 appendCursor(Qt::SizeBDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Slash"),
75 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeb.png")));
76 appendCursor(Qt::SizeAllCursor, QCoreApplication::translate("QtCursorDatabase", "Size All"),
77 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeall.png")));
78 appendCursor(Qt::BlankCursor, QCoreApplication::translate("QtCursorDatabase", "Blank"),
79 QIcon());
80 appendCursor(Qt::SplitVCursor, QCoreApplication::translate("QtCursorDatabase", "Split Vertical"),
81 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-vsplit.png")));
82 appendCursor(Qt::SplitHCursor, QCoreApplication::translate("QtCursorDatabase", "Split Horizontal"),
83 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hsplit.png")));
84 appendCursor(Qt::PointingHandCursor, QCoreApplication::translate("QtCursorDatabase", "Pointing Hand"),
85 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hand.png")));
86 appendCursor(Qt::ForbiddenCursor, QCoreApplication::translate("QtCursorDatabase", "Forbidden"),
87 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-forbidden.png")));
88 appendCursor(Qt::OpenHandCursor, QCoreApplication::translate("QtCursorDatabase", "Open Hand"),
89 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-openhand.png")));
90 appendCursor(Qt::ClosedHandCursor, QCoreApplication::translate("QtCursorDatabase", "Closed Hand"),
91 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-closedhand.png")));
92 appendCursor(Qt::WhatsThisCursor, QCoreApplication::translate("QtCursorDatabase", "What's This"),
93 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-whatsthis.png")));
94 appendCursor(Qt::BusyCursor, QCoreApplication::translate("QtCursorDatabase", "Busy"),
95 QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-busy.png")));
96 }
97
clear()98 void QtCursorDatabase::clear()
99 {
100 m_cursorNames.clear();
101 m_cursorIcons.clear();
102 m_valueToCursorShape.clear();
103 m_cursorShapeToValue.clear();
104 }
105
appendCursor(Qt::CursorShape shape,const QString & name,const QIcon & icon)106 void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon)
107 {
108 if (m_cursorShapeToValue.contains(shape))
109 return;
110 const int value = m_cursorNames.count();
111 m_cursorNames.append(name);
112 m_cursorIcons.insert(value, icon);
113 m_valueToCursorShape.insert(value, shape);
114 m_cursorShapeToValue.insert(shape, value);
115 }
116
cursorShapeNames() const117 QStringList QtCursorDatabase::cursorShapeNames() const
118 {
119 return m_cursorNames;
120 }
121
cursorShapeIcons() const122 QMap<int, QIcon> QtCursorDatabase::cursorShapeIcons() const
123 {
124 return m_cursorIcons;
125 }
126
cursorToShapeName(const QCursor & cursor) const127 QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const
128 {
129 int val = cursorToValue(cursor);
130 if (val >= 0)
131 return m_cursorNames.at(val);
132 return QString();
133 }
134
cursorToShapeIcon(const QCursor & cursor) const135 QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const
136 {
137 int val = cursorToValue(cursor);
138 return m_cursorIcons.value(val);
139 }
140
cursorToValue(const QCursor & cursor) const141 int QtCursorDatabase::cursorToValue(const QCursor &cursor) const
142 {
143 #ifndef QT_NO_CURSOR
144 Qt::CursorShape shape = cursor.shape();
145 if (m_cursorShapeToValue.contains(shape))
146 return m_cursorShapeToValue[shape];
147 #endif
148 return -1;
149 }
150
151 #ifndef QT_NO_CURSOR
valueToCursor(int value) const152 QCursor QtCursorDatabase::valueToCursor(int value) const
153 {
154 if (m_valueToCursorShape.contains(value))
155 return QCursor(m_valueToCursorShape[value]);
156 return QCursor();
157 }
158 #endif
159
brushValuePixmap(const QBrush & b)160 QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b)
161 {
162 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
163 img.fill(0);
164
165 QPainter painter(&img);
166 painter.setCompositionMode(QPainter::CompositionMode_Source);
167 painter.fillRect(0, 0, img.width(), img.height(), b);
168 QColor color = b.color();
169 if (color.alpha() != 255) { // indicate alpha by an inset
170 QBrush opaqueBrush = b;
171 color.setAlpha(255);
172 opaqueBrush.setColor(color);
173 painter.fillRect(img.width() / 4, img.height() / 4,
174 img.width() / 2, img.height() / 2, opaqueBrush);
175 }
176 painter.end();
177 return QPixmap::fromImage(img);
178 }
179
brushValueIcon(const QBrush & b)180 QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b)
181 {
182 return QIcon(brushValuePixmap(b));
183 }
184
colorValueText(const QColor & c)185 QString QtPropertyBrowserUtils::colorValueText(const QColor &c)
186 {
187 return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2, %3] (%4)")
188 .arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
189 }
190
fontValuePixmap(const QFont & font)191 QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font)
192 {
193 QFont f = font;
194 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
195 img.fill(0);
196 QPainter p(&img);
197 p.setRenderHint(QPainter::TextAntialiasing, true);
198 p.setRenderHint(QPainter::Antialiasing, true);
199 f.setPointSize(13);
200 p.setFont(f);
201 QTextOption t;
202 t.setAlignment(Qt::AlignCenter);
203 p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t);
204 return QPixmap::fromImage(img);
205 }
206
fontValueIcon(const QFont & f)207 QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f)
208 {
209 return QIcon(fontValuePixmap(f));
210 }
211
fontValueText(const QFont & f)212 QString QtPropertyBrowserUtils::fontValueText(const QFont &f)
213 {
214 return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2]")
215 .arg(f.family()).arg(f.pointSize());
216 }
217
218
QtBoolEdit(QWidget * parent)219 QtBoolEdit::QtBoolEdit(QWidget *parent) :
220 QWidget(parent),
221 m_checkBox(new QCheckBox(this)),
222 m_textVisible(true)
223 {
224 QHBoxLayout *lt = new QHBoxLayout;
225 if (QApplication::layoutDirection() == Qt::LeftToRight)
226 lt->setContentsMargins(4, 0, 0, 0);
227 else
228 lt->setContentsMargins(0, 0, 4, 0);
229 lt->addWidget(m_checkBox);
230 setLayout(lt);
231 connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
232 setFocusProxy(m_checkBox);
233 m_checkBox->setText(tr("True"));
234 }
235
setTextVisible(bool textVisible)236 void QtBoolEdit::setTextVisible(bool textVisible)
237 {
238 if (m_textVisible == textVisible)
239 return;
240
241 m_textVisible = textVisible;
242 if (m_textVisible)
243 m_checkBox->setText(isChecked() ? tr("True") : tr("False"));
244 else
245 m_checkBox->setText(QString());
246 }
247
checkState() const248 Qt::CheckState QtBoolEdit::checkState() const
249 {
250 return m_checkBox->checkState();
251 }
252
setCheckState(Qt::CheckState state)253 void QtBoolEdit::setCheckState(Qt::CheckState state)
254 {
255 m_checkBox->setCheckState(state);
256 }
257
isChecked() const258 bool QtBoolEdit::isChecked() const
259 {
260 return m_checkBox->isChecked();
261 }
262
setChecked(bool c)263 void QtBoolEdit::setChecked(bool c)
264 {
265 m_checkBox->setChecked(c);
266 if (!m_textVisible)
267 return;
268 m_checkBox->setText(isChecked() ? tr("True") : tr("False"));
269 }
270
blockCheckBoxSignals(bool block)271 bool QtBoolEdit::blockCheckBoxSignals(bool block)
272 {
273 return m_checkBox->blockSignals(block);
274 }
275
mousePressEvent(QMouseEvent * event)276 void QtBoolEdit::mousePressEvent(QMouseEvent *event)
277 {
278 if (event->buttons() == Qt::LeftButton) {
279 m_checkBox->click();
280 event->accept();
281 } else {
282 QWidget::mousePressEvent(event);
283 }
284 }
285
paintEvent(QPaintEvent *)286 void QtBoolEdit::paintEvent(QPaintEvent *)
287 {
288 QStyleOption opt;
289 opt.init(this);
290 QPainter p(this);
291 style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
292 }
293
294
295
QtKeySequenceEdit(QWidget * parent)296 QtKeySequenceEdit::QtKeySequenceEdit(QWidget *parent)
297 : QWidget(parent), m_num(0), m_lineEdit(new QLineEdit(this))
298 {
299 QHBoxLayout *layout = new QHBoxLayout(this);
300 layout->addWidget(m_lineEdit);
301 layout->setMargin(0);
302 m_lineEdit->installEventFilter(this);
303 m_lineEdit->setReadOnly(true);
304 m_lineEdit->setFocusProxy(this);
305 setFocusPolicy(m_lineEdit->focusPolicy());
306 setAttribute(Qt::WA_InputMethodEnabled);
307 }
308
eventFilter(QObject * o,QEvent * e)309 bool QtKeySequenceEdit::eventFilter(QObject *o, QEvent *e)
310 {
311 if (o == m_lineEdit && e->type() == QEvent::ContextMenu) {
312 QContextMenuEvent *c = static_cast<QContextMenuEvent *>(e);
313 QMenu *menu = m_lineEdit->createStandardContextMenu();
314 const QList<QAction *> actions = menu->actions();
315 QListIterator<QAction *> itAction(actions);
316 while (itAction.hasNext()) {
317 QAction *action = itAction.next();
318 action->setShortcut(QKeySequence());
319 QString actionString = action->text();
320 const int pos = actionString.lastIndexOf(QLatin1Char('\t'));
321 if (pos > 0)
322 actionString.remove(pos, actionString.length() - pos);
323 action->setText(actionString);
324 }
325 QAction *actionBefore = 0;
326 if (actions.count() > 0)
327 actionBefore = actions[0];
328 QAction *clearAction = new QAction(tr("Clear Shortcut"), menu);
329 menu->insertAction(actionBefore, clearAction);
330 menu->insertSeparator(actionBefore);
331 clearAction->setEnabled(!m_keySequence.isEmpty());
332 connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearShortcut()));
333 menu->exec(c->globalPos());
334 delete menu;
335 e->accept();
336 return true;
337 }
338
339 return QWidget::eventFilter(o, e);
340 }
341
slotClearShortcut()342 void QtKeySequenceEdit::slotClearShortcut()
343 {
344 if (m_keySequence.isEmpty())
345 return;
346 setKeySequence(QKeySequence());
347 emit keySequenceChanged(m_keySequence);
348 }
349
handleKeyEvent(QKeyEvent * e)350 void QtKeySequenceEdit::handleKeyEvent(QKeyEvent *e)
351 {
352 int nextKey = e->key();
353 if (nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift ||
354 nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt ||
355 nextKey == Qt::Key_Super_L || nextKey == Qt::Key_AltGr)
356 return;
357
358 nextKey |= translateModifiers(e->modifiers(), e->text());
359 int k0 = m_keySequence[0];
360 int k1 = m_keySequence[1];
361 int k2 = m_keySequence[2];
362 int k3 = m_keySequence[3];
363 switch (m_num) {
364 case 0: k0 = nextKey; k1 = 0; k2 = 0; k3 = 0; break;
365 case 1: k1 = nextKey; k2 = 0; k3 = 0; break;
366 case 2: k2 = nextKey; k3 = 0; break;
367 case 3: k3 = nextKey; break;
368 default: break;
369 }
370 ++m_num;
371 if (m_num > 3)
372 m_num = 0;
373 m_keySequence = QKeySequence(k0, k1, k2, k3);
374 m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText));
375 e->accept();
376 emit keySequenceChanged(m_keySequence);
377 }
378
setKeySequence(const QKeySequence & sequence)379 void QtKeySequenceEdit::setKeySequence(const QKeySequence &sequence)
380 {
381 if (sequence == m_keySequence)
382 return;
383 m_num = 0;
384 m_keySequence = sequence;
385 m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText));
386 }
387
keySequence() const388 QKeySequence QtKeySequenceEdit::keySequence() const
389 {
390 return m_keySequence;
391 }
392
translateModifiers(Qt::KeyboardModifiers state,const QString & text) const393 int QtKeySequenceEdit::translateModifiers(Qt::KeyboardModifiers state, const QString &text) const
394 {
395 int result = 0;
396 if ((state & Qt::ShiftModifier) && (text.size() == 0 || !text.at(0).isPrint() || text.at(0).isLetter() || text.at(0).isSpace()))
397 result |= Qt::SHIFT;
398 if (state & Qt::ControlModifier)
399 result |= Qt::CTRL;
400 if (state & Qt::MetaModifier)
401 result |= Qt::META;
402 if (state & Qt::AltModifier)
403 result |= Qt::ALT;
404 return result;
405 }
406
focusInEvent(QFocusEvent * e)407 void QtKeySequenceEdit::focusInEvent(QFocusEvent *e)
408 {
409 m_lineEdit->event(e);
410 m_lineEdit->selectAll();
411 QWidget::focusInEvent(e);
412 }
413
focusOutEvent(QFocusEvent * e)414 void QtKeySequenceEdit::focusOutEvent(QFocusEvent *e)
415 {
416 m_num = 0;
417 m_lineEdit->event(e);
418 QWidget::focusOutEvent(e);
419 }
420
keyPressEvent(QKeyEvent * e)421 void QtKeySequenceEdit::keyPressEvent(QKeyEvent *e)
422 {
423 handleKeyEvent(e);
424 e->accept();
425 }
426
keyReleaseEvent(QKeyEvent * e)427 void QtKeySequenceEdit::keyReleaseEvent(QKeyEvent *e)
428 {
429 m_lineEdit->event(e);
430 }
431
paintEvent(QPaintEvent *)432 void QtKeySequenceEdit::paintEvent(QPaintEvent *)
433 {
434 QStyleOption opt;
435 opt.init(this);
436 QPainter p(this);
437 style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
438 }
439
event(QEvent * e)440 bool QtKeySequenceEdit::event(QEvent *e)
441 {
442 if (e->type() == QEvent::Shortcut ||
443 e->type() == QEvent::ShortcutOverride ||
444 e->type() == QEvent::KeyRelease) {
445 e->accept();
446 return true;
447 }
448 return QWidget::event(e);
449 }
450
451
452
453
454 #if QT_VERSION >= 0x040400
455 QT_END_NAMESPACE
456 #endif
457