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