diff --git a/doc/src/howto/creator-ui.qdoc b/doc/src/howto/creator-ui.qdoc index f59e6d5eaee434bc3ec78b9da2ec5d8938b600b2..880de704db28d43dbc313ecb84d4e05c4d3e5c38 100644 --- a/doc/src/howto/creator-ui.qdoc +++ b/doc/src/howto/creator-ui.qdoc @@ -135,6 +135,9 @@ \li \gui {Type Hierarchy} shows the base classes of a class. + \li \gui {Include Hierarchy} shows which files are included in the current file + and which files include the current file. + \endlist You can change the view of the sidebar in the following ways: @@ -234,6 +237,12 @@ To view the base classes of a class, right-click the class and select \gui {Open Type Hierarchy} or press \key {Ctrl+Shift+T}. + \section2 Viewing Include Hierarchy + + To view which files are included in the current file and which files include + the current file, right-click in the editor and select \gui {Open Include Hierarchy} + or press \key {Ctrl+Shift+I}. + \section1 Viewing Output The task pane in \QC can display one of the following panes: diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index 3a7b73fdee13e91dc5f4753dd084563bf4cdd44e..740a70d2b98cbd6a6c45f8a0bb6163da7b491144 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -19,7 +19,11 @@ HEADERS += cppeditorplugin.h \ cppquickfixes.h \ cppquickfix.h \ cppsnippetprovider.h \ - cpptypehierarchy.h + cpptypehierarchy.h \ + cppincludehierarchy.h \ + cppincludehierarchymodel.h \ + cppincludehierarchyitem.h \ + cppincludehierarchytreeview.h SOURCES += cppeditorplugin.cpp \ cppautocompleter.cpp \ @@ -37,7 +41,11 @@ SOURCES += cppeditorplugin.cpp \ cppquickfix.cpp \ cppquickfixes.cpp \ cppsnippetprovider.cpp \ - cpptypehierarchy.cpp + cpptypehierarchy.cpp \ + cppincludehierarchy.cpp \ + cppincludehierarchymodel.cpp \ + cppincludehierarchyitem.cpp \ + cppincludehierarchytreeview.cpp RESOURCES += cppeditor.qrc diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index efc4ac003f855133a578377d6cb146f81341777a..fd3da1fe8408e456229a6c9ebf6fc8a6b2e441a5 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -40,6 +40,14 @@ QtcPlugin { "cpphighlighter.h", "cpphoverhandler.cpp", "cpphoverhandler.h", + "cppincludehierarchy.cpp", + "cppincludehierarchy.h", + "cppincludehierarchyitem.cpp", + "cppincludehierarchyitem.h", + "cppincludehierarchymodel.cpp", + "cppincludehierarchymodel.h", + "cppincludehierarchytreeview.cpp", + "cppincludehierarchytreeview.h", "cppoutline.cpp", "cppoutline.h", "cppquickfixassistant.cpp", diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h index cf9d607c4e0c2a1d47cf1e0022f6917fee7ae581..ae87b13ead14b9561b73989ca7c2341457b4c5cd 100644 --- a/src/plugins/cppeditor/cppeditorconstants.h +++ b/src/plugins/cppeditor/cppeditorconstants.h @@ -48,6 +48,10 @@ const int TYPE_HIERARCHY_PRIORITY = 700; const char TYPE_HIERARCHY_ID[] = "CppEditor.TypeHierarchy"; const char OPEN_TYPE_HIERARCHY[] = "CppEditor.OpenTypeHierarchy"; +const int INCLUDE_HIERARCHY_PRIORITY = 800; +const char INCLUDE_HIERARCHY_ID[] = "CppEditor.IncludeHierarchy"; +const char OPEN_INCLUDE_HIERARCHY[] = "CppEditor.OpenIncludeHierarchy"; + const char C_SOURCE_MIMETYPE[] = "text/x-csrc"; const char C_HEADER_MIMETYPE[] = "text/x-chdr"; const char CPP_SOURCE_MIMETYPE[] = "text/x-c++src"; diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 3b939b49d03e5e45553f5ad425894f40183e8074..62640202505f326011c4a5bbfbfca2c6383b9da9 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -36,6 +36,7 @@ #include "cpphoverhandler.h" #include "cppoutline.h" #include "cpptypehierarchy.h" +#include "cppincludehierarchy.h" #include "cppsnippetprovider.h" #include "cppquickfixassistant.h" #include "cppquickfixes.h" @@ -103,6 +104,7 @@ CppEditorPlugin::CppEditorPlugin() : m_findUsagesAction(0), m_updateCodeModelAction(0), m_openTypeHierarchyAction(0), + m_openIncludeHierarchyAction(0), m_quickFixProvider(0) { m_instance = this; @@ -156,6 +158,7 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err addAutoReleasedObject(new CppHoverHandler); addAutoReleasedObject(new CppOutlineWidgetFactory); addAutoReleasedObject(new CppTypeHierarchyFactory); + addAutoReleasedObject(new CppIncludeHierarchyFactory); addAutoReleasedObject(new CppSnippetProvider); addAutoReleasedObject(new CppHighlighterFactory); @@ -244,6 +247,13 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err contextMenu->addAction(cmd); cppToolsMenu->addAction(cmd); + m_openIncludeHierarchyAction = new QAction(tr("Open Include Hierarchy"), this); + cmd = Core::ActionManager::registerAction(m_openIncludeHierarchyAction, Constants::OPEN_INCLUDE_HIERARCHY, context); + cmd->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+Shift+I") : tr("Ctrl+Shift+I"))); + connect(m_openIncludeHierarchyAction, SIGNAL(triggered()), this, SLOT(openIncludeHierarchy())); + contextMenu->addAction(cmd); + cppToolsMenu->addAction(cmd); + // Refactoring sub-menu Context globalContext(Core::Constants::C_GLOBAL); Command *sep = contextMenu->addSeparator(globalContext); @@ -351,6 +361,7 @@ void CppEditorPlugin::onTaskStarted(Core::Id type) m_findUsagesAction->setEnabled(false); m_updateCodeModelAction->setEnabled(false); m_openTypeHierarchyAction->setEnabled(false); + m_openIncludeHierarchyAction->setEnabled(false); } } @@ -361,6 +372,7 @@ void CppEditorPlugin::onAllTasksFinished(Core::Id type) m_findUsagesAction->setEnabled(true); m_updateCodeModelAction->setEnabled(true); m_openTypeHierarchyAction->setEnabled(true); + m_openIncludeHierarchyAction->setEnabled(true); } } @@ -383,4 +395,15 @@ void CppEditorPlugin::openTypeHierarchy() } } +void CppEditorPlugin::openIncludeHierarchy() +{ + CPPEditorWidget *editor + = qobject_cast<CPPEditorWidget*>(Core::EditorManager::currentEditor()->widget()); + if (editor) { + Core::NavigationWidget *navigation = Core::NavigationWidget::instance(); + navigation->activateSubWidget(Core::Id(Constants::INCLUDE_HIERARCHY_ID)); + emit includeHierarchyRequested(); + } +} + Q_EXPORT_PLUGIN(CppEditorPlugin) diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index ce2083dc1958ddfd153385c4f622c796ecc7b965..7442d6692403312974605ee540e139c56f71b898 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -74,10 +74,12 @@ public: signals: void outlineSortingChanged(bool sort); void typeHierarchyRequested(); + void includeHierarchyRequested(); public slots: void openDeclarationDefinitionInNextSplit(); void openTypeHierarchy(); + void openIncludeHierarchy(); void findUsages(); void renameSymbolUnderCursor(); void switchDeclarationDefinition(); @@ -291,6 +293,7 @@ private: QAction *m_findUsagesAction; QAction *m_updateCodeModelAction; QAction *m_openTypeHierarchyAction; + QAction *m_openIncludeHierarchyAction; CppQuickFixAssistProvider *m_quickFixProvider; diff --git a/src/plugins/cppeditor/cppincludehierarchy.cpp b/src/plugins/cppeditor/cppincludehierarchy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15a2429f8242c4eeb743fef9d201896233ba13b8 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchy.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppincludehierarchy.h" + +#include "cppeditor.h" +#include "cppeditorconstants.h" +#include "cppeditorplugin.h" +#include "cppelementevaluator.h" +#include "cppincludehierarchymodel.h" +#include "cppincludehierarchytreeview.h" + +#include <cplusplus/CppDocument.h> + +#include <utils/annotateditemdelegate.h> +#include <utils/fileutils.h> + +#include <QDir> +#include <QLabel> +#include <QLatin1String> +#include <QModelIndex> +#include <QStandardItem> +#include <QVBoxLayout> + +using namespace CppEditor; +using namespace Internal; +using namespace Utils; + +namespace CppEditor { +namespace Internal { + +class CppIncludeLabel : public QLabel +{ +public: + CppIncludeLabel(QWidget *parent) + : QLabel(parent) + {} + + void setup(const QString &fileName, const QString &filePath) + { + setText(fileName); + m_link = CPPEditorWidget::Link(filePath); + } + +private: + void mousePressEvent(QMouseEvent *) + { + if (!m_link.hasValidTarget()) + return; + + Core::EditorManager::openEditorAt(m_link.targetFileName, + m_link.targetLine, + m_link.targetColumn, + Constants::CPPEDITOR_ID); + } + + CPPEditorWidget::Link m_link; +}; + +// CppIncludeHierarchyWidget +CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() : + QWidget(0), + m_treeView(0), + m_model(0), + m_delegate(0), + m_includeHierarchyInfoLabel(0) +{ + m_inspectedFile = new CppIncludeLabel(this); + m_inspectedFile->setMargin(5); + m_model = new CppIncludeHierarchyModel(this); + m_treeView = new CppIncludeHierarchyTreeView(this); + m_delegate = new AnnotatedItemDelegate(this); + m_delegate->setDelimiter(QLatin1String(" ")); + m_delegate->setAnnotationRole(AnnotationRole); + m_treeView->setModel(m_model); + m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_treeView->setItemDelegate(m_delegate); + + connect(m_treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onItemClicked(QModelIndex))); + + m_includeHierarchyInfoLabel = new QLabel(tr("No include hierarchy available"), this); + m_includeHierarchyInfoLabel->setAlignment(Qt::AlignCenter); + m_includeHierarchyInfoLabel->setAutoFillBackground(true); + m_includeHierarchyInfoLabel->setBackgroundRole(QPalette::Base); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(m_inspectedFile); + layout->addWidget(m_treeView); + layout->addWidget(m_includeHierarchyInfoLabel); + setLayout(layout); + + connect(CppEditorPlugin::instance(), SIGNAL(includeHierarchyRequested()), SLOT(perform())); +} + +CppIncludeHierarchyWidget::~CppIncludeHierarchyWidget() +{ +} + +void CppIncludeHierarchyWidget::perform() +{ + showNoIncludeHierarchyLabel(); + + CPPEditor *editor = qobject_cast<CPPEditor *>(Core::EditorManager::currentEditor()); + if (!editor) + return; + CPPEditorWidget *widget = qobject_cast<CPPEditorWidget *>(editor->widget()); + if (!widget) + return; + + m_model->clear(); + m_model->buildHierarchy(widget->editorDocument()->filePath()); + if (m_model->isEmpty()) + return; + + m_inspectedFile->setup(widget->editorDocument()->displayName(), + widget->editorDocument()->filePath()); + + //expand "Includes" + m_treeView->expand(m_model->index(0, 0)); + //expand "Included by" + m_treeView->expand(m_model->index(1, 0)); + + showIncludeHierarchy(); +} + +void CppIncludeHierarchyWidget::onItemClicked(const QModelIndex &index) +{ + const TextEditor::BaseTextEditorWidget::Link link + = index.data(LinkRole).value<TextEditor::BaseTextEditorWidget::Link>(); + if (link.hasValidTarget()) + Core::EditorManager::openEditorAt(link.targetFileName, + link.targetLine, + link.targetColumn, + Constants::CPPEDITOR_ID); +} + +void CppIncludeHierarchyWidget::showNoIncludeHierarchyLabel() +{ + m_inspectedFile->hide(); + m_treeView->hide(); + m_includeHierarchyInfoLabel->show(); +} + +void CppIncludeHierarchyWidget::showIncludeHierarchy() +{ + m_inspectedFile->show(); + m_treeView->show(); + m_includeHierarchyInfoLabel->hide(); +} + +// CppIncludeHierarchyStackedWidget +CppIncludeHierarchyStackedWidget::CppIncludeHierarchyStackedWidget(QWidget *parent) : + QStackedWidget(parent), + m_typeHiearchyWidgetInstance(new CppIncludeHierarchyWidget) +{ + addWidget(m_typeHiearchyWidgetInstance); +} + +CppIncludeHierarchyStackedWidget::~CppIncludeHierarchyStackedWidget() +{ + delete m_typeHiearchyWidgetInstance; +} + +// CppIncludeHierarchyFactory +CppIncludeHierarchyFactory::CppIncludeHierarchyFactory() +{ +} + +CppIncludeHierarchyFactory::~CppIncludeHierarchyFactory() +{ +} + +QString CppIncludeHierarchyFactory::displayName() const +{ + return tr("Include Hierarchy"); +} + +int CppIncludeHierarchyFactory::priority() const +{ + return Constants::INCLUDE_HIERARCHY_PRIORITY; +} + +Core::Id CppIncludeHierarchyFactory::id() const +{ + return Core::Id(Constants::INCLUDE_HIERARCHY_ID); +} + +QKeySequence CppIncludeHierarchyFactory::activationSequence() const +{ + return QKeySequence(); +} + +Core::NavigationView CppIncludeHierarchyFactory::createWidget() +{ + CppIncludeHierarchyStackedWidget *w = new CppIncludeHierarchyStackedWidget; + static_cast<CppIncludeHierarchyWidget *>(w->currentWidget())->perform(); + Core::NavigationView navigationView; + navigationView.widget = w; + return navigationView; +} + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchy.h b/src/plugins/cppeditor/cppincludehierarchy.h new file mode 100644 index 0000000000000000000000000000000000000000..fd8d31cbde12e50bf6d6ff859f740c61099d494d --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchy.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPINCLUDEHIERARCHY_H +#define CPPINCLUDEHIERARCHY_H + +#include <coreplugin/inavigationwidgetfactory.h> + +#include <QString> +#include <QStackedWidget> +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QStandardItemModel; +class QStandardItem; +class QModelIndex; +class QLabel; +QT_END_NAMESPACE + +namespace Core { +class IEditor; +} + +namespace Utils { +class AnnotatedItemDelegate; +class FileName; +} + +namespace CppEditor { +namespace Internal { + +class CPPEditorWidget; +class CppInclude; +class CppIncludeLabel; +class CppIncludeHierarchyModel; +class CppIncludeHierarchyTreeView; + +class CppIncludeHierarchyWidget : public QWidget +{ + Q_OBJECT +public: + CppIncludeHierarchyWidget(); + virtual ~CppIncludeHierarchyWidget(); + +public slots: + void perform(); + +private slots: + void onItemClicked(const QModelIndex &index); + +private: + void showNoIncludeHierarchyLabel(); + void showIncludeHierarchy(); + + CPPEditorWidget *m_cppEditor; + CppIncludeHierarchyTreeView *m_treeView; + CppIncludeHierarchyModel *m_model; + Utils::AnnotatedItemDelegate *m_delegate; + CppIncludeLabel *m_inspectedFile; + QLabel *m_includeHierarchyInfoLabel; +}; + +// @todo: Pretty much the same design as the OutlineWidgetStack. Maybe we can generalize the +// outline factory so that it works for different widgets that support the same editor. +class CppIncludeHierarchyStackedWidget : public QStackedWidget +{ + Q_OBJECT +public: + CppIncludeHierarchyStackedWidget(QWidget *parent = 0); + virtual ~CppIncludeHierarchyStackedWidget(); + +private: + CppIncludeHierarchyWidget *m_typeHiearchyWidgetInstance; +}; + +class CppIncludeHierarchyFactory : public Core::INavigationWidgetFactory +{ + Q_OBJECT +public: + CppIncludeHierarchyFactory(); + virtual ~CppIncludeHierarchyFactory(); + + QString displayName() const; + int priority() const; + Core::Id id() const; + QKeySequence activationSequence() const; + Core::NavigationView createWidget(); +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPINCLUDEHIERARCHY_H diff --git a/src/plugins/cppeditor/cppincludehierarchyitem.cpp b/src/plugins/cppeditor/cppincludehierarchyitem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dee900260e5a098cd3872bda9814f14d3339f8ba --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchyitem.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppincludehierarchyitem.h" + +namespace CppEditor { +namespace Internal { + +CppIncludeHierarchyItem::CppIncludeHierarchyItem(const QString &filePath, + CppIncludeHierarchyItem *parent, + bool isCyclic) + : m_fileName(filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1)) + , m_filePath(filePath) + , m_parentItem(parent) + , m_isCyclic(isCyclic) + , m_hasChildren(false) + , m_line(0) +{ +} + +CppIncludeHierarchyItem::~CppIncludeHierarchyItem() +{ + removeChildren(); +} + +const QString &CppIncludeHierarchyItem::fileName() const +{ + return m_fileName; +} + +const QString &CppIncludeHierarchyItem::filePath() const +{ + return m_filePath; +} + +CppIncludeHierarchyItem *CppIncludeHierarchyItem::parent() const +{ + return m_parentItem; +} + +bool CppIncludeHierarchyItem::isCyclic() const +{ + return m_isCyclic; +} + +void CppIncludeHierarchyItem::appendChild(CppIncludeHierarchyItem *childItem) +{ + m_childItems.append(childItem); +} + +CppIncludeHierarchyItem *CppIncludeHierarchyItem::child(int row) +{ + return m_childItems.at(row); +} + +int CppIncludeHierarchyItem::row() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast<CppIncludeHierarchyItem*>(this)); + + return 0; +} + +int CppIncludeHierarchyItem::childCount() const +{ + return m_childItems.size(); +} + +void CppIncludeHierarchyItem::removeChildren() +{ + qDeleteAll(m_childItems); + m_childItems.clear(); +} + +bool CppIncludeHierarchyItem::needChildrenPopulate() const +{ + return m_hasChildren && m_childItems.isEmpty(); +} + +bool CppIncludeHierarchyItem::hasChildren() const +{ + return m_hasChildren; +} + +void CppIncludeHierarchyItem::setHasChildren(bool hasChildren) +{ + m_hasChildren = hasChildren; +} + +int CppIncludeHierarchyItem::line() const +{ + return m_line; +} + +void CppIncludeHierarchyItem::setLine(int line) +{ + m_line = line; +} + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchyitem.h b/src/plugins/cppeditor/cppincludehierarchyitem.h new file mode 100644 index 0000000000000000000000000000000000000000..f40de829c7a01ca024b6469800fa2389bd3fd614 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchyitem.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPINCLUDEHIERARCHYITEM_H +#define CPPINCLUDEHIERARCHYITEM_H + +#include <QList> +#include <QString> + +namespace CppEditor { +namespace Internal { + +class CppIncludeHierarchyItem +{ +public: + CppIncludeHierarchyItem(const QString &filePath, CppIncludeHierarchyItem *parent = 0, + bool isCyclic = false); + virtual ~CppIncludeHierarchyItem(); + + CppIncludeHierarchyItem *parent() const; + CppIncludeHierarchyItem *child(int row); + int childCount() const; + void appendChild(CppIncludeHierarchyItem *childItem); + void removeChildren(); + bool needChildrenPopulate() const; + int row() const; + bool isCyclic() const; + + const QString &fileName() const; + const QString &filePath() const; + bool hasChildren() const; + void setHasChildren(bool hasChildren); + int line() const; + void setLine(int line); + +private: + QString m_fileName; + QString m_filePath; + QList<CppIncludeHierarchyItem *> m_childItems; + CppIncludeHierarchyItem *m_parentItem; + bool m_isCyclic; + bool m_hasChildren; + int m_line; +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPINCLUDEHIERARCHYITEM_H diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.cpp b/src/plugins/cppeditor/cppincludehierarchymodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b6909f61795596c43c5d9cf8352f3025e82be58 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchymodel.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppincludehierarchymodel.h" + +#include "cppincludehierarchyitem.h" + +#include <coreplugin/fileiconprovider.h> +#include <cplusplus/CppDocument.h> +#include <cppeditor/cppeditor.h> +#include <cpptools/cppmodelmanagerinterface.h> + +#include <QSet> + +using namespace CPlusPlus; + +namespace CppEditor { +namespace Internal { + +CppIncludeHierarchyModel::CppIncludeHierarchyModel(QObject *parent) + : QAbstractItemModel(parent) + , m_rootItem(new CppIncludeHierarchyItem(QString())) + , m_includesItem(new CppIncludeHierarchyItem(tr("Includes"), m_rootItem)) + , m_includedByItem(new CppIncludeHierarchyItem(tr("Included by"), m_rootItem)) + +{ + m_rootItem->appendChild(m_includesItem); + m_rootItem->appendChild(m_includedByItem); +} + +CppIncludeHierarchyModel::~CppIncludeHierarchyModel() +{ + delete m_rootItem; +} + +QModelIndex CppIncludeHierarchyModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + CppIncludeHierarchyItem *parentItem = parent.isValid() + ? static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()) + : m_rootItem; + + CppIncludeHierarchyItem *childItem = parentItem->child(row); + return childItem ? createIndex(row, column, childItem) : QModelIndex(); +} + +QModelIndex CppIncludeHierarchyModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + CppIncludeHierarchyItem *childItem + = static_cast<CppIncludeHierarchyItem*>(index.internalPointer()); + CppIncludeHierarchyItem *parentItem = childItem->parent(); + + if (parentItem == m_rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int CppIncludeHierarchyModel::rowCount(const QModelIndex &parent) const +{ + CppIncludeHierarchyItem *parentItem; + + if (!parent.isValid()) + parentItem = m_rootItem; + else + parentItem = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); + + return parentItem->childCount(); +} + +int CppIncludeHierarchyModel::columnCount(const QModelIndex &) const +{ + return 1; +} + +QVariant CppIncludeHierarchyModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + CppIncludeHierarchyItem *item = static_cast<CppIncludeHierarchyItem*>(index.internalPointer()); + + if (!item) + return QVariant(); + + if (role == Qt::DisplayRole) { + if ((item == m_includesItem && m_includesItem->childCount() == 0) + || (item == m_includedByItem && m_includedByItem->childCount() == 0)) { + return QString(item->fileName() + tr(" (none)")); + } + + if (item->isCyclic()) + return QString(item->fileName() + tr(" (cyclic)")); + + return item->fileName(); + } + + if (item == m_rootItem || item == m_includesItem || item == m_includedByItem) + return QVariant(); + + switch (role) { + case Qt::ToolTipRole: + return item->filePath(); + case Qt::DecorationRole: + return Core::FileIconProvider::icon(QFileInfo(item->filePath())); + case LinkRole: { + QVariant itemLink; + CPPEditorWidget::Link link(item->filePath(), item->line()); + itemLink.setValue(link); + return itemLink; + } + } + + return QVariant(); +} + +void CppIncludeHierarchyModel::fetchMore(const QModelIndex &parent) +{ + if (!parent.isValid()) + return; + + CppIncludeHierarchyItem *parentItem + = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); + Q_ASSERT(parentItem); + + if (parentItem == m_rootItem || parentItem == m_includesItem || parentItem == m_includedByItem) + return; + + if (parentItem->needChildrenPopulate()) { + QSet<QString> cyclic; + CppIncludeHierarchyItem *item = parentItem->parent(); + while (!(item == m_includesItem || item == m_includedByItem)) { + cyclic << item->filePath(); + item = item->parent(); + } + + if (item == m_includesItem) + buildHierarchyIncludes_helper(parentItem->filePath(), parentItem, &cyclic); + else + buildHierarchyIncludedBy_helper(parentItem->filePath(), parentItem, &cyclic); + } + +} + +bool CppIncludeHierarchyModel::canFetchMore(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return false; + + CppIncludeHierarchyItem *parentItem + = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); + Q_ASSERT(parentItem); + + if (parentItem == m_includesItem || parentItem == m_includedByItem) + return false; + + if (parentItem->needChildrenPopulate()) + return true; + + return false; +} + +void CppIncludeHierarchyModel::clear() +{ + beginResetModel(); + m_includesItem->removeChildren(); + m_includedByItem->removeChildren(); + endResetModel(); +} + +bool CppIncludeHierarchyModel::hasChildren(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return true; + CppIncludeHierarchyItem *parentItem + = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); + + Q_ASSERT(parentItem); + return parentItem->hasChildren(); +} + +void CppIncludeHierarchyModel::buildHierarchy(const QString &filePath) +{ + beginResetModel(); + buildHierarchyIncludes(filePath); + buildHierarchyIncludedBy(filePath); + endResetModel(); +} + +bool CppIncludeHierarchyModel::isEmpty() const +{ + return !m_includesItem->hasChildren() && !m_includedByItem->hasChildren(); +} + +void CppIncludeHierarchyModel::buildHierarchyIncludes(const QString ¤tFilePath) +{ + QSet<QString> cyclic; + buildHierarchyIncludes_helper(currentFilePath, m_includesItem, &cyclic); +} + +void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &filePath, + CppIncludeHierarchyItem *parent, + QSet<QString> *cyclic, bool recursive) +{ + const Snapshot &snapshot = CppTools::CppModelManagerInterface::instance()->snapshot(); + Document::Ptr doc = snapshot.document(filePath); + if (!doc) + return; + + parent->setHasChildren(doc->resolvedIncludes().size() > 0); + if (!recursive) + return; + + cyclic->insert(filePath); + + foreach (const Document::Include &includeFile, doc->resolvedIncludes()) { + const QString includedFilePath = includeFile.resolvedFileName(); + CppIncludeHierarchyItem *item = 0; + + if (cyclic->contains(includedFilePath)) { + item = new CppIncludeHierarchyItem(includedFilePath, parent, true); + parent->appendChild(item); + continue; + } + item = new CppIncludeHierarchyItem(includedFilePath, parent); + parent->appendChild(item); + buildHierarchyIncludes_helper(includedFilePath, item, cyclic, false); + + } + cyclic->remove(filePath); +} + +void CppIncludeHierarchyModel::buildHierarchyIncludedBy(const QString ¤tFilePath) +{ + QSet<QString> cyclic; + buildHierarchyIncludedBy_helper(currentFilePath, m_includedByItem, &cyclic); +} + +void CppIncludeHierarchyModel::buildHierarchyIncludedBy_helper(const QString &filePath, + CppIncludeHierarchyItem *parent, + QSet<QString> *cyclic, + bool recursive) +{ + cyclic->insert(filePath); + const Snapshot &snapshot = CppTools::CppModelManagerInterface::instance()->snapshot(); + Snapshot::const_iterator citEnd = snapshot.end(); + for (Snapshot::const_iterator cit = snapshot.begin(); cit != citEnd; ++cit) { + const QString filePathFromSnapshot = cit.key(); + Document::Ptr doc = cit.value(); + foreach (const Document::Include &includeFile, doc->resolvedIncludes()) { + const QString includedFilePath = includeFile.resolvedFileName(); + + if (includedFilePath == filePath) { + parent->setHasChildren(true); + if (!recursive) { + cyclic->remove(filePath); + return; + } + + const bool isCyclic = cyclic->contains(filePathFromSnapshot); + CppIncludeHierarchyItem *item = new CppIncludeHierarchyItem(filePathFromSnapshot, + parent, + isCyclic); + item->setLine(includeFile.line()); + parent->appendChild(item); + buildHierarchyIncludedBy_helper(filePathFromSnapshot, item, cyclic, false); + } + } + } + cyclic->remove(filePath); +} + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.h b/src/plugins/cppeditor/cppincludehierarchymodel.h new file mode 100644 index 0000000000000000000000000000000000000000..90d26856346a8c8398bfc0b06de3d80b70e6ef06 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchymodel.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPINCLUDEHIERARCHYMODEL_H +#define CPPINCLUDEHIERARCHYMODEL_H + +#include <QAbstractItemModel> + +namespace { + +enum ItemRole { + AnnotationRole = Qt::UserRole + 1, + LinkRole +}; + +} // Anonymous + +namespace CppEditor { +namespace Internal { + +class CppIncludeHierarchyItem; + +class CppIncludeHierarchyModel : public QAbstractItemModel +{ +public: + explicit CppIncludeHierarchyModel(QObject *parent); + ~CppIncludeHierarchyModel(); + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + void fetchMore(const QModelIndex &parent); + bool canFetchMore(const QModelIndex &parent) const; + bool hasChildren(const QModelIndex &parent) const; + + void clear(); + void buildHierarchy(const QString &filePath); + bool isEmpty() const; + +private: + void buildHierarchyIncludes(const QString ¤tFilePath); + void buildHierarchyIncludes_helper(const QString &filePath, CppIncludeHierarchyItem *parent, + QSet<QString> *cyclic, bool recursive = true); + void buildHierarchyIncludedBy(const QString ¤tFilePath); + void buildHierarchyIncludedBy_helper(const QString &filePath, CppIncludeHierarchyItem *parent, + QSet<QString> *cyclic, bool recursive = true); + + CppIncludeHierarchyItem *m_rootItem; + CppIncludeHierarchyItem *m_includesItem; + CppIncludeHierarchyItem *m_includedByItem; +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPINCLUDEHIERARCHYMODEL_H diff --git a/src/plugins/cppeditor/cppincludehierarchytreeview.cpp b/src/plugins/cppeditor/cppincludehierarchytreeview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43a46279e2afd50708e09a75afb76dcff4309096 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchytreeview.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppincludehierarchytreeview.h" + +#include <QKeyEvent> + +namespace CppEditor { +namespace Internal { + +CppIncludeHierarchyTreeView::CppIncludeHierarchyTreeView(QWidget *parent/* = 0*/) + : NavigationTreeView(parent) +{ +} + +void CppIncludeHierarchyTreeView::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Asterisk: + QAbstractItemView::keyPressEvent(event); + return; + } + + NavigationTreeView::keyPressEvent(event); +} + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchytreeview.h b/src/plugins/cppeditor/cppincludehierarchytreeview.h new file mode 100644 index 0000000000000000000000000000000000000000..eaa624bdae6b6c8942203223d70ebe00849a1815 --- /dev/null +++ b/src/plugins/cppeditor/cppincludehierarchytreeview.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPINCLUDEHIERARCHYTREEVIEW_H +#define CPPINCLUDEHIERARCHYTREEVIEW_H + +#include <utils/navigationtreeview.h> + +namespace CppEditor { +namespace Internal { + +class CppIncludeHierarchyTreeView : public Utils::NavigationTreeView +{ +public: + CppIncludeHierarchyTreeView(QWidget *parent = 0); +protected: + void keyPressEvent(QKeyEvent *event); +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPINCLUDEHIERARCHYTREEVIEW_H