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 tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
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 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 
34 
35 #include "qtpropertybrowserutils_p.h"
36 #include <QtWidgets/QApplication>
37 #include <QtGui/QPainter>
38 #include <QtWidgets/QHBoxLayout>
39 #include <QtGui/QMouseEvent>
40 #include <QtWidgets/QCheckBox>
41 #include <QtWidgets/QLineEdit>
42 #include <QtWidgets/QMenu>
43 #include <QtCore/QLocale>
44 #include <QtWidgets/QStyleOption>
45 
46 QT_BEGIN_NAMESPACE
47 
QtCursorDatabase()48 QtCursorDatabase::QtCursorDatabase()
49 {
50     Q_INIT_RESOURCE(qtpropertybrowser);
51 
52     appendCursor(Qt::ArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Arrow"),
53                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-arrow.png")));
54     appendCursor(Qt::UpArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Up Arrow"),
55                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-uparrow.png")));
56     appendCursor(Qt::CrossCursor, QCoreApplication::translate("QtCursorDatabase", "Cross"),
57                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-cross.png")));
58     appendCursor(Qt::WaitCursor, QCoreApplication::translate("QtCursorDatabase", "Wait"),
59                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-wait.png")));
60     appendCursor(Qt::IBeamCursor, QCoreApplication::translate("QtCursorDatabase", "IBeam"),
61                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-ibeam.png")));
62     appendCursor(Qt::SizeVerCursor, QCoreApplication::translate("QtCursorDatabase", "Size Vertical"),
63                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizev.png")));
64     appendCursor(Qt::SizeHorCursor, QCoreApplication::translate("QtCursorDatabase", "Size Horizontal"),
65                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeh.png")));
66     appendCursor(Qt::SizeFDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Backslash"),
67                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizef.png")));
68     appendCursor(Qt::SizeBDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Slash"),
69                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeb.png")));
70     appendCursor(Qt::SizeAllCursor, QCoreApplication::translate("QtCursorDatabase", "Size All"),
71                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeall.png")));
72     appendCursor(Qt::BlankCursor, QCoreApplication::translate("QtCursorDatabase", "Blank"),
73                  QIcon());
74     appendCursor(Qt::SplitVCursor, QCoreApplication::translate("QtCursorDatabase", "Split Vertical"),
75                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-vsplit.png")));
76     appendCursor(Qt::SplitHCursor, QCoreApplication::translate("QtCursorDatabase", "Split Horizontal"),
77                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hsplit.png")));
78     appendCursor(Qt::PointingHandCursor, QCoreApplication::translate("QtCursorDatabase", "Pointing Hand"),
79                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hand.png")));
80     appendCursor(Qt::ForbiddenCursor, QCoreApplication::translate("QtCursorDatabase", "Forbidden"),
81                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-forbidden.png")));
82     appendCursor(Qt::OpenHandCursor, QCoreApplication::translate("QtCursorDatabase", "Open Hand"),
83                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-openhand.png")));
84     appendCursor(Qt::ClosedHandCursor, QCoreApplication::translate("QtCursorDatabase", "Closed Hand"),
85                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-closedhand.png")));
86     appendCursor(Qt::WhatsThisCursor, QCoreApplication::translate("QtCursorDatabase", "What's This"),
87                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-whatsthis.png")));
88     appendCursor(Qt::BusyCursor, QCoreApplication::translate("QtCursorDatabase", "Busy"),
89                  QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-busy.png")));
90 }
91 
clear()92 void QtCursorDatabase::clear()
93 {
94     m_cursorNames.clear();
95     m_cursorIcons.clear();
96     m_valueToCursorShape.clear();
97     m_cursorShapeToValue.clear();
98 }
99 
appendCursor(Qt::CursorShape shape,const QString & name,const QIcon & icon)100 void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon)
101 {
102     if (m_cursorShapeToValue.contains(shape))
103         return;
104     const int value = m_cursorNames.count();
105     m_cursorNames.append(name);
106     m_cursorIcons.insert(value, icon);
107     m_valueToCursorShape.insert(value, shape);
108     m_cursorShapeToValue.insert(shape, value);
109 }
110 
cursorShapeNames() const111 QStringList QtCursorDatabase::cursorShapeNames() const
112 {
113     return m_cursorNames;
114 }
115 
cursorShapeIcons() const116 QMap<int, QIcon> QtCursorDatabase::cursorShapeIcons() const
117 {
118     return m_cursorIcons;
119 }
120 
cursorToShapeName(const QCursor & cursor) const121 QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const
122 {
123     int val = cursorToValue(cursor);
124     if (val >= 0)
125         return m_cursorNames.at(val);
126     return QString();
127 }
128 
cursorToShapeIcon(const QCursor & cursor) const129 QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const
130 {
131     int val = cursorToValue(cursor);
132     return m_cursorIcons.value(val);
133 }
134 
cursorToValue(const QCursor & cursor) const135 int QtCursorDatabase::cursorToValue(const QCursor &cursor) const
136 {
137 #ifndef QT_NO_CURSOR
138     Qt::CursorShape shape = cursor.shape();
139     if (m_cursorShapeToValue.contains(shape))
140         return m_cursorShapeToValue[shape];
141 #endif
142     return -1;
143 }
144 
145 #ifndef QT_NO_CURSOR
valueToCursor(int value) const146 QCursor QtCursorDatabase::valueToCursor(int value) const
147 {
148     if (m_valueToCursorShape.contains(value))
149         return QCursor(m_valueToCursorShape[value]);
150     return QCursor();
151 }
152 #endif
153 
brushValuePixmap(const QBrush & b)154 QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b)
155 {
156     QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
157     img.fill(0);
158 
159     QPainter painter(&img);
160     painter.setCompositionMode(QPainter::CompositionMode_Source);
161     painter.fillRect(0, 0, img.width(), img.height(), b);
162     QColor color = b.color();
163     if (color.alpha() != 255) { // indicate alpha by an inset
164         QBrush  opaqueBrush = b;
165         color.setAlpha(255);
166         opaqueBrush.setColor(color);
167         painter.fillRect(img.width() / 4, img.height() / 4,
168                          img.width() / 2, img.height() / 2, opaqueBrush);
169     }
170     painter.end();
171     return QPixmap::fromImage(img);
172 }
173 
brushValueIcon(const QBrush & b)174 QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b)
175 {
176     return QIcon(brushValuePixmap(b));
177 }
178 
colorValueText(const QColor & c)179 QString QtPropertyBrowserUtils::colorValueText(const QColor &c)
180 {
181     return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2, %3] (%4)")
182            .arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
183 }
184 
fontValuePixmap(const QFont & font)185 QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font)
186 {
187     QFont f = font;
188     QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
189     img.fill(0);
190     QPainter p(&img);
191     p.setRenderHint(QPainter::TextAntialiasing, true);
192     p.setRenderHint(QPainter::Antialiasing, true);
193     f.setPointSize(13);
194     p.setFont(f);
195     QTextOption t;
196     t.setAlignment(Qt::AlignCenter);
197     p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t);
198     return QPixmap::fromImage(img);
199 }
200 
fontValueIcon(const QFont & f)201 QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f)
202 {
203     return QIcon(fontValuePixmap(f));
204 }
205 
fontValueText(const QFont & f)206 QString QtPropertyBrowserUtils::fontValueText(const QFont &f)
207 {
208     return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2]")
209            .arg(f.family()).arg(f.pointSize());
210 }
211 
trimDecimalZeros(const QChar & point,const QString & text)212 QString QtPropertyBrowserUtils::trimDecimalZeros(const QChar &point, const QString &text)
213 {
214 	int idx = text.indexOf(point);
215 	if (idx >= 0)
216 	{
217 		QString corrText(text);
218 		while (corrText.endsWith('0'))
219 			corrText.chop(1);
220 		if (corrText.endsWith(point))
221 			corrText.chop(1);
222 		return corrText;
223 	}
224 	else
225 		return text;
226 }
227 
dateFormat()228 QString QtPropertyBrowserUtils::dateFormat()
229 {
230     QLocale loc;
231     return loc.dateFormat(QLocale::ShortFormat);
232 }
233 
timeFormat()234 QString QtPropertyBrowserUtils::timeFormat()
235 {
236     QLocale loc;
237     // ShortFormat is missing seconds on UNIX.
238     return loc.timeFormat(QLocale::LongFormat);
239 }
240 
dateTimeFormat()241 QString QtPropertyBrowserUtils::dateTimeFormat()
242 {
243     QString format = dateFormat();
244     format += QLatin1Char(' ');
245     format += timeFormat();
246     return format;
247 }
248 
249 
QtBoolEdit(QWidget * parent)250 QtBoolEdit::QtBoolEdit(QWidget *parent) :
251     QWidget(parent),
252     m_checkBox(new QCheckBox(this)),
253     m_textVisible(true)
254 {
255     QHBoxLayout *lt = new QHBoxLayout;
256     if (QApplication::layoutDirection() == Qt::LeftToRight)
257         lt->setContentsMargins(4, 0, 0, 0);
258     else
259         lt->setContentsMargins(0, 0, 4, 0);
260     lt->addWidget(m_checkBox);
261     setLayout(lt);
262     connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
263     setFocusProxy(m_checkBox);
264     m_checkBox->setText(tr("True"));
265 }
266 
setTextVisible(bool textVisible)267 void QtBoolEdit::setTextVisible(bool textVisible)
268 {
269     if (m_textVisible == textVisible)
270         return;
271 
272     m_textVisible = textVisible;
273     if (m_textVisible)
274         m_checkBox->setText(isChecked() ? tr("True") : tr("False"));
275     else
276         m_checkBox->setText(QString());
277 }
278 
checkState() const279 Qt::CheckState QtBoolEdit::checkState() const
280 {
281     return m_checkBox->checkState();
282 }
283 
setCheckState(Qt::CheckState state)284 void QtBoolEdit::setCheckState(Qt::CheckState state)
285 {
286     m_checkBox->setCheckState(state);
287 }
288 
isChecked() const289 bool QtBoolEdit::isChecked() const
290 {
291     return m_checkBox->isChecked();
292 }
293 
setChecked(bool c)294 void QtBoolEdit::setChecked(bool c)
295 {
296     m_checkBox->setChecked(c);
297     if (!m_textVisible)
298         return;
299     m_checkBox->setText(isChecked() ? tr("True") : tr("False"));
300 }
301 
blockCheckBoxSignals(bool block)302 bool QtBoolEdit::blockCheckBoxSignals(bool block)
303 {
304     return m_checkBox->blockSignals(block);
305 }
306 
mousePressEvent(QMouseEvent * event)307 void QtBoolEdit::mousePressEvent(QMouseEvent *event)
308 {
309     if (event->buttons() == Qt::LeftButton) {
310         m_checkBox->click();
311         event->accept();
312     } else {
313         QWidget::mousePressEvent(event);
314     }
315 }
316 
paintEvent(QPaintEvent *)317 void QtBoolEdit::paintEvent(QPaintEvent *)
318 {
319     QStyleOption opt;
320     opt.init(this);
321     QPainter p(this);
322     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
323 }
324 
325 
326 
QtKeySequenceEdit(QWidget * parent)327 QtKeySequenceEdit::QtKeySequenceEdit(QWidget *parent)
328     : QWidget(parent), m_num(0), m_lineEdit(new QLineEdit(this))
329 {
330     QHBoxLayout *layout = new QHBoxLayout(this);
331     layout->addWidget(m_lineEdit);
332     layout->setMargin(0);
333     m_lineEdit->installEventFilter(this);
334     m_lineEdit->setReadOnly(true);
335     m_lineEdit->setFocusProxy(this);
336     setFocusPolicy(m_lineEdit->focusPolicy());
337     setAttribute(Qt::WA_InputMethodEnabled);
338 }
339 
eventFilter(QObject * o,QEvent * e)340 bool QtKeySequenceEdit::eventFilter(QObject *o, QEvent *e)
341 {
342     if (o == m_lineEdit && e->type() == QEvent::ContextMenu) {
343         QContextMenuEvent *c = static_cast<QContextMenuEvent *>(e);
344         QMenu *menu = m_lineEdit->createStandardContextMenu();
345         const QList<QAction *> actions = menu->actions();
346         QListIterator<QAction *> itAction(actions);
347         while (itAction.hasNext()) {
348             QAction *action = itAction.next();
349             action->setShortcut(QKeySequence());
350             QString actionString = action->text();
351             const int pos = actionString.lastIndexOf(QLatin1Char('\t'));
352             if (pos > 0)
353                 actionString.remove(pos, actionString.length() - pos);
354             action->setText(actionString);
355         }
356         QAction *actionBefore = 0;
357         if (actions.count() > 0)
358             actionBefore = actions[0];
359         QAction *clearAction = new QAction(tr("Clear Shortcut"), menu);
360         menu->insertAction(actionBefore, clearAction);
361         menu->insertSeparator(actionBefore);
362         clearAction->setEnabled(!m_keySequence.isEmpty());
363         connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearShortcut()));
364         menu->exec(c->globalPos());
365         delete menu;
366         e->accept();
367         return true;
368     }
369 
370     return QWidget::eventFilter(o, e);
371 }
372 
slotClearShortcut()373 void QtKeySequenceEdit::slotClearShortcut()
374 {
375     if (m_keySequence.isEmpty())
376         return;
377     setKeySequence(QKeySequence());
378     emit keySequenceChanged(m_keySequence);
379 }
380 
handleKeyEvent(QKeyEvent * e)381 void QtKeySequenceEdit::handleKeyEvent(QKeyEvent *e)
382 {
383     int nextKey = e->key();
384     if (nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift ||
385             nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt ||
386             nextKey == Qt::Key_Super_L || nextKey == Qt::Key_AltGr)
387         return;
388 
389     nextKey |= translateModifiers(e->modifiers(), e->text());
390     int k0 = m_keySequence[0];
391     int k1 = m_keySequence[1];
392     int k2 = m_keySequence[2];
393     int k3 = m_keySequence[3];
394     switch (m_num) {
395         case 0: k0 = nextKey; k1 = 0; k2 = 0; k3 = 0; break;
396         case 1: k1 = nextKey; k2 = 0; k3 = 0; break;
397         case 2: k2 = nextKey; k3 = 0; break;
398         case 3: k3 = nextKey; break;
399         default: break;
400     }
401     ++m_num;
402     if (m_num > 3)
403         m_num = 0;
404     m_keySequence = QKeySequence(k0, k1, k2, k3);
405     m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText));
406     e->accept();
407     emit keySequenceChanged(m_keySequence);
408 }
409 
setKeySequence(const QKeySequence & sequence)410 void QtKeySequenceEdit::setKeySequence(const QKeySequence &sequence)
411 {
412     if (sequence == m_keySequence)
413         return;
414     m_num = 0;
415     m_keySequence = sequence;
416     m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText));
417 }
418 
keySequence() const419 QKeySequence QtKeySequenceEdit::keySequence() const
420 {
421     return m_keySequence;
422 }
423 
translateModifiers(Qt::KeyboardModifiers state,const QString & text) const424 int QtKeySequenceEdit::translateModifiers(Qt::KeyboardModifiers state, const QString &text) const
425 {
426     int result = 0;
427     if ((state & Qt::ShiftModifier) && (text.size() == 0 || !text.at(0).isPrint() || text.at(0).isLetter() || text.at(0).isSpace()))
428         result |= Qt::SHIFT;
429     if (state & Qt::ControlModifier)
430         result |= Qt::CTRL;
431     if (state & Qt::MetaModifier)
432         result |= Qt::META;
433     if (state & Qt::AltModifier)
434         result |= Qt::ALT;
435     return result;
436 }
437 
focusInEvent(QFocusEvent * e)438 void QtKeySequenceEdit::focusInEvent(QFocusEvent *e)
439 {
440     m_lineEdit->event(e);
441     m_lineEdit->selectAll();
442     QWidget::focusInEvent(e);
443 }
444 
focusOutEvent(QFocusEvent * e)445 void QtKeySequenceEdit::focusOutEvent(QFocusEvent *e)
446 {
447     m_num = 0;
448     m_lineEdit->event(e);
449     QWidget::focusOutEvent(e);
450 }
451 
keyPressEvent(QKeyEvent * e)452 void QtKeySequenceEdit::keyPressEvent(QKeyEvent *e)
453 {
454     handleKeyEvent(e);
455     e->accept();
456 }
457 
keyReleaseEvent(QKeyEvent * e)458 void QtKeySequenceEdit::keyReleaseEvent(QKeyEvent *e)
459 {
460     m_lineEdit->event(e);
461 }
462 
paintEvent(QPaintEvent *)463 void QtKeySequenceEdit::paintEvent(QPaintEvent *)
464 {
465     QStyleOption opt;
466     opt.init(this);
467     QPainter p(this);
468     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
469 }
470 
event(QEvent * e)471 bool QtKeySequenceEdit::event(QEvent *e)
472 {
473     if (e->type() == QEvent::Shortcut ||
474             e->type() == QEvent::ShortcutOverride  ||
475             e->type() == QEvent::KeyRelease) {
476         e->accept();
477         return true;
478     }
479     return QWidget::event(e);
480 }
481 
482 
483 QT_END_NAMESPACE
484