forked from qt-creator/qt-creator
Fixes: Make Goto Slot work.
Task: 205821 Details: Do not look only in the source file, but also in the first order includes for the class definition. Polish and simplify the thing a bit, do not check for Ui_foo.
This commit is contained in:
@@ -59,6 +59,7 @@
|
|||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
enum { debugSlotNavigation = 0 };
|
enum { debugSlotNavigation = 0 };
|
||||||
|
enum { indentation = 4 };
|
||||||
|
|
||||||
using namespace Designer::Internal;
|
using namespace Designer::Internal;
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
@@ -75,6 +76,12 @@ static QString msgClassNotFound(const QString &uiClassName, const QList<Document
|
|||||||
return WorkbenchIntegration::tr("The class definition of '%1' could not be found in %2.").arg(uiClassName, files);
|
return WorkbenchIntegration::tr("The class definition of '%1' could not be found in %2.").arg(uiClassName, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline CppTools::CppModelManagerInterface *cppModelManagerInstance()
|
||||||
|
{
|
||||||
|
Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
|
||||||
|
return core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
|
||||||
|
}
|
||||||
|
|
||||||
WorkbenchIntegration::WorkbenchIntegration(QDesignerFormEditorInterface *core, FormEditorW *parent) :
|
WorkbenchIntegration::WorkbenchIntegration(QDesignerFormEditorInterface *core, FormEditorW *parent) :
|
||||||
qdesigner_internal::QDesignerIntegration(core, ::qobject_cast<QObject*>(parent)),
|
qdesigner_internal::QDesignerIntegration(core, ::qobject_cast<QObject*>(parent)),
|
||||||
m_few(parent)
|
m_few(parent)
|
||||||
@@ -101,18 +108,13 @@ QWidget *WorkbenchIntegration::containerWindow(QWidget * /*widget*/) const
|
|||||||
return fw->integrationContainer();
|
return fw->integrationContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<Document::Ptr> findDocumentsIncluding(const QString &fileName, bool checkFileNameOnly)
|
static QList<Document::Ptr> findDocumentsIncluding(const CPlusPlus::Snapshot &docTable,
|
||||||
|
const QString &fileName, bool checkFileNameOnly)
|
||||||
{
|
{
|
||||||
Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
|
|
||||||
CppTools::CppModelManagerInterface *cppModelManager =
|
|
||||||
core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
|
|
||||||
|
|
||||||
QList<Document::Ptr> docList;
|
QList<Document::Ptr> docList;
|
||||||
// take all docs
|
foreach (const Document::Ptr &doc, docTable) { // we go through all documents
|
||||||
CPlusPlus::Snapshot docTable = cppModelManager->snapshot();
|
const QStringList includes = doc->includedFiles();
|
||||||
foreach (Document::Ptr doc, docTable) { // we go through all documents
|
foreach (const QString &include, includes) {
|
||||||
QStringList includes = doc->includedFiles();
|
|
||||||
foreach (QString include, includes) {
|
|
||||||
if (checkFileNameOnly) {
|
if (checkFileNameOnly) {
|
||||||
const QFileInfo fi(include);
|
const QFileInfo fi(include);
|
||||||
if (fi.fileName() == fileName) { // we are only interested in docs which includes fileName only
|
if (fi.fileName() == fileName) { // we are only interested in docs which includes fileName only
|
||||||
@@ -127,78 +129,79 @@ static QList<Document::Ptr> findDocumentsIncluding(const QString &fileName, bool
|
|||||||
return docList;
|
return docList;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Class *findClass(Namespace *parentNameSpace, const QString &uiClassName, QString *namespaceName)
|
// Check for a class name where haystack is a member class of an object.
|
||||||
|
// So, haystack can be shorter (can have some namespaces omitted because of a
|
||||||
|
// "using namespace" declaration, for example, comparing
|
||||||
|
// "foo::Ui::form", against "using namespace foo; Ui::form".
|
||||||
|
|
||||||
|
static bool matchMemberClassName(const QString &needle, const QString &hayStack)
|
||||||
{
|
{
|
||||||
// construct proper ui class name, take into account namespaced ui class name
|
if (needle == hayStack)
|
||||||
QString className1;
|
return true;
|
||||||
QString className2;
|
if (!needle.endsWith(hayStack))
|
||||||
int indexOfScope = uiClassName.lastIndexOf(QLatin1String("::"));
|
return false;
|
||||||
if (indexOfScope < 0) {
|
// Check if there really is a separator "::"
|
||||||
className1 = QLatin1String("Ui::") + uiClassName;
|
const int separatorPos = needle.size() - hayStack.size() - 1;
|
||||||
className2 = QLatin1String("Ui_") + uiClassName;
|
return separatorPos > 1 && needle.at(separatorPos) == QLatin1Char(':');
|
||||||
} else {
|
}
|
||||||
className1 = uiClassName.left(indexOfScope + 2) + QLatin1String("Ui::") + uiClassName.mid(indexOfScope + 2);
|
|
||||||
className2 = uiClassName.left(indexOfScope + 2) + QLatin1String("Ui_") + uiClassName.mid(indexOfScope + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < parentNameSpace->memberCount(); i++) { // we go through all namespace members
|
// Find class definition in namespace
|
||||||
if (Class *cl = parentNameSpace->memberAt(i)->asClass()) { // we have found a class - we are interested in classes only
|
static const Class *findClass(const Namespace *parentNameSpace, const QString &className, QString *namespaceName)
|
||||||
Overview o;
|
{
|
||||||
QString className = o.prettyName(cl->name());
|
if (debugSlotNavigation)
|
||||||
for (unsigned j = 0; j < cl->memberCount(); j++) { // we go through class members
|
qDebug() << Q_FUNC_INFO << className;
|
||||||
const Declaration *decl = cl->memberAt(j)->asDeclaration();
|
|
||||||
if (decl) { // we want to know if the class contains a member (so we look into a declaration) of uiClassName type
|
|
||||||
NamedType *nt = decl->type()->asNamedType();
|
|
||||||
|
|
||||||
|
const Overview o;
|
||||||
|
const unsigned namespaceMemberCount = parentNameSpace->memberCount();
|
||||||
|
for (unsigned i = 0; i < namespaceMemberCount; i++) { // we go through all namespace members
|
||||||
|
const Symbol *sym = parentNameSpace->memberAt(i);
|
||||||
|
// we have found a class - we are interested in classes only
|
||||||
|
if (const Class *cl = sym->asClass()) {
|
||||||
|
const unsigned classMemberCount = cl->memberCount();
|
||||||
|
for (unsigned j = 0; j < classMemberCount; j++) // we go through class members
|
||||||
|
if (const Declaration *decl = cl->memberAt(j)->asDeclaration()) {
|
||||||
|
// we want to know if the class contains a member (so we look into
|
||||||
|
// a declaration) of uiClassName type
|
||||||
|
const NamedType *nt = decl->type()->asNamedType();
|
||||||
// handle pointers to member variables
|
// handle pointers to member variables
|
||||||
if (PointerType *pt = decl->type()->asPointerType())
|
if (PointerType *pt = decl->type()->asPointerType())
|
||||||
nt = pt->elementType()->asNamedType();
|
nt = pt->elementType()->asNamedType();
|
||||||
|
|
||||||
if (nt) {
|
if (nt && matchMemberClassName(className, o.prettyName(nt->name())))
|
||||||
Overview typeOverview;
|
|
||||||
const QString memberClass = typeOverview.prettyName(nt->name());
|
|
||||||
if (memberClass == className1 || memberClass == className2) // names match
|
|
||||||
return cl;
|
return cl;
|
||||||
// memberClass can be shorter (can have some namespaces cut because of e.g. "using namespace" declaration)
|
} // decl
|
||||||
if (memberClass == className1.right(memberClass.length())) { // memberClass lenght <= className length
|
} else {
|
||||||
const QString namespacePrefix = className1.left(className1.length() - memberClass.length());
|
// Check namespaces
|
||||||
if (namespacePrefix.right(2) == QLatin1String("::"))
|
if (const Namespace *ns = sym->asNamespace()) {
|
||||||
return cl;
|
QString tempNS = *namespaceName;
|
||||||
}
|
tempNS += o.prettyName(ns->name());
|
||||||
// the same as above but for className2
|
tempNS += QLatin1String("::");
|
||||||
if (memberClass == className2.right(memberClass.length())) { // memberClass lenght <= className length
|
if (const Class *cl = findClass(ns, className, &tempNS)) {
|
||||||
const QString namespacePrefix = className2.left(className1.length() - memberClass.length());
|
|
||||||
if (namespacePrefix.right(2) == QLatin1String("::"))
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Namespace *ns = parentNameSpace->memberAt(i)->asNamespace()) {
|
|
||||||
Overview o;
|
|
||||||
QString tempNS = *namespaceName + o.prettyName(ns->name()) + QLatin1String("::");
|
|
||||||
Class *cl = findClass(ns, uiClassName, &tempNS);
|
|
||||||
if (cl) {
|
|
||||||
*namespaceName = tempNS;
|
*namespaceName = tempNS;
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
}
|
} // member is namespave
|
||||||
}
|
} // member is no class
|
||||||
|
} // for members
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Function *findDeclaration(Class *cl, const QString &functionName)
|
static const Function *findDeclaration(const Class *cl, const QString &functionName)
|
||||||
{
|
{
|
||||||
const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
|
const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
|
||||||
for (unsigned j = 0; j < cl->memberCount(); j++) { // go through all members
|
const unsigned mCount = cl->memberCount();
|
||||||
const Declaration *decl = cl->memberAt(j)->asDeclaration();
|
// we are interested only in declarations (can be decl of method or of a field)
|
||||||
if (decl) { // we are interested only in declarations (can be decl of method or of a field)
|
// we are only interested in declarations of methods
|
||||||
Function *fun = decl->type()->asFunction();
|
const Overview overview;
|
||||||
if (fun) { // we are only interested in declarations of methods
|
for (unsigned j = 0; j < mCount; j++) { // go through all members
|
||||||
Overview overview;
|
if (const Declaration *decl = cl->memberAt(j)->asDeclaration())
|
||||||
QString memberFunction = overview.prettyName(fun->name()) + QLatin1Char('(');
|
if (const Function *fun = decl->type()->asFunction()) {
|
||||||
for (uint i = 0; i < fun->argumentCount(); i++) { // we build argument types string
|
// Format signature
|
||||||
Argument *arg = fun->argumentAt(i)->asArgument();
|
QString memberFunction = overview.prettyName(fun->name());
|
||||||
|
memberFunction += QLatin1Char('(');
|
||||||
|
const uint aCount = fun->argumentCount();
|
||||||
|
for (uint i = 0; i < aCount; i++) { // we build argument types string
|
||||||
|
const Argument *arg = fun->argumentAt(i)->asArgument();
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
memberFunction += QLatin1Char(',');
|
memberFunction += QLatin1Char(',');
|
||||||
memberFunction += overview.prettyType(arg->type());
|
memberFunction += overview.prettyType(arg->type());
|
||||||
@@ -210,18 +213,17 @@ static Function *findDeclaration(Class *cl, const QString &functionName)
|
|||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove me, see below
|
// TODO: remove me, see below
|
||||||
static bool isCompatible(Name *name, Name *otherName)
|
static bool isCompatible(const Name *name, const Name *otherName)
|
||||||
{
|
{
|
||||||
if (NameId *nameId = name->asNameId()) {
|
if (const NameId *nameId = name->asNameId()) {
|
||||||
if (TemplateNameId *otherTemplId = otherName->asTemplateNameId())
|
if (const TemplateNameId *otherTemplId = otherName->asTemplateNameId())
|
||||||
return nameId->identifier()->isEqualTo(otherTemplId->identifier());
|
return nameId->identifier()->isEqualTo(otherTemplId->identifier());
|
||||||
} else if (TemplateNameId *templId = name->asTemplateNameId()) {
|
} else if (const TemplateNameId *templId = name->asTemplateNameId()) {
|
||||||
if (NameId *otherNameId = otherName->asNameId())
|
if (const NameId *otherNameId = otherName->asNameId())
|
||||||
return templId->identifier()->isEqualTo(otherNameId->identifier());
|
return templId->identifier()->isEqualTo(otherNameId->identifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +231,7 @@ static bool isCompatible(Name *name, Name *otherName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove me, see below
|
// TODO: remove me, see below
|
||||||
static bool isCompatible(Function *definition, Symbol *declaration, QualifiedNameId *declarationName)
|
static bool isCompatible(const Function *definition, const Symbol *declaration, const QualifiedNameId *declarationName)
|
||||||
{
|
{
|
||||||
Function *declTy = declaration->type()->asFunction();
|
Function *declTy = declaration->type()->asFunction();
|
||||||
if (! declTy)
|
if (! declTy)
|
||||||
@@ -269,11 +271,9 @@ static bool isCompatible(Function *definition, Symbol *declaration, QualifiedNam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
|
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
|
||||||
static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
|
static Document::Ptr findDefinition(const Function *functionDeclaration, int *line)
|
||||||
{
|
{
|
||||||
Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
|
CppTools::CppModelManagerInterface *cppModelManager = cppModelManagerInstance();
|
||||||
CppTools::CppModelManagerInterface *cppModelManager =
|
|
||||||
core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
|
|
||||||
if (!cppModelManager)
|
if (!cppModelManager)
|
||||||
return Document::Ptr();
|
return Document::Ptr();
|
||||||
|
|
||||||
@@ -286,7 +286,8 @@ static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
|
|||||||
if (QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
|
if (QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
|
||||||
for (unsigned i = 0; i < q->nameCount(); ++i) {
|
for (unsigned i = 0; i < q->nameCount(); ++i) {
|
||||||
qualifiedName.prepend(q->nameAt(i));
|
qualifiedName.prepend(q->nameAt(i));
|
||||||
}
|
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qualifiedName.prepend(scopeOwnerName);
|
qualifiedName.prepend(scopeOwnerName);
|
||||||
}
|
}
|
||||||
@@ -299,7 +300,6 @@ static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
|
|||||||
Control control;
|
Control control;
|
||||||
QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
|
QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
|
||||||
LookupContext context(&control);
|
LookupContext context(&control);
|
||||||
|
|
||||||
const Snapshot documents = cppModelManager->snapshot();
|
const Snapshot documents = cppModelManager->snapshot();
|
||||||
foreach (Document::Ptr doc, documents) {
|
foreach (Document::Ptr doc, documents) {
|
||||||
QList<Scope *> visibleScopes;
|
QList<Scope *> visibleScopes;
|
||||||
@@ -368,71 +368,80 @@ static int findClassEndPosition(const QString &headerContents, int classStartPos
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addDeclaration(const QString &docFileName, Class *cl, const QString &functionName)
|
static inline ITextEditable *editableAt(const QString &fileName, int line, int column)
|
||||||
{
|
{
|
||||||
// functionName comes already with argument names (if designer managed to do that)
|
return qobject_cast<ITextEditable *>(TextEditor::BaseTextEditor::openEditorAt(fileName, line, column));
|
||||||
for (unsigned j = 0; j < cl->memberCount(); j++) { // go through all members
|
}
|
||||||
const Declaration *decl = cl->memberAt(j)->asDeclaration();
|
|
||||||
if (decl) { // we want to find any method which is a private slot (then we don't need to add "private slots:" statement)
|
static void addDeclaration(const QString &docFileName, const Class *cl, const QString &functionName)
|
||||||
Function *fun = decl->type()->asFunction();
|
{
|
||||||
if (fun) { // we are only interested in declarations of methods
|
QString declaration = QLatin1String("void ");
|
||||||
|
declaration += functionName;
|
||||||
|
declaration += QLatin1String(";\n");
|
||||||
|
|
||||||
|
// functionName comes already with argument names (if designer managed to
|
||||||
|
// do that). First, let's try to find any method which is a private slot
|
||||||
|
// (then we don't need to add "private slots:" statement)
|
||||||
|
const unsigned mCount = cl->memberCount();
|
||||||
|
for (unsigned j = 0; j < mCount; j++) { // go through all members
|
||||||
|
if (const Declaration *decl = cl->memberAt(j)->asDeclaration())
|
||||||
|
if (const Function *fun = decl->type()->asFunction()) {
|
||||||
|
// we are only interested in declarations of methods.
|
||||||
|
// fun->column() returns always 0, what can cause trouble in case in one
|
||||||
|
// line if there is: "private slots: void foo();"
|
||||||
if (fun->isSlot() && fun->isPrivate()) {
|
if (fun->isSlot() && fun->isPrivate()) {
|
||||||
ITextEditable *editable = qobject_cast<ITextEditable *>(
|
if (ITextEditable *editable = editableAt(docFileName, fun->line(), fun->column()))
|
||||||
TextEditor::BaseTextEditor::openEditorAt(docFileName, fun->line(), fun->column()));
|
editable->insert(declaration + QLatin1String(" "));
|
||||||
// fun->column() raturns always 0, what can cause trouble in case in one
|
|
||||||
// line there is: "private slots: void foo();"
|
|
||||||
if (editable) {
|
|
||||||
editable->insert(QLatin1String("void ") + functionName + QLatin1String(";\n "));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// We didn't find any method under "private slots:", let's add "private slots:". Below code
|
// We didn't find any method under "private slots:", let's add "private slots:". Below code
|
||||||
// adds "private slots:" by the end of the class definition.
|
// adds "private slots:" by the end of the class definition.
|
||||||
|
|
||||||
ITextEditable *editable = qobject_cast<ITextEditable *>(
|
if (ITextEditable *editable = editableAt(docFileName, cl->line(), cl->column())) {
|
||||||
TextEditor::BaseTextEditor::openEditorAt(docFileName, cl->line(), cl->column()));
|
|
||||||
if (editable) {
|
|
||||||
int classEndPosition = findClassEndPosition(editable->contents(), editable->position());
|
int classEndPosition = findClassEndPosition(editable->contents(), editable->position());
|
||||||
if (classEndPosition >= 0) {
|
if (classEndPosition >= 0) {
|
||||||
int line, column;
|
int line, column;
|
||||||
editable->convertPosition(classEndPosition, &line, &column); // converts back position into a line and column
|
editable->convertPosition(classEndPosition, &line, &column); // converts back position into a line and column
|
||||||
editable->gotoLine(line, column); // go to position (we should be just before closing } of the class)
|
editable->gotoLine(line, column); // go to position (we should be just before closing } of the class)
|
||||||
editable->insert(QLatin1String("\nprivate slots:\n ")
|
editable->insert(QLatin1String("\nprivate slots:\n ") + declaration);
|
||||||
+ QLatin1String("void ") + functionName + QLatin1String(";\n"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Document::Ptr addDefinition(const QString &headerFileName, const QString &className,
|
static Document::Ptr addDefinition(const CPlusPlus::Snapshot &docTable,
|
||||||
|
const QString &headerFileName, const QString &className,
|
||||||
const QString &functionName, int *line)
|
const QString &functionName, int *line)
|
||||||
{
|
{
|
||||||
|
QString definition = QLatin1String("\nvoid ");
|
||||||
|
definition += className;
|
||||||
|
definition += QLatin1String("::");
|
||||||
|
definition += functionName;
|
||||||
|
definition += QLatin1String("\n{\n");
|
||||||
|
definition += QString(indentation, QLatin1Char(' '));
|
||||||
|
definition += QLatin1String("\n}\n");
|
||||||
|
|
||||||
// we find all documents which include headerFileName
|
// we find all documents which include headerFileName
|
||||||
QList<Document::Ptr> docList = findDocumentsIncluding(headerFileName, false);
|
const QList<Document::Ptr> docList = findDocumentsIncluding(docTable, headerFileName, false);
|
||||||
if (docList.isEmpty())
|
if (docList.isEmpty())
|
||||||
return Document::Ptr();
|
return Document::Ptr();
|
||||||
|
|
||||||
QFileInfo headerFI(headerFileName);
|
QFileInfo headerFI(headerFileName);
|
||||||
const QString headerBaseName = headerFI.baseName();
|
const QString headerBaseName = headerFI.baseName();
|
||||||
const QString headerAbsolutePath = headerFI.absolutePath();
|
const QString headerAbsolutePath = headerFI.absolutePath();
|
||||||
foreach (Document::Ptr doc, docList) {
|
foreach (const Document::Ptr &doc, docList) {
|
||||||
QFileInfo sourceFI(doc->fileName());
|
const QFileInfo sourceFI(doc->fileName());
|
||||||
// we take only those documents which has the same filename and path (maybe we don't need to compare the path???)
|
// we take only those documents which has the same filename and path (maybe we don't need to compare the path???)
|
||||||
if (headerBaseName == sourceFI.baseName() && headerAbsolutePath == sourceFI.absolutePath()) {
|
if (headerBaseName == sourceFI.baseName() && headerAbsolutePath == sourceFI.absolutePath()) {
|
||||||
ITextEditable *editable = qobject_cast<ITextEditable *>(
|
if (ITextEditable *editable = editableAt(doc->fileName(), 0, 0)) {
|
||||||
TextEditor::BaseTextEditor::openEditorAt(doc->fileName(), 0));
|
|
||||||
if (editable) {
|
|
||||||
const QString contents = editable->contents();
|
const QString contents = editable->contents();
|
||||||
int column;
|
int column;
|
||||||
editable->convertPosition(contents.length(), line, &column);
|
editable->convertPosition(contents.length(), line, &column);
|
||||||
editable->gotoLine(*line, column);
|
editable->gotoLine(*line, column);
|
||||||
editable->insert(QLatin1String("\nvoid ") + className + QLatin1String("::") +
|
editable->insert(definition);
|
||||||
functionName + QLatin1String("\n {\n\n }\n"));
|
|
||||||
*line += 1;
|
*line += 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
@@ -440,33 +449,84 @@ static Document::Ptr addDefinition(const QString &headerFileName, const QString
|
|||||||
return Document::Ptr();
|
return Document::Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert the parameter names into a signature, "void foo(bool)" ->
|
||||||
|
// "void foo(bool checked)"
|
||||||
static QString addParameterNames(const QString &functionSignature, const QStringList ¶meterNames)
|
static QString addParameterNames(const QString &functionSignature, const QStringList ¶meterNames)
|
||||||
{
|
{
|
||||||
QString functionName = functionSignature.left(functionSignature.indexOf(QLatin1Char('(')) + 1);
|
const int firstParen = functionSignature.indexOf(QLatin1Char('('));
|
||||||
QString argumentsString = functionSignature.mid(functionSignature.indexOf(QLatin1Char('(')) + 1);
|
QString functionName = functionSignature.left(firstParen + 1);
|
||||||
argumentsString = argumentsString.left(argumentsString.indexOf(QLatin1Char(')')));
|
QString argumentsString = functionSignature.mid(firstParen + 1);
|
||||||
|
const int lastParen = argumentsString.lastIndexOf(QLatin1Char(')'));
|
||||||
|
if (lastParen != -1)
|
||||||
|
argumentsString.truncate(lastParen);
|
||||||
const QStringList arguments = argumentsString.split(QLatin1Char(','), QString::SkipEmptyParts);
|
const QStringList arguments = argumentsString.split(QLatin1Char(','), QString::SkipEmptyParts);
|
||||||
for (int i = 0; i < arguments.count(); ++i) {
|
const int pCount = parameterNames.count();
|
||||||
|
const int aCount = arguments.count();
|
||||||
|
for (int i = 0; i < aCount; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
functionName += QLatin1String(", ");
|
functionName += QLatin1String(", ");
|
||||||
functionName += arguments.at(i);
|
functionName += arguments.at(i);
|
||||||
if (i < parameterNames.count())
|
if (i < pCount) {
|
||||||
functionName += QLatin1Char(' ') + parameterNames.at(i);
|
functionName += QLatin1Char(' ');
|
||||||
|
functionName += parameterNames.at(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
functionName += QLatin1Char(')');
|
functionName += QLatin1Char(')');
|
||||||
return functionName;
|
return functionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursively find a class definition in the document passed on or in its
|
||||||
|
// included files (going down [maxIncludeDepth] includes) and return a pair
|
||||||
|
// of <Class*, Document>.
|
||||||
|
|
||||||
|
typedef QPair<const Class *, Document::Ptr> ClassDocumentPtrPair;
|
||||||
|
|
||||||
|
static ClassDocumentPtrPair
|
||||||
|
findClassRecursively(const CPlusPlus::Snapshot &docTable,
|
||||||
|
const Document::Ptr &doc, const QString &className,
|
||||||
|
unsigned maxIncludeDepth, QString *namespaceName)
|
||||||
|
{
|
||||||
|
if (debugSlotNavigation)
|
||||||
|
qDebug() << Q_FUNC_INFO << doc->fileName() << maxIncludeDepth;
|
||||||
|
// Check document
|
||||||
|
if (const Class *cl = findClass(doc->globalNamespace(), className, namespaceName))
|
||||||
|
return ClassDocumentPtrPair(cl, doc);
|
||||||
|
if (maxIncludeDepth) {
|
||||||
|
// Check the includes
|
||||||
|
const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u;
|
||||||
|
foreach (const QString &include, doc->includedFiles()) {
|
||||||
|
const CPlusPlus::Snapshot::const_iterator it = docTable.constFind(include);
|
||||||
|
if (it != docTable.constEnd()) {
|
||||||
|
const Document::Ptr includeDoc = it.value();
|
||||||
|
const ClassDocumentPtrPair irc = findClassRecursively(docTable, it.value(), className, recursionMaxIncludeDepth, namespaceName);
|
||||||
|
if (irc.first)
|
||||||
|
return irc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ClassDocumentPtrPair(0, Document::Ptr());
|
||||||
|
}
|
||||||
|
|
||||||
void WorkbenchIntegration::slotNavigateToSlot(const QString &objectName, const QString &signalSignature,
|
void WorkbenchIntegration::slotNavigateToSlot(const QString &objectName, const QString &signalSignature,
|
||||||
const QStringList ¶meterNames)
|
const QStringList ¶meterNames)
|
||||||
{
|
{
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
if (!navigateToSlot(objectName, signalSignature, parameterNames, &errorMessage) && !errorMessage.isEmpty()) {
|
if (!navigateToSlot(objectName, signalSignature, parameterNames, &errorMessage) && !errorMessage.isEmpty()) {
|
||||||
QMessageBox::critical(m_few->designerEditor()->topLevel(), tr("Error finding source file"), errorMessage);
|
QMessageBox::warning(m_few->designerEditor()->topLevel(), tr("Error finding/adding a slot."), errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build name of the class as generated by uic, insert Ui namespace
|
||||||
|
// "foo::bar::form" -> "foo::bar::Ui::form"
|
||||||
|
|
||||||
|
static inline QString uiClassName(QString formObjectName)
|
||||||
|
{
|
||||||
|
const int indexOfScope = formObjectName.lastIndexOf(QLatin1String("::"));
|
||||||
|
const int uiNameSpaceInsertionPos = indexOfScope >= 0 ? indexOfScope : 0;
|
||||||
|
formObjectName.insert(uiNameSpaceInsertionPos, QLatin1String("Ui::"));
|
||||||
|
return formObjectName;
|
||||||
|
}
|
||||||
|
|
||||||
bool WorkbenchIntegration::navigateToSlot(const QString &objectName,
|
bool WorkbenchIntegration::navigateToSlot(const QString &objectName,
|
||||||
const QString &signalSignature,
|
const QString &signalSignature,
|
||||||
const QStringList ¶meterNames,
|
const QStringList ¶meterNames,
|
||||||
@@ -482,7 +542,10 @@ bool WorkbenchIntegration::navigateToSlot(const QString &objectName,
|
|||||||
const QFileInfo fi(currentUiFile);
|
const QFileInfo fi(currentUiFile);
|
||||||
const QString uicedName = QLatin1String("ui_") + fi.baseName() + QLatin1String(".h");
|
const QString uicedName = QLatin1String("ui_") + fi.baseName() + QLatin1String(".h");
|
||||||
|
|
||||||
QList<Document::Ptr> docList = findDocumentsIncluding(uicedName, true); // change to false when we know the absolute path to generated ui_<>.h file
|
// take all docs
|
||||||
|
|
||||||
|
const CPlusPlus::Snapshot docTable = cppModelManagerInstance()->snapshot();
|
||||||
|
QList<Document::Ptr> docList = findDocumentsIncluding(docTable, uicedName, true); // change to false when we know the absolute path to generated ui_<>.h file
|
||||||
|
|
||||||
if (debugSlotNavigation)
|
if (debugSlotNavigation)
|
||||||
qDebug() << objectName << signalSignature << "Looking for " << uicedName << " returned " << docList.size();
|
qDebug() << objectName << signalSignature << "Looking for " << uicedName << " returned " << docList.size();
|
||||||
@@ -493,44 +556,63 @@ bool WorkbenchIntegration::navigateToSlot(const QString &objectName,
|
|||||||
|
|
||||||
QDesignerFormWindowInterface *fwi = m_few->activeFormWindow()->formWindow();
|
QDesignerFormWindowInterface *fwi = m_few->activeFormWindow()->formWindow();
|
||||||
|
|
||||||
const QString uiClassName = fwi->mainContainer()->objectName();
|
const QString uiClass = uiClassName(fwi->mainContainer()->objectName());
|
||||||
|
|
||||||
if (debugSlotNavigation)
|
if (debugSlotNavigation)
|
||||||
qDebug() << "Checking docs for " << uiClassName;
|
qDebug() << "Checking docs for " << uiClass;
|
||||||
|
|
||||||
|
// Find the class definition in the file itself or in the directly
|
||||||
|
// included files (order 1).
|
||||||
|
QString namespaceName;
|
||||||
|
const Class *cl;
|
||||||
|
Document::Ptr doc;
|
||||||
|
|
||||||
|
foreach (const Document::Ptr &d, docList) {
|
||||||
|
const ClassDocumentPtrPair cd = findClassRecursively(docTable, d, uiClass, 1u , &namespaceName);
|
||||||
|
if (cd.first) {
|
||||||
|
cl = cd.first;
|
||||||
|
doc = cd.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cl) {
|
||||||
|
*errorMessage = msgClassNotFound(uiClass, docList);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (const Document::Ptr &doc, docList) {
|
|
||||||
QString namespaceName; // namespace of the class found
|
|
||||||
Class *cl = findClass(doc->globalNamespace(), uiClassName, &namespaceName);
|
|
||||||
if (cl) {
|
|
||||||
Overview o;
|
Overview o;
|
||||||
const QString className = namespaceName + o.prettyName(cl->name());
|
const QString className = namespaceName + o.prettyName(cl->name());
|
||||||
|
|
||||||
QString functionName = QLatin1String("on_") + objectName + QLatin1Char('_') + signalSignature;
|
const QString functionName = QLatin1String("on_") + objectName + QLatin1Char('_') + signalSignature;
|
||||||
QString functionNameWithParameterNames = addParameterNames(functionName, parameterNames);
|
const QString functionNameWithParameterNames = addParameterNames(functionName, parameterNames);
|
||||||
Function *fun = findDeclaration(cl, functionName);
|
|
||||||
|
if (debugSlotNavigation)
|
||||||
|
qDebug() << "Found " << uiClass << doc->fileName() << " checking " << functionName << functionNameWithParameterNames;
|
||||||
|
|
||||||
int line = 0;
|
int line = 0;
|
||||||
Document::Ptr sourceDoc;
|
Document::Ptr sourceDoc;
|
||||||
if (!fun) {
|
|
||||||
|
if (const Function *fun = findDeclaration(cl, functionName)) {
|
||||||
|
sourceDoc = findDefinition(fun, &line);
|
||||||
|
if (!sourceDoc) {
|
||||||
|
// add function definition to cpp file
|
||||||
|
sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// add function declaration to cl
|
// add function declaration to cl
|
||||||
addDeclaration(doc->fileName(), cl, functionNameWithParameterNames);
|
addDeclaration(doc->fileName(), cl, functionNameWithParameterNames);
|
||||||
|
|
||||||
// add function definition to cpp file
|
// add function definition to cpp file
|
||||||
sourceDoc = addDefinition(doc->fileName(), className, functionNameWithParameterNames, &line);
|
sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line);
|
||||||
} else {
|
|
||||||
sourceDoc = findDefinition(fun, &line);
|
|
||||||
if (!sourceDoc) {
|
|
||||||
// add function definition to cpp file
|
|
||||||
sourceDoc = addDefinition(doc->fileName(), className, functionNameWithParameterNames, &line);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (sourceDoc) {
|
|
||||||
// jump to function definition
|
|
||||||
TextEditor::BaseTextEditor::openEditorAt(sourceDoc->fileName(), line);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*errorMessage = msgClassNotFound(uiClassName, docList);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!sourceDoc) {
|
||||||
|
*errorMessage = tr("Unable to add the method definition.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// jump to function definition, position within code
|
||||||
|
TextEditor::BaseTextEditor::openEditorAt(sourceDoc->fileName(), line + 2, indentation);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user