Commit 087e7249 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Designer: Prepare re-implementation of "Goto Slot".

...making use of the new code model features. Move code to
separate file. Make it possible to obtain path to generated
header file from project manager.
parent de4fedbe
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 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 "codemodelhelpers.h"
#include <cpptools/cppmodelmanagerinterface.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/CoreTypes.h>
#include <cplusplus/Name.h>
#include <cplusplus/Names.h>
#include <cplusplus/Literals.h>
#include <cplusplus/Scope.h>
#include <cplusplus/Control.h>
#include <SymbolVisitor.h>
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
// Debug helpers for code model. @todo: Move to some CppTools library?
typedef QMap<QString, QStringList> DependencyMap;
typedef CPlusPlus::Document::Ptr DocumentPtr;
typedef QList<CPlusPlus::Symbol *> SymbolList;
typedef QList<DocumentPtr> DocumentPtrList;
static const char setupUiC[] = "setupUi";
// Find the generated "ui_form.h" header of the form via project.
static QString generatedHeaderOf(const QString &uiFileName)
{
const ProjectExplorer::SessionManager *sessionMgr = ProjectExplorer::ProjectExplorerPlugin::instance()->session();
if (const ProjectExplorer::Project *uiProject = sessionMgr->projectForFile(uiFileName))
return uiProject->generatedUiHeader(uiFileName);
return QString();
}
namespace {
// Find function symbols in a document by name.
class SearchFunction : public CPlusPlus::SymbolVisitor {
public:
typedef QList<CPlusPlus::Function *> FunctionList;
explicit SearchFunction(const char *name);
FunctionList operator()(const DocumentPtr &doc);
virtual bool visit(CPlusPlus::Function * f);
private:
const size_t m_length;
const char *m_name;
FunctionList m_matches;
};
SearchFunction::SearchFunction(const char *name) :
m_length(qstrlen(name)),
m_name(name)
{
}
SearchFunction::FunctionList SearchFunction::operator()(const DocumentPtr &doc)
{
m_matches.clear();
const unsigned globalSymbolCount = doc->globalSymbolCount();
for (unsigned i = 0; i < globalSymbolCount; i++)
accept(doc->globalSymbolAt(i));
return m_matches;
}
bool SearchFunction::visit(CPlusPlus::Function * f)
{
if (const CPlusPlus::Name *name = f->name())
if (const CPlusPlus::Identifier *id = name->identifier())
if (id->size() == m_length)
if (!qstrncmp(m_name, id->chars(), m_length))
m_matches.push_back(f);
return true;
}
} // anonymous namespace
namespace Designer {
namespace Internal {
// Goto slot invoked by the designer context menu. Either navigates
// to an existing slot function or create a new one.
bool navigateToSlot(const QString &uiFileName,
const QString & /* objectName */,
const QString & /* signalSignature */,
const QStringList & /* parameterNames */,
QString *errorMessage)
{
// Find the generated header.
const QString generatedHeaderFile = generatedHeaderOf(uiFileName);
if (generatedHeaderFile.isEmpty()) {
*errorMessage = QCoreApplication::translate("Designer", "The generated header of the form '%1' could be found.\nRebuilding the project might help.").arg(uiFileName);
return false;
}
const CPlusPlus::Snapshot snapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
const DocumentPtr generatedHeaderDoc = snapshot.value(generatedHeaderFile);
if (!generatedHeaderDoc) {
*errorMessage = QCoreApplication::translate("Designer", "The generated header '%1' could not be found in the code model.\nRebuilding the project might help.").arg(generatedHeaderFile);
return false;
}
// Look for setupUi
SearchFunction searchFunc(setupUiC);
const SearchFunction::FunctionList funcs = searchFunc(generatedHeaderDoc);
if (funcs.size() != 1) {
*errorMessage = QString::fromLatin1("Internal error: The function '%1' could not be found in in %2").arg(QLatin1String(setupUiC), generatedHeaderFile);
return false;
}
return true;
}
} // namespace Internal
} // namespace Designer
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 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 CODEMODELHELPERS_H
#define CODEMODELHELPERS_H
#include <QtCore/QtGlobal>
QT_BEGIN_NAMESPACE
class QString;
class QStringList;
QT_END_NAMESPACE
namespace Designer {
namespace Internal {
// Goto slot invoked by the designer context menu. Either navigates
// to an existing slot function or create a new one.
bool navigateToSlot(const QString &uiFileName,
const QString &objectName,
const QString &signalSignature,
const QStringList &parameterNames,
QString *errorMessage);
} // namespace Internal
} // namespace Designer
#endif // CODEMODELHELPERS_H
......@@ -35,6 +35,7 @@ HEADERS += formeditorplugin.h \
settingsmanager.h \
formtemplatewizardpage.h \
formwizarddialog.h \
codemodelhelpers.h \
designer_export.h
SOURCES += formeditorplugin.cpp \
......@@ -49,7 +50,8 @@ SOURCES += formeditorplugin.cpp \
formeditorw.cpp \
settingsmanager.cpp \
formtemplatewizardpage.cpp \
formwizarddialog.cpp
formwizarddialog.cpp \
codemodelhelpers.cpp
RESOURCES += designer.qrc
......
......@@ -31,6 +31,7 @@
#include "qtcreatorintegration.h"
#include "formeditorw.h"
#include "formwindoweditor.h"
#include "codemodelhelpers.h"
#include <cpptools/cppmodelmanagerinterface.h>
#include <cplusplus/Symbols.h>
......@@ -570,7 +571,9 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
QString *errorMessage)
{
const QString currentUiFile = m_few->activeFormWindow()->file()->fileName();
#if 0
return Designer::Internal::navigateToSlot(currentUiFile, objectName, signalSignature, parameterNames, errorMessage);
#endif
// TODO: we should pass to findDocumentsIncluding an absolute path to generated .h file from ui.
// Currently we are guessing the name of ui_<>.h file and pass the file name only to the findDocumentsIncluding().
// The idea is that the .pro file knows if the .ui files is inside, and the .pro file knows it will
......
......@@ -467,3 +467,9 @@ QStringList Project::frameworkPaths(const QString &) const
{
return QStringList();
}
QString Project::generatedUiHeader(const QString & /* formFile */) const
{
return QString();
}
......@@ -113,6 +113,8 @@ public:
enum FilesMode { AllFiles, ExcludeGeneratedFiles };
virtual QStringList files(FilesMode fileMode) const = 0;
// TODO: generalize to find source(s) of generated files?
virtual QString generatedUiHeader(const QString &formFile) const;
// C++ specific
// TODO do a C++ project as a base ?
......
......@@ -1252,6 +1252,23 @@ void Qt4ProFileNode::updateCodeModelSupportFromEditor(const QString &uiFileName,
qt4proFileNode->updateCodeModelSupportFromEditor(uiFileName, fw);
}
QString Qt4ProFileNode::uiDirectory() const
{
const Qt4VariablesHash::const_iterator it = m_varValues.constFind(UiDirVar);
if (it != m_varValues.constEnd() && !it.value().isEmpty())
return it.value().front();
return buildDir();
}
QString Qt4ProFileNode::uiHeaderFile(const QString &uiDir, const QString &formFile)
{
QString uiHeaderFilePath = uiDir;
uiHeaderFilePath += QLatin1String("/ui_");
uiHeaderFilePath += QFileInfo(formFile).completeBaseName();
uiHeaderFilePath += QLatin1String(".h");
return QDir::cleanPath(uiHeaderFilePath);
}
void Qt4ProFileNode::createUiCodeModelSupport()
{
// qDebug()<<"creatUiCodeModelSupport()";
......@@ -1271,17 +1288,10 @@ void Qt4ProFileNode::createUiCodeModelSupport()
const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
// Find the UiDir, there can only ever be one
QString uiDir = buildDir();
QStringList tmp = m_varValues[UiDirVar];
if (tmp.size() != 0)
uiDir = tmp.first();
foreach (FileNode *uiFile, uiFiles) {
QString uiHeaderFilePath
= QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName());
uiHeaderFilePath = QDir::cleanPath(uiHeaderFilePath);
// qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
const QString uiDir = uiDirectory();
foreach (const FileNode *uiFile, uiFiles) {
const QString uiHeaderFilePath = uiHeaderFile(uiDir, uiFile->path());
// qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path());
if (it != oldCodeModelSupport.end()) {
// qDebug()<<"updated old codemodelsupport";
......
......@@ -196,6 +196,10 @@ public:
void updateCodeModelSupportFromBuild(const QStringList &files);
void updateCodeModelSupportFromEditor(const QString &uiFileName, Designer::FormWindowEditor *fw);
QString uiDirectory() const;
static QString uiHeaderFile(const QString &uiDir, const QString &formFile);
public slots:
void scheduleUpdate();
void update();
......@@ -203,6 +207,8 @@ private slots:
void buildStateChanged(ProjectExplorer::Project*);
private:
typedef QHash<Qt4Variable, QStringList> Qt4VariablesHash;
void createUiCodeModelSupport();
QStringList updateUiFiles();
Qt4ProFileNode *createSubProFileNode(const QString &path);
......@@ -215,7 +221,7 @@ private:
void invalidate();
Qt4ProjectType m_projectType;
QHash<Qt4Variable, QStringList> m_varValues;
Qt4VariablesHash m_varValues;
QTimer m_updateTimer;
QMap<QString, QDateTime> m_uitimestamps;
......
......@@ -787,6 +787,38 @@ QStringList Qt4Project::files(FilesMode fileMode) const
return files;
}
// Find the folder that contains a file a certain type (recurse down)
static FolderNode *folderOf(FolderNode *in, FileType fileType, const QString &fileName)
{
foreach(FileNode *fn, in->fileNodes())
if (fn->fileType() == fileType && fn->path() == fileName)
return in;
foreach(FolderNode *folder, in->subFolderNodes())
if (FolderNode *pn = folderOf(folder, fileType, fileName))
return pn;
return 0;
}
// Find the Qt4ProFileNode that contains a file of a certain type.
// First recurse down to folder, then find the pro-file.
static Qt4ProFileNode *proFileNodeOf(Qt4ProFileNode *in, FileType fileType, const QString &fileName)
{
for (FolderNode *folder = folderOf(in, fileType, fileName); folder; folder = folder->parentFolderNode())
if (Qt4ProFileNode *proFile = qobject_cast<Qt4ProFileNode *>(folder))
return proFile;
return 0;
}
QString Qt4Project::generatedUiHeader(const QString &formFile) const
{
// Look in sub-profiles as SessionManager::projectForFile returns
// the top-level project only.
if (m_rootProjectNode)
if (const Qt4ProFileNode *pro = proFileNodeOf(m_rootProjectNode, FormType, formFile))
return Qt4ProFileNode::uiHeaderFile(pro->uiDirectory(), formFile);
return QString();
}
QList<ProjectExplorer::Project*> Qt4Project::dependsOn()
{
// NBS implement dependsOn
......@@ -820,8 +852,6 @@ void Qt4Project::updateActiveRunConfiguration()
emit targetInformationChanged();
}
BuildConfigWidget *Qt4Project::createConfigWidget()
{
return new Qt4ProjectConfigWidget(this);
......
......@@ -179,6 +179,7 @@ public:
Internal::Qt4ProFileNode *rootProjectNode() const;
virtual QStringList files(FilesMode fileMode) const;
virtual QString generatedUiHeader(const QString &formFile) const;
// returns the CONFIG variable from the .pro file
QStringList qmakeConfig() const;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment