From 2d50925071cd71942d78f52486eae69a02da3234 Mon Sep 17 00:00:00 2001 From: Leandro Melo <leandro.melo@nokia.com> Date: Wed, 6 Oct 2010 15:23:05 +0200 Subject: [PATCH] Create a reusable item delegate wich supports "annotations". Currently used by the QML outline and C++ type hierarchy. Reviewed-by: kkoehne Task-number: QTCREATORBUG-2583 --- src/libs/utils/annotateditemdelegate.cpp | 115 ++++++++++++++++++ src/libs/utils/annotateditemdelegate.h | 66 ++++++++++ src/libs/utils/utils-lib.pri | 6 +- src/plugins/cppeditor/cpptypehierarchy.cpp | 102 ++-------------- src/plugins/cppeditor/cpptypehierarchy.h | 38 ++---- .../qmljseditor/qmljsoutlinetreeview.cpp | 66 +--------- .../qmljseditor/qmljsoutlinetreeview.h | 11 -- src/plugins/texteditor/basetexteditor.h | 2 + 8 files changed, 212 insertions(+), 194 deletions(-) create mode 100644 src/libs/utils/annotateditemdelegate.cpp create mode 100644 src/libs/utils/annotateditemdelegate.h diff --git a/src/libs/utils/annotateditemdelegate.cpp b/src/libs/utils/annotateditemdelegate.cpp new file mode 100644 index 00000000000..dfb1e9db8e6 --- /dev/null +++ b/src/libs/utils/annotateditemdelegate.cpp @@ -0,0 +1,115 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "annotateditemdelegate.h" + +#include <QtCore/QSize> +#include <QtCore/QModelIndex> +#include <QtGui/QStandardItemModel> +#include <QtGui/QPainter> +#include <QtGui/QStyle> +#include <QtGui/QStyleOptionViewItemV4> +#include <QtGui/QApplication> + +using namespace Utils; + +AnnotatedItemDelegate::AnnotatedItemDelegate(QObject *parent) : QStyledItemDelegate(parent) +{} + +AnnotatedItemDelegate::~AnnotatedItemDelegate() +{} + +void AnnotatedItemDelegate::setAnnotationRole(int role) +{ + m_annotationRole = role; +} + +int AnnotatedItemDelegate::annotationRole() const +{ + return m_annotationRole; +} + +void AnnotatedItemDelegate::setDelimiter(const QString &delimiter) +{ + m_delimiter = delimiter; +} + +const QString &AnnotatedItemDelegate::delimiter() const +{ + return m_delimiter; +} + +void AnnotatedItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + QStyle *style = QApplication::style(); + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + + const QString &annotation = index.data(m_annotationRole).toString(); + if (!annotation.isEmpty()) { + QPalette disabled(opt.palette); + disabled.setCurrentColorGroup(QPalette::Disabled); + + painter->save(); + painter->setPen(disabled.color(QPalette::WindowText)); + + static int extra = opt.fontMetrics.width(m_delimiter) + 10; + const QPixmap &pixmap = opt.icon.pixmap(opt.decorationSize); + const QRect &iconRect = style->itemPixmapRect(opt.rect, opt.decorationAlignment, pixmap); + const QRect &displayRect = style->itemTextRect(opt.fontMetrics, opt.rect, + opt.displayAlignment, true, index.data(Qt::DisplayRole).toString()); + QRect annotationRect = style->itemTextRect(opt.fontMetrics, opt.rect, + opt.displayAlignment, true, annotation); + annotationRect.adjust(iconRect.width() + displayRect.width() + extra, 0, + iconRect.width() + displayRect.width() + extra, 0); + + QApplication::style()->drawItemText(painter, annotationRect, + Qt::AlignLeft | Qt::AlignBottom, disabled, true, annotation); + + painter->restore(); + } +} + +QSize AnnotatedItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + const QString &annotation = index.data(m_annotationRole).toString(); + if (!annotation.isEmpty()) + opt.text += m_delimiter + annotation; + + return QApplication::style()->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), 0); +} diff --git a/src/libs/utils/annotateditemdelegate.h b/src/libs/utils/annotateditemdelegate.h new file mode 100644 index 00000000000..77c403f295d --- /dev/null +++ b/src/libs/utils/annotateditemdelegate.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANNOTATEDITEMDELEGATE_H +#define ANNOTATEDITEMDELEGATE_H + +#include "utils_global.h" + +#include <QtCore/QString> +#include <QtCore/QSize> +#include <QtGui/QStyledItemDelegate> + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT AnnotatedItemDelegate : public QStyledItemDelegate +{ +public: + AnnotatedItemDelegate(QObject *parent = 0); + virtual ~AnnotatedItemDelegate(); + + void setAnnotationRole(int role); + int annotationRole() const; + + void setDelimiter(const QString &delimiter); + const QString &delimiter() const; + +protected: + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + int m_annotationRole; + QString m_delimiter; +}; + +} // Utils + +#endif // ANNOTATEDITEMDELEGATE_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 3cafe99c5af..aa2e65cf11d 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -50,7 +50,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/crumblepath.cpp \ $$PWD/debuggerlanguagechooser.cpp \ $$PWD/historycompleter.cpp \ - $$PWD/buildablehelperlibrary.cpp + $$PWD/buildablehelperlibrary.cpp \ + $$PWD/annotateditemdelegate.cpp win32 { SOURCES += $$PWD/abstractprocess_win.cpp \ @@ -111,7 +112,8 @@ HEADERS += $$PWD/environment.h \ $$PWD/crumblepath.h \ $$PWD/debuggerlanguagechooser.h \ $$PWD/historycompleter.h \ - $$PWD/buildablehelperlibrary.h + $$PWD/buildablehelperlibrary.h \ + $$PWD/annotateditemdelegate.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp index a837911ecf7..e7ee9913646 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.cpp +++ b/src/plugins/cppeditor/cpptypehierarchy.cpp @@ -35,97 +35,19 @@ #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/coreconstants.h> #include <utils/navigationtreeview.h> +#include <utils/annotateditemdelegate.h> #include <QtCore/QLatin1Char> #include <QtCore/QLatin1String> #include <QtCore/QModelIndex> -#include <QtCore/QSettings> #include <QtGui/QVBoxLayout> #include <QtGui/QStandardItemModel> -#include <QtGui/QFontMetrics> -#include <QtGui/QApplication> -#include <QtGui/QPainter> #include <QtGui/QLabel> using namespace CppEditor; using namespace Internal; - -// CppTypeHierarchyItem -CppTypeHierarchyItem::CppTypeHierarchyItem(const CppClass &cppClass) : - QStandardItem(), m_cppClass(cppClass) -{} - -CppTypeHierarchyItem::~CppTypeHierarchyItem() -{} - -int CppTypeHierarchyItem::type() const -{ return UserType; } - -const CppClass &CppTypeHierarchyItem::cppClass() const -{ return m_cppClass; } - -// CppTypeHierarchyDelegate -CppTypeHierarchyDelegate::CppTypeHierarchyDelegate(QObject *parent) : QStyledItemDelegate(parent) -{} - -CppTypeHierarchyDelegate::~CppTypeHierarchyDelegate() -{} - -void CppTypeHierarchyDelegate::paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - if (const QStyleOptionViewItemV3 *v3 = - qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option)) { - QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, v3, painter, v3->widget); - - QStyleOptionViewItemV4 opt = option; - initStyleOption(&opt, index); - - const QStandardItemModel *model = static_cast<const QStandardItemModel *>(index.model()); - CppTypeHierarchyItem *item = - static_cast<CppTypeHierarchyItem *>(model->itemFromIndex(index)); - - painter->save(); - const QIcon &icon = item->cppClass().icon(); - const QSize &iconSize = icon.actualSize(opt.decorationSize); - QRect workingRect(opt.rect); - QRect decorationRect(workingRect.topLeft(), iconSize); - icon.paint(painter, decorationRect, opt.decorationAlignment); - workingRect.setX(workingRect.x() + iconSize.width() + 4); - - QRect boundingRect; - const QString &name = item->cppClass().name() + QLatin1Char(' '); - painter->drawText(workingRect, Qt::AlignLeft, name, &boundingRect); - if (item->cppClass().name() != item->cppClass().qualifiedName()) { - QFont font(painter->font()); - if (font.pointSize() > 2) - font.setPointSize(font.pointSize() - 2); - else if (font.pointSize() > 1) - font.setPointSize(font.pointSize() - 1); - font.setItalic(true); - painter->setFont(font); - - QFontMetrics metrics(font); - workingRect.setX(boundingRect.x() + boundingRect.width()); - workingRect.setY(boundingRect.y() + boundingRect.height() - metrics.height()); - painter->drawText(workingRect, Qt::AlignLeft, item->cppClass().qualifiedName()); - } - painter->restore(); - } else { - QStyledItemDelegate::paint(painter, option, index); - } -} - -QSize CppTypeHierarchyDelegate::sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QSize size = QStyledItemDelegate::sizeHint(option, index); - size.rwidth() += 5; // Extend a bit because of the font processing. - return size; -} +using namespace Utils; // CppTypeHierarchyWidget CppTypeHierarchyWidget::CppTypeHierarchyWidget(Core::IEditor *editor) : @@ -144,7 +66,9 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget(Core::IEditor *editor) : m_model = new QStandardItemModel; m_treeView = new Utils::NavigationTreeView; - m_delegate = new CppTypeHierarchyDelegate; + m_delegate = new AnnotatedItemDelegate; + m_delegate->setDelimiter(QLatin1String(" ")); + m_delegate->setAnnotationRole(AnnotationRole); m_treeView->setModel(m_model); m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_treeView->setItemDelegate(m_delegate); @@ -200,13 +124,16 @@ void CppTypeHierarchyWidget::perform() void CppTypeHierarchyWidget::buildModel(const CppClass &cppClass, QStandardItem *parent) { - CppTypeHierarchyItem *item = new CppTypeHierarchyItem(cppClass); + QStandardItem *item = new QStandardItem; parent->appendRow(item); - // The delegate retrieves data from the item directly. This is to help size hint. - const QString &display = cppClass.name() + cppClass.qualifiedName(); - m_model->setData(m_model->indexFromItem(item), display, Qt::DisplayRole); + m_model->setData(m_model->indexFromItem(item), cppClass.name(), Qt::DisplayRole); + if (cppClass.name() != cppClass.qualifiedName()) + m_model->setData(m_model->indexFromItem(item), cppClass.qualifiedName(), AnnotationRole); m_model->setData(m_model->indexFromItem(item), cppClass.icon(), Qt::DecorationRole); + QVariant link; + link.setValue(CPPEditor::Link(cppClass.link())); + m_model->setData(m_model->indexFromItem(item), link, LinkRole); foreach (const CppClass &cppBase, cppClass.bases()) buildModel(cppBase, item); @@ -216,10 +143,7 @@ void CppTypeHierarchyWidget::buildModel(const CppClass &cppClass, QStandardItem void CppTypeHierarchyWidget::onItemClicked(const QModelIndex &index) { - if (QStandardItem *item = m_model->itemFromIndex(index)) { - CppTypeHierarchyItem *cppItem = static_cast<CppTypeHierarchyItem *>(item); - m_cppEditor->openLink(cppItem->cppClass().link()); - } + m_cppEditor->openLink(index.data(LinkRole).value<CPPEditor::Link>()); } // CppTypeHierarchyStackedWidget diff --git a/src/plugins/cppeditor/cpptypehierarchy.h b/src/plugins/cppeditor/cpptypehierarchy.h index db617471514..663feae84d6 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.h +++ b/src/plugins/cppeditor/cpptypehierarchy.h @@ -37,13 +37,11 @@ #include <QtCore/QString> #include <QtGui/QWidget> #include <QtGui/QStackedWidget> -#include <QtGui/QStandardItem> -#include <QtGui/QStyledItemDelegate> QT_BEGIN_NAMESPACE class QStandardItemModel; +class QStandardItem; class QModelIndex; -class QPainter; QT_END_NAMESPACE namespace Core { @@ -52,6 +50,7 @@ class IEditor; namespace Utils { class NavigationTreeView; +class AnnotatedItemDelegate; } namespace CppEditor { @@ -59,32 +58,6 @@ namespace Internal { class CPPEditor; -class CppTypeHierarchyItem : public QStandardItem -{ -public: - CppTypeHierarchyItem(const CppClass &cppClass); - virtual ~CppTypeHierarchyItem(); - - virtual int type() const; - - const CppClass &cppClass() const; - -private: - CppClass m_cppClass; -}; - -class CppTypeHierarchyDelegate : public QStyledItemDelegate -{ -public: - CppTypeHierarchyDelegate(QObject *parent = 0); - virtual ~CppTypeHierarchyDelegate(); - - virtual void paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const; - virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; -}; - class CppTypeHierarchyWidget : public QWidget { Q_OBJECT @@ -101,12 +74,17 @@ private slots: void onItemClicked(const QModelIndex &index); private: + enum ItemRole { + AnnotationRole = Qt::UserRole + 1, + LinkRole + }; + void buildModel(const CppClass &cppClass, QStandardItem *item); CPPEditor *m_cppEditor; Utils::NavigationTreeView *m_treeView; QStandardItemModel *m_model; - CppTypeHierarchyDelegate *m_delegate; + Utils::AnnotatedItemDelegate *m_delegate; }; // @todo: Pretty much the same design as the OutlineWidgetStack. Maybe we can generalize the diff --git a/src/plugins/qmljseditor/qmljsoutlinetreeview.cpp b/src/plugins/qmljseditor/qmljsoutlinetreeview.cpp index 1e47392f70d..e0828ab840e 100644 --- a/src/plugins/qmljseditor/qmljsoutlinetreeview.cpp +++ b/src/plugins/qmljseditor/qmljsoutlinetreeview.cpp @@ -1,71 +1,11 @@ #include "qmljsoutlinetreeview.h" #include "qmloutlinemodel.h" -#include <QtCore/QDebug> -#include <QtGui/QApplication> -#include <QtGui/QPainter> +#include <utils/annotateditemdelegate.h> namespace QmlJSEditor { namespace Internal { -QmlJSOutlineItemDelegate::QmlJSOutlineItemDelegate(QObject *parent) : - QStyledItemDelegate(parent) -{ -} - -QSize QmlJSOutlineItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - QStyleOptionViewItemV4 opt = option; - initStyleOption(&opt, index); - - const QString annotation = index.data(QmlOutlineModel::AnnotationRole).toString(); - if (!annotation.isEmpty()) - opt.text += " " + annotation; - - QStyle *style = QApplication::style(); - return style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), 0); -} - -void QmlJSOutlineItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QStyleOptionViewItemV4 opt = option; - initStyleOption(&opt, index); - - if (opt.state & QStyle::State_Selected) - painter->fillRect(opt.rect, option.palette.highlight()); - - const QString typeString = index.data(Qt::DisplayRole).toString(); - const QString annotationString = index.data(QmlOutlineModel::AnnotationRole).toString(); - - QStyle *style = QApplication::style(); - - style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0); - - if (!annotationString.isEmpty()) { - QPalette::ColorRole textColorRole = QPalette::Text; - if (option.state & QStyle::State_Selected) { - textColorRole = QPalette::HighlightedText; - } - - // calculate sizes of icon, type. - QPixmap iconPixmap = opt.icon.pixmap(opt.rect.size()); - QRect iconRect = style->itemPixmapRect(opt.rect, Qt::AlignLeft, iconPixmap); - QRect typeRect = style->itemTextRect(opt.fontMetrics, opt.rect, Qt::AlignLeft, true, typeString); - QRect annotationRect = style->itemTextRect(opt.fontMetrics, opt.rect, Qt::AlignLeft | Qt::AlignBottom, true, - annotationString); - - static int space = opt.fontMetrics.width(" "); - annotationRect.adjust(iconRect.width() + typeRect.width() + space, 0, - iconRect.width() + typeRect.width() + space, 0); - - QPalette disabledPalette(opt.palette); - disabledPalette.setCurrentColorGroup(QPalette::Disabled); - style->drawItemText(painter, annotationRect, Qt::AlignLeft, disabledPalette, true, - annotationString, textColorRole); - } -} - QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) : Utils::NavigationTreeView(parent) { @@ -80,7 +20,9 @@ QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) : setRootIsDecorated(false); - QmlJSOutlineItemDelegate *itemDelegate = new QmlJSOutlineItemDelegate(this); + Utils::AnnotatedItemDelegate *itemDelegate = new Utils::AnnotatedItemDelegate(this); + itemDelegate->setDelimiter(QLatin1String(" ")); + itemDelegate->setAnnotationRole(QmlOutlineModel::AnnotationRole); setItemDelegateForColumn(0, itemDelegate); } diff --git a/src/plugins/qmljseditor/qmljsoutlinetreeview.h b/src/plugins/qmljseditor/qmljsoutlinetreeview.h index 23fb29ca375..a16afad081c 100644 --- a/src/plugins/qmljseditor/qmljsoutlinetreeview.h +++ b/src/plugins/qmljseditor/qmljsoutlinetreeview.h @@ -2,21 +2,10 @@ #define QMLJSOUTLINETREEVIEW_H #include <utils/navigationtreeview.h> -#include <QtGui/QStyledItemDelegate> namespace QmlJSEditor { namespace Internal { -class QmlJSOutlineItemDelegate : public QStyledItemDelegate -{ -public: - explicit QmlJSOutlineItemDelegate(QObject *parent = 0); - - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const; -}; - class QmlJSOutlineTreeView : public Utils::NavigationTreeView { Q_OBJECT diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index aa19330753a..c544e23b6b1 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -648,4 +648,6 @@ private: } // namespace TextEditor +Q_DECLARE_METATYPE(TextEditor::BaseTextEditor::Link); + #endif // BASETEXTEDITOR_H -- GitLab