OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / components / navigator / navigatortreeview.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "navigatortreeview.h"
34
35 #include <qmath.h>
36
37 #include "navigatorview.h"
38 #include "navigatortreemodel.h"
39 #include "navigatorwidget.h"
40 #include "qproxystyle.h"
41
42 #include <nodeproperty.h>
43 #include "metainfo.h"
44 #include <QLineEdit>
45 #include <QPen>
46 #include <QPixmapCache>
47
48
49 static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
50 {
51     const qreal radiusBase = qMax(qreal(1), maxRadius);
52
53     QString key = QLatin1String("WaveUnderline-Bauhaus");
54
55     QPixmap pixmap;
56     if (QPixmapCache::find(key, pixmap))
57         return pixmap;
58
59     const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio
60     const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
61     const int radius = qFloor(radiusBase);
62
63     QPainterPath path;
64
65     qreal xs = 0;
66     qreal ys = radius;
67
68     while (xs < width) {
69         xs += halfPeriod;
70         ys = -ys;
71         path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
72     }
73
74     pixmap = QPixmap(width, radius * 2);
75     pixmap.fill(Qt::transparent);
76     {
77         QPen wavePen = pen;
78         wavePen.setCapStyle(Qt::SquareCap);
79
80         // This is to protect against making the line too fat, as happens on Mac OS X
81         // due to it having a rather thick width for the regular underline.
82         const qreal maxPenWidth = .8 * radius;
83         if (wavePen.widthF() > maxPenWidth)
84             wavePen.setWidth(maxPenWidth);
85
86         QPainter imgPainter(&pixmap);
87         imgPainter.setPen(wavePen);
88         imgPainter.setRenderHint(QPainter::Antialiasing);
89         imgPainter.translate(0, radius);
90         imgPainter.drawPath(path);
91     }
92
93     QPixmapCache::insert(key, pixmap);
94
95     return pixmap;
96 }
97
98 namespace QmlDesigner {
99
100 static void drawSelectionBackground(QPainter *painter, const QStyleOption &option)
101 {
102     QWidget colorReference;
103
104     painter->save();
105     QLinearGradient gradient;
106     QColor highlightColor = colorReference.palette().highlight().color();
107     if (0.5*highlightColor.saturationF()+0.75-highlightColor.valueF() < 0)
108         highlightColor.setHsvF(highlightColor.hsvHueF(),0.1 + highlightColor.saturationF()*2.0, highlightColor.valueF());
109     gradient.setColorAt(0, highlightColor.lighter(130));
110     gradient.setColorAt(1, highlightColor.darker(130));
111     gradient.setStart(option.rect.topLeft());
112     gradient.setFinalStop(option.rect.bottomLeft());
113     painter->fillRect(option.rect, gradient);
114     painter->setPen(highlightColor.lighter());
115     painter->drawLine(option.rect.topLeft(),option.rect.topRight());
116     painter->setPen(highlightColor.darker());
117     painter->drawLine(option.rect.bottomLeft(),option.rect.bottomRight());
118     painter->restore();
119 }
120
121 // This style basically allows us to span the entire row
122 // including the arrow indicators which would otherwise not be
123 // drawn by the delegate
124 class TreeViewStyle : public QProxyStyle
125 {
126 public:
127     void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const
128     {
129         if (element == QStyle::PE_PanelItemViewRow) {
130             if (option->state & QStyle::State_Selected) {
131                 drawSelectionBackground(painter, *option);
132             } else {
133 //                // 3D shadows
134 //                painter->save();
135 //                painter->setPen(QColor(255, 255, 255, 15));
136 //                painter->drawLine(option->rect.topLeft(), option->rect.topRight());
137 //                painter->setPen(QColor(0, 0, 0, 25));
138 //                painter->drawLine(option->rect.bottomLeft(),option->rect.bottomRight());
139 //                painter->restore();
140             }
141         } else if (element == PE_IndicatorItemViewItemDrop) {
142             painter->save();
143             QRect rect = option->rect;
144             rect.setLeft(0);
145             rect.setWidth(widget->rect().width());
146             QColor highlight = option->palette.text().color();
147             highlight.setAlphaF(0.7);
148             painter->setPen(QPen(highlight.lighter(), 1));
149             if (option->rect.height() == 0) {
150                 if (option->rect.top()>0)
151                     painter->drawLine(rect.topLeft(), rect.topRight());
152             }
153             else {
154                 highlight.setAlphaF(0.2);
155                 painter->setBrush(highlight);
156                 painter->drawRect(rect.adjusted(0, 0, -1, -1));
157             }
158             painter->restore();
159         } else if (element == PE_FrameFocusRect) {
160             // don't draw
161         } else {
162             QProxyStyle::drawPrimitive(element, option, painter, widget);
163         }
164     }
165
166     int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const {
167         if (hint == SH_ItemView_ShowDecorationSelected)
168             return 0;
169         else
170             return QProxyStyle::styleHint(hint, option, widget, returnData);
171     }
172 };
173
174 NavigatorTreeView::NavigatorTreeView(QWidget *parent)
175     : QTreeView(parent)
176 {
177     TreeViewStyle *style = new TreeViewStyle;
178     setStyle(style);
179     style->setParent(this);
180 }
181
182 QSize IconCheckboxItemDelegate::sizeHint(const QStyleOptionViewItem &option,
183                                          const QModelIndex &index) const
184 {
185     Q_UNUSED(option);
186     Q_UNUSED(index);
187
188     if (!index.data(Qt::UserRole).isValid())
189         return QSize();
190
191     return QSize(15, 20);
192 }
193
194 void IconCheckboxItemDelegate::paint(QPainter *painter,
195                                      const QStyleOptionViewItem &option, const QModelIndex &index) const
196 {
197     if (!index.data(Qt::UserRole).isValid())
198         return;
199
200     painter->save();
201     if (option.state & QStyle::State_Selected)
202         drawSelectionBackground(painter, option);
203
204     if (!m_TreeModel->nodeForIndex(index).isRootNode()) {
205
206         bool isChecked= (m_TreeModel->itemFromIndex(index)->checkState() == Qt::Checked);
207
208         if (m_TreeModel->isNodeInvisible( index ))
209             painter->setOpacity(0.5);
210
211         if (isChecked)
212             painter->drawPixmap(option.rect.x()+2,option.rect.y()+2,onPix);
213         else
214             painter->drawPixmap(option.rect.x()+2,option.rect.y()+2,offPix);
215     }
216     painter->restore();
217 }
218
219 void NameItemDelegate::paint(QPainter *painter,
220                const QStyleOptionViewItem &option, const QModelIndex &index) const
221 {
222     if (option.state & QStyle::State_Selected)
223         drawSelectionBackground(painter, option);
224
225     QString displayString;
226     QPoint displayStringOffset;
227
228     painter->save();
229     QFontMetrics fm(option.font);
230     int width = 0;
231     if (index.data(Qt::UserRole).isValid()) {
232
233         int pixmapSide = 16;
234
235         if (m_TreeModel->isNodeInvisible( index ))
236             painter->setOpacity(0.5);
237
238         ModelNode node = m_TreeModel->nodeForIndex(index);
239
240         QIcon icon;
241         if (node.isValid()) {
242             // if node has no own icon, search for it in the itemlibrary
243             const ItemLibraryInfo *libraryInfo = node.model()->metaInfo().itemLibraryInfo();
244             QList <ItemLibraryEntry> infoList = libraryInfo->entriesForType(node.type(),
245                                                                             node.majorVersion(),
246                                                                             node.minorVersion());
247             foreach (const ItemLibraryEntry &entry, infoList) {
248                 if (icon.isNull()) {
249                     icon = entry.icon();
250                     break;
251                 }
252             }
253         }
254         // if the library was also empty, use the default icon
255         if (icon.isNull())
256             icon = QIcon(QLatin1String(":/ItemLibrary/images/item-default-icon.png"));
257         if (!node.metaInfo().isValid())
258             icon = QIcon(QLatin1String(":/ItemLibrary/images/item-invalid-icon.png"));
259
260         // If no icon is present, leave an empty space of 24 pixels anyway
261         QPixmap pixmap = icon.pixmap(pixmapSide, pixmapSide);
262         painter->drawPixmap(option.rect.x()+1,option.rect.y()+2,pixmap);
263
264         displayString = node.id();
265         if (displayString.isEmpty())
266             displayString = node.simplifiedTypeName();
267
268         // Check text length does not exceed available space
269         int extraSpace=12+pixmapSide;
270
271         displayString = fm.elidedText(displayString,Qt::ElideMiddle,option.rect.width()-extraSpace);
272         displayStringOffset = QPoint(5+pixmapSide,-5);
273         width = fm.width(displayString);
274     }
275     else {
276         displayString = index.data(Qt::DisplayRole).toString();
277         displayStringOffset = QPoint(0, -2);
278     }
279
280     QPoint pos = option.rect.bottomLeft() + displayStringOffset;
281     painter->drawText(pos, displayString);
282
283     ModelNode node = m_TreeModel->nodeForIndex(index);
284
285     if (!node.isValid() ||!node.metaInfo().isValid()) {
286         painter->translate(0, pos.y() + 1);
287         QPen pen;
288         pen.setColor(Qt::red);
289
290         const qreal underlineOffset = fm.underlinePos();
291         const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
292         const int descent = fm.descent();
293
294         painter->setBrushOrigin(painter->brushOrigin().x(), 0);
295         painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
296     }
297
298     painter->restore();
299 }
300
301 QWidget *NameItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
302 {
303     Q_UNUSED(option);
304     if (!index.data(Qt::UserRole).isValid())
305         return 0;
306
307     return new QLineEdit(parent);
308 }
309
310 void NameItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
311 {
312     ModelNode node = m_TreeModel->nodeForIndex(index);
313     QString value = node.id();
314
315     QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
316     lineEdit->setText(value);
317 }
318
319 void NameItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
320 {
321     Q_UNUSED(model);
322     QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
323     m_TreeModel->setId(index,lineEdit->text());
324     lineEdit->clearFocus();
325 }
326
327 void NameItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
328 {
329     Q_UNUSED(index);
330     QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
331     lineEdit->setGeometry(option.rect);
332 }
333
334 }