Commit ae8192ad authored by Denis Mingulov's avatar Denis Mingulov Committed by Kai Koehne
Browse files

ClassView: Initial implementation



Merge-request: 2167
Reviewed-by: default avatarKai Koehne <kai.koehne@nokia.com>
parent 915ba478
<plugin name="ClassView" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Denis Mingulov</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin 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 plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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.
</license>
<category>Qt Creator</category>
<description>Class View component.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
<dependency name="Core" version="2.1.80"/>
<dependency name="CppTools" version="2.1.80"/>
<dependency name="ProjectExplorer" version="2.1.80"/>
<dependency name="TextEditor" version="2.1.80"/>
</dependencyList>
</plugin>
TEMPLATE = lib
TARGET = ClassView
include(classview_dependencies.pri)
HEADERS += \
classviewplugin.h \
classviewnavigationwidgetfactory.h \
classviewconstants.h \
classviewnavigationwidget.h \
classviewparser.h \
classviewmanager.h \
classviewsymbollocation.h \
classviewsymbolinformation.h \
classviewparsertreeitem.h \
classviewutils.h \
classviewtreeitemmodel.h
SOURCES += \
classviewplugin.cpp \
classviewnavigationwidgetfactory.cpp \
classviewnavigationwidget.cpp \
classviewparser.cpp \
classviewmanager.cpp \
classviewsymbollocation.cpp \
classviewsymbolinformation.cpp \
classviewparsertreeitem.cpp \
classviewutils.cpp \
classviewtreeitemmodel.cpp
OTHER_FILES += \
ClassView.pluginspec
FORMS += \
classviewnavigationwidget.ui
RESOURCES += \
classview.qrc
<RCC>
<qresource prefix="/classview">
<file>images/hierarchicalmode.png</file>
</qresource>
</RCC>
include(../../qtcreatorplugin.pri)
include(../../libs/utils/utils.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/cpptools/cpptools.pri)
include(../../plugins/projectexplorer/projectexplorer.pri)
include(../../libs/cplusplus/cplusplus.pri)
include(../../plugins/texteditor/texteditor.pri)
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Denis Mingulov.
**
** 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 CLASSVIEWCONSTANTS_H
#define CLASSVIEWCONSTANTS_H
namespace ClassView {
namespace Constants {
//! Navi Widget Factory id
const char * const CLASSVIEWNAVIGATION_ID = "Class View";
//! Settings' group
const char * const CLASSVIEW_SETTINGS_GROUP = "ClassView";
//! Settings' prefix for the tree widget
const char * const CLASSVIEW_SETTINGS_TREEWIDGET_PREFIX = "TreeWidget.";
//! Flat mode settings
const char * const CLASSVIEW_SETTINGS_FLATMODE = "FlatMode";
//! Delay in msecs before an update
const int CLASSVIEW_EDITINGTREEUPDATE_DELAY = 400;
//! QStandardItem roles
enum ItemRole {
SymbolLocationsRole = Qt::UserRole + 1, //!< Symbol locations
IconTypeRole, //!< Icon type (integer)
SymbolNameRole, //!< Symbol name
SymbolTypeRole //!< Symbol type
};
} // namespace Constants
} // namespace ClassView
#endif // CLASSVIEWCONSTANTS_H
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Denis Mingulov.
**
** 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 "classviewsymbollocation.h"
#include "classviewmanager.h"
#include "classviewnavigationwidgetfactory.h"
#include "classviewparser.h"
#include "classviewutils.h"
#include <utils/qtcassert.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <texteditor/basetexteditor.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <cpptools/cpptoolsconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <texteditor/itexteditor.h>
#include <QtCore/QThread>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
namespace ClassView {
namespace Internal {
///////////////////////////////// ManagerPrivate //////////////////////////////////
/*!
\struct ManagerPrivate
\brief Private class data for \a Manager
\sa Manager
*/
struct ManagerPrivate
{
ManagerPrivate() : state(false) {}
//! instance
static Manager *instance;
//! Pointer to widget factory
QPointer<NavigationWidgetFactory> widgetFactory;
//! State mutex
QMutex mutexState;
//! Internal manager state. \sa Manager::state
bool state;
//! code state/changes parser
Parser parser;
//! separate thread for the parser
QThread parserThread;
//! cpp code model manager
QPointer<CppTools::CppModelManagerInterface> codeModelManager;
//! there is some massive operation ongoing so temporary we should wait
bool disableCodeParser;
};
// static variable initialization
Manager *ManagerPrivate::instance = 0;
///////////////////////////////// Manager //////////////////////////////////
Manager::Manager(QObject *parent)
: QObject(parent),
d_ptr(new ManagerPrivate())
{
d_ptr->widgetFactory = NavigationWidgetFactory::instance();
// register - to be able send between signal/slots
qRegisterMetaType<QSharedPointer<QStandardItem> >("QSharedPointer<QStandardItem>");
initialize();
// start a separate thread for the parser
d_ptr->parser.moveToThread(&d_ptr->parserThread);
d_ptr->parserThread.start();
// initial setup
onProjectListChanged();
}
Manager::~Manager()
{
d_ptr->parserThread.quit();
d_ptr->parserThread.wait();
}
Manager *Manager::instance(QObject *parent)
{
if (!ManagerPrivate::instance)
ManagerPrivate::instance = new Manager(parent);
return ManagerPrivate::instance;
}
bool Manager::canFetchMore(QStandardItem *item) const
{
return d_ptr->parser.canFetchMore(item);
}
void Manager::fetchMore(QStandardItem *item, bool skipRoot)
{
d_ptr->parser.fetchMore(item, skipRoot);
}
void Manager::initialize()
{
// use Qt::QueuedConnection everywhere
// widget factory signals
connect(d_ptr->widgetFactory, SIGNAL(widgetIsCreated()),
SLOT(onWidgetIsCreated()), Qt::QueuedConnection);
// internal manager state is changed
connect(this, SIGNAL(stateChanged(bool)), SLOT(onStateChanged(bool)), Qt::QueuedConnection);
// connections to enable/disbale navi widget factory
ProjectExplorer::SessionManager *sessionManager =
ProjectExplorer::ProjectExplorerPlugin::instance()->session();
connect(sessionManager, SIGNAL(projectAdded(ProjectExplorer::Project*)),
SLOT(onProjectListChanged()), Qt::QueuedConnection);
connect(sessionManager, SIGNAL(projectRemoved(ProjectExplorer::Project*)),
SLOT(onProjectListChanged()), Qt::QueuedConnection);
Core::ICore *core = Core::ICore::instance();
// connect to the progress manager for signals about Parsing tasks
connect(core->progressManager(), SIGNAL(taskStarted(QString)),
SLOT(onTaskStarted(QString)), Qt::QueuedConnection);
connect(core->progressManager(), SIGNAL(allTasksFinished(QString)),
SLOT(onAllTasksFinished(QString)), Qt::QueuedConnection);
// connect to the cpp model manager for signals about document updates
d_ptr->codeModelManager = CppTools::CppModelManagerInterface::instance();
// when code manager signals that document is updated - handle it by ourselves
connect(d_ptr->codeModelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)), Qt::QueuedConnection);
// when we signals that really document is updated - sent it to the parser
connect(this, SIGNAL(requestDocumentUpdated(CPlusPlus::Document::Ptr)),
&d_ptr->parser, SLOT(parseDocument(CPlusPlus::Document::Ptr)), Qt::QueuedConnection);
//
connect(d_ptr->codeModelManager, SIGNAL(aboutToRemoveFiles(QStringList)),
&d_ptr->parser, SLOT(removeFiles(QStringList)), Qt::QueuedConnection);
// translate data update from the parser to listeners
connect(&d_ptr->parser, SIGNAL(treeDataUpdate(QSharedPointer<QStandardItem>)),
this, SLOT(onTreeDataUpdate(QSharedPointer<QStandardItem>)), Qt::QueuedConnection);
// requet current state - immediately after a notification
connect(this, SIGNAL(requestTreeDataUpdate()),
&d_ptr->parser, SLOT(requestCurrentState()), Qt::QueuedConnection);
// full reset request to parser
connect(this, SIGNAL(requestResetCurrentState()),
&d_ptr->parser, SLOT(resetDataToCurrentState()), Qt::QueuedConnection);
// clear cache request
connect(this, SIGNAL(requestClearCache()),
&d_ptr->parser, SLOT(clearCache()), Qt::QueuedConnection);
// clear full cache request
connect(this, SIGNAL(requestClearCacheAll()),
&d_ptr->parser, SLOT(clearCacheAll()), Qt::QueuedConnection);
// flat mode request
connect(this, SIGNAL(requestSetFlatMode(bool)),
&d_ptr->parser, SLOT(setFlatMode(bool)), Qt::QueuedConnection);
}
bool Manager::state() const
{
return d_ptr->state;
}
void Manager::setState(bool state)
{
QMutexLocker locker(&d_ptr->mutexState);
// boolean comparsion - should be done correctly by any compiler
if (state == d_ptr->state)
return;
d_ptr->state = state;
emit stateChanged(d_ptr->state);
}
void Manager::onWidgetIsCreated()
{
// do nothing - continue to sleep
}
void Manager::onWidgetVisibilityIsChanged(bool visibility)
{
// activate data handling - when 1st time 'Class View' will be open
if (visibility)
setState(true);
}
void Manager::onStateChanged(bool state)
{
if (state) {
// enabled - request a current snapshots etc?..
emit requestResetCurrentState();
} else {
// disabled - clean parsers internal cache
emit requestClearCacheAll();
}
}
void Manager::onProjectListChanged()
{
// do nothing if Manager is disabled
if (!state())
return;
// update to the latest state
requestTreeDataUpdate();
}
void Manager::onTaskStarted(const QString &type)
{
if (type != CppTools::Constants::TASK_INDEX)
return;
// disable tree updates to speed up
d_ptr->disableCodeParser = true;
}
void Manager::onAllTasksFinished(const QString &type)
{
if (type != CppTools::Constants::TASK_INDEX)
return;
// parsing is finished, enable tree updates
d_ptr->disableCodeParser = false;
// do nothing if Manager is disabled
if (!state())
return;
// any document might be changed, emit signal to clear cache
emit requestClearCache();
// request to update a tree to the current state
emit requestResetCurrentState();
}
void Manager::onDocumentUpdated(CPlusPlus::Document::Ptr doc)
{
// do nothing if Manager is disabled
if (!state())
return;
// do nothing if updates are disabled
if (d_ptr->disableCodeParser)
return;
emit requestDocumentUpdated(doc);
}
void Manager::gotoLocation(const QString &fileName, int line, int column)
{
bool newEditor = false;
TextEditor::BaseTextEditor::openEditorAt(fileName, line, column, QString(), &newEditor);
}
void Manager::gotoLocations(const QList<QVariant> &list)
{
QSet<SymbolLocation> locations = Utils::roleToLocations(list);
if (locations.count() == 0)
return;
QString fileName;
int line = 0;
int column = 0;
bool currentPositionAvailable = false;
// what is open now?
Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
if (editor) {
// get current file name
Core::IFile *file = editor->file();
if (file)
fileName = file->fileName();
// if text file - what is current position?
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
if (textEditor) {
// there is open currently text editor
int position = textEditor->position();
textEditor->convertPosition(position, &line, &column);
currentPositionAvailable = true;
}
}
// if there is something open - try to check, is it currently activated symbol?
if (currentPositionAvailable) {
SymbolLocation current(fileName, line, column);
QSet<SymbolLocation>::const_iterator it = locations.find(current);
QSet<SymbolLocation>::const_iterator end = locations.constEnd();
// is it known location?
if (it != end) {
// found - do one additional step
++it;
if (it == end)
it = locations.begin();
const SymbolLocation &found = *it;
gotoLocation(found.fileName(), found.line(), found.column());
return;
}
}
// no success - open first item in the list
const SymbolLocation loc = *locations.constBegin();
gotoLocation(loc.fileName(), loc.line(), loc.column());
}
void Manager::onRequestTreeDataUpdate()
{
// do nothing if Manager is disabled
if (!state())
return;
emit requestTreeDataUpdate();
}
void Manager::setFlatMode(bool flat)
{
emit requestSetFlatMode(flat);
}
void Manager::onTreeDataUpdate(QSharedPointer<QStandardItem> result)
{
// do nothing if Manager is disabled
if (!state())
return;
emit treeDataUpdate(result);
}
} // namespace Internal
} // namespace ClassView
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Denis Mingulov.
**
** 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 CLASSVIEWMANAGER_H
#define CLASSVIEWMANAGER_H
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
#include <QtCore/QSharedPointer>
#include <QtGui/QStandardItem>
#include <cplusplus/CppDocument.h>
namespace ClassView {
namespace Internal {
class NavigationWidgetFactory;
/*!
\class Manager
\brief Class View manager
Class View Manager. Interacts with other Qt Creator plugins - this is a proxy between them and
parser.
\a Parser is moved to a separate thread and is connected to \a Manager by signal/slots.
Manager's signals starting with 'request' are for Parser.
*/
class Manager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Manager)
public:
/*!
\brief
\param widgetFactory NavigationWidgetFactory
\param parent Parent object
*/
virtual ~Manager();
//! Get an instance of Manager
static Manager *instance(QObject *parent = 0);
/*!
\brief Lazy data population for a \a QStandardItemModel
\param item Item with has to be checked
*/
bool canFetchMore(QStandardItem *item) const;
/*!
\brief Lazy data population for a \a QStandardItemModel
\param item Item with has to be checked
\param skipRoot Skip root item (is needed for the manual update, call not from model)
*/
void fetchMore(QStandardItem *item, bool skipRoot = false);
signals:
/*!