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