1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "navigatortreeview.h"
37 #include "navigatorview.h"
38 #include "navigatortreemodel.h"
39 #include "navigatorwidget.h"
40 #include "qproxystyle.h"
42 #include <nodeproperty.h>
46 #include <QPixmapCache>
49 static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
51 const qreal radiusBase = qMax(qreal(1), maxRadius);
53 QString key = QLatin1String("WaveUnderline-Bauhaus");
56 if (QPixmapCache::find(key, pixmap))
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);
71 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
74 pixmap = QPixmap(width, radius * 2);
75 pixmap.fill(Qt::transparent);
78 wavePen.setCapStyle(Qt::SquareCap);
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);
86 QPainter imgPainter(&pixmap);
87 imgPainter.setPen(wavePen);
88 imgPainter.setRenderHint(QPainter::Antialiasing);
89 imgPainter.translate(0, radius);
90 imgPainter.drawPath(path);
93 QPixmapCache::insert(key, pixmap);
98 namespace QmlDesigner {
100 static void drawSelectionBackground(QPainter *painter, const QStyleOption &option)
102 QWidget colorReference;
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());
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
127 void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const
129 if (element == QStyle::PE_PanelItemViewRow) {
130 if (option->state & QStyle::State_Selected) {
131 drawSelectionBackground(painter, *option);
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();
141 } else if (element == PE_IndicatorItemViewItemDrop) {
143 QRect rect = option->rect;
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());
154 highlight.setAlphaF(0.2);
155 painter->setBrush(highlight);
156 painter->drawRect(rect.adjusted(0, 0, -1, -1));
159 } else if (element == PE_FrameFocusRect) {
162 QProxyStyle::drawPrimitive(element, option, painter, widget);
166 int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const {
167 if (hint == SH_ItemView_ShowDecorationSelected)
170 return QProxyStyle::styleHint(hint, option, widget, returnData);
174 NavigatorTreeView::NavigatorTreeView(QWidget *parent)
177 TreeViewStyle *style = new TreeViewStyle;
179 style->setParent(this);
182 QSize IconCheckboxItemDelegate::sizeHint(const QStyleOptionViewItem &option,
183 const QModelIndex &index) const
188 if (!index.data(Qt::UserRole).isValid())
191 return QSize(15, 20);
194 void IconCheckboxItemDelegate::paint(QPainter *painter,
195 const QStyleOptionViewItem &option, const QModelIndex &index) const
197 if (!index.data(Qt::UserRole).isValid())
201 if (option.state & QStyle::State_Selected)
202 drawSelectionBackground(painter, option);
204 if (!m_TreeModel->nodeForIndex(index).isRootNode()) {
206 bool isChecked= (m_TreeModel->itemFromIndex(index)->checkState() == Qt::Checked);
208 if (m_TreeModel->isNodeInvisible( index ))
209 painter->setOpacity(0.5);
212 painter->drawPixmap(option.rect.x()+2,option.rect.y()+2,onPix);
214 painter->drawPixmap(option.rect.x()+2,option.rect.y()+2,offPix);
219 void NameItemDelegate::paint(QPainter *painter,
220 const QStyleOptionViewItem &option, const QModelIndex &index) const
222 if (option.state & QStyle::State_Selected)
223 drawSelectionBackground(painter, option);
225 QString displayString;
226 QPoint displayStringOffset;
229 QFontMetrics fm(option.font);
231 if (index.data(Qt::UserRole).isValid()) {
235 if (m_TreeModel->isNodeInvisible( index ))
236 painter->setOpacity(0.5);
238 ModelNode node = m_TreeModel->nodeForIndex(index);
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(),
246 node.minorVersion());
247 foreach (const ItemLibraryEntry &entry, infoList) {
254 // if the library was also empty, use the default icon
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"));
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);
264 displayString = node.id();
265 if (displayString.isEmpty())
266 displayString = node.simplifiedTypeName();
268 // Check text length does not exceed available space
269 int extraSpace=12+pixmapSide;
271 displayString = fm.elidedText(displayString,Qt::ElideMiddle,option.rect.width()-extraSpace);
272 displayStringOffset = QPoint(5+pixmapSide,-5);
273 width = fm.width(displayString);
276 displayString = index.data(Qt::DisplayRole).toString();
277 displayStringOffset = QPoint(0, -2);
280 QPoint pos = option.rect.bottomLeft() + displayStringOffset;
281 painter->drawText(pos, displayString);
283 ModelNode node = m_TreeModel->nodeForIndex(index);
285 if (!node.isValid() ||!node.metaInfo().isValid()) {
286 painter->translate(0, pos.y() + 1);
288 pen.setColor(Qt::red);
290 const qreal underlineOffset = fm.underlinePos();
291 const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
292 const int descent = fm.descent();
294 painter->setBrushOrigin(painter->brushOrigin().x(), 0);
295 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
301 QWidget *NameItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
304 if (!index.data(Qt::UserRole).isValid())
307 return new QLineEdit(parent);
310 void NameItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
312 ModelNode node = m_TreeModel->nodeForIndex(index);
313 QString value = node.id();
315 QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
316 lineEdit->setText(value);
319 void NameItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
322 QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
323 m_TreeModel->setId(index,lineEdit->text());
324 lineEdit->clearFocus();
327 void NameItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
330 QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
331 lineEdit->setGeometry(option.rect);