forked from qt-creator/qt-creator
Designer: Fix "Go to slot..." for project-less "Qt Designer Form Class"es
Task-number: QTCREATORBUG-9653 Change-Id: Ia50c295ee474d08b3fb0574a4f759a8ab901876a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
@@ -62,6 +62,11 @@ SOURCES += formeditorplugin.cpp \
|
|||||||
qtdesignerformclasscodegenerator.cpp \
|
qtdesignerformclasscodegenerator.cpp \
|
||||||
designerxmleditorwidget.cpp
|
designerxmleditorwidget.cpp
|
||||||
|
|
||||||
|
equals(TEST, 1) {
|
||||||
|
SOURCES += gotoslot_test.cpp
|
||||||
|
DEFINES += SRCDIR=\\\"$$PWD\\\"
|
||||||
|
}
|
||||||
|
|
||||||
RESOURCES += designer.qrc
|
RESOURCES += designer.qrc
|
||||||
|
|
||||||
OTHER_FILES += README.txt
|
OTHER_FILES += README.txt
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import qbs.base 1.0
|
import qbs.base 1.0
|
||||||
|
import qbs.FileInfo
|
||||||
|
|
||||||
import "../QtcPlugin.qbs" as QtcPlugin
|
import "../QtcPlugin.qbs" as QtcPlugin
|
||||||
|
import "../../../qbs/defaults.js" as Defaults
|
||||||
|
|
||||||
QtcPlugin {
|
QtcPlugin {
|
||||||
name: "Designer"
|
name: "Designer"
|
||||||
@@ -72,4 +74,13 @@ QtcPlugin {
|
|||||||
"formclasswizardparameters.cpp", "formclasswizardparameters.h",
|
"formclasswizardparameters.cpp", "formclasswizardparameters.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Group {
|
||||||
|
name: "Tests"
|
||||||
|
condition: Defaults.testsEnabled(qbs)
|
||||||
|
files: [ "gotoslot_test.cpp" ]
|
||||||
|
|
||||||
|
cpp.defines: outer.concat(['SRCDIR="' + FileInfo.path(filePath) + '"'])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void initializeTemplates();
|
void initializeTemplates();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
void test_gotoslot_withoutProject();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
153
src/plugins/designer/gotoslot_test.cpp
Normal file
153
src/plugins/designer/gotoslot_test.cpp
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** 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 "formeditorplugin.h"
|
||||||
|
|
||||||
|
#include "formeditorw.h"
|
||||||
|
|
||||||
|
#include <coreplugin/testdatadir.h>
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
|
||||||
|
#include <cplusplus/CppDocument.h>
|
||||||
|
#include <cplusplus/Overview.h>
|
||||||
|
|
||||||
|
#include <QDesignerFormEditorInterface>
|
||||||
|
#include <QDesignerIntegrationInterface>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
|
using namespace Core::Internal::Tests;
|
||||||
|
using namespace CppTools;
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
using namespace Designer;
|
||||||
|
using namespace Designer::Internal;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class MyTestDataDir : public Core::Internal::Tests::TestDataDir {
|
||||||
|
public:
|
||||||
|
MyTestDataDir(const QString &dir)
|
||||||
|
: TestDataDir(QLatin1String(SRCDIR "/../../../tests/designer/") + dir)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool containsSymbol(Scope *scope, const QString &functionName)
|
||||||
|
{
|
||||||
|
Overview oo;
|
||||||
|
for (int i = 0, end = scope->memberCount(); i < end; ++i) {
|
||||||
|
Symbol *symbol = scope->memberAt(i);
|
||||||
|
const QString symbolName = oo.prettyName(symbol->name());
|
||||||
|
if (symbolName == functionName)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GoToSlotTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GoToSlotTest() : m_modelManager(CppModelManagerInterface::instance()) { cleanup(); }
|
||||||
|
~GoToSlotTest() { cleanup(); }
|
||||||
|
|
||||||
|
void run() const
|
||||||
|
{
|
||||||
|
MyTestDataDir testData(QLatin1String("gotoslot_withoutProject"));
|
||||||
|
const QString cppFile = testData.file(QLatin1String("form.cpp"));
|
||||||
|
const QString hFile = testData.file(QLatin1String("form.h"));
|
||||||
|
const QString uiFile = testData.file(QLatin1String("form.ui"));
|
||||||
|
const QStringList files = QStringList() << cppFile << hFile << uiFile;
|
||||||
|
|
||||||
|
const QString functionName = QLatin1String("on_pushButton_clicked");
|
||||||
|
const QString qualifiedFunctionName = QLatin1String("Form::") + functionName;
|
||||||
|
|
||||||
|
foreach (const QString &file, files)
|
||||||
|
QVERIFY(EditorManager::openEditor(file));
|
||||||
|
QCOMPARE(EditorManager::documentModel()->openedDocuments().size(), files.size());
|
||||||
|
while (!m_modelManager->snapshot().contains(cppFile)
|
||||||
|
|| !m_modelManager->snapshot().contains(hFile)) {
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks before
|
||||||
|
Document::Ptr cppDocumentBefore = m_modelManager->snapshot().document(cppFile);
|
||||||
|
QCOMPARE(cppDocumentBefore->globalSymbolCount(), 2U);
|
||||||
|
QVERIFY(!containsSymbol(cppDocumentBefore->globalNamespace(), qualifiedFunctionName));
|
||||||
|
|
||||||
|
Document::Ptr hDocumentBefore = m_modelManager->snapshot().document(hFile);
|
||||||
|
QCOMPARE(hDocumentBefore->globalSymbolAt(1)->asScope()->memberCount(), 3U);
|
||||||
|
QVERIFY(!containsSymbol(hDocumentBefore->globalSymbolAt(1)->asScope(), functionName));
|
||||||
|
|
||||||
|
// Execute "Go To Slot"
|
||||||
|
FormEditorW *few = FormEditorW::instance();
|
||||||
|
QDesignerIntegrationInterface *integration = few->designerEditor()->integration();
|
||||||
|
QVERIFY(integration);
|
||||||
|
integration->emitNavigateToSlot(QLatin1String("pushButton"), QLatin1String("clicked()"),
|
||||||
|
QStringList());
|
||||||
|
QApplication::processEvents();
|
||||||
|
|
||||||
|
// Checks after
|
||||||
|
m_modelManager->updateSourceFiles(QStringList() << cppFile << hFile).waitForFinished();
|
||||||
|
|
||||||
|
QCOMPARE(EditorManager::currentDocument()->filePath(), cppFile);
|
||||||
|
QVERIFY(EditorManager::currentDocument()->isModified());
|
||||||
|
|
||||||
|
Document::Ptr cppDocumentAfter = m_modelManager->snapshot().document(cppFile);
|
||||||
|
QCOMPARE(cppDocumentAfter->globalSymbolCount(), 3U);
|
||||||
|
QVERIFY(containsSymbol(cppDocumentAfter->globalNamespace(), qualifiedFunctionName));
|
||||||
|
|
||||||
|
Document::Ptr hDocumentAfter = m_modelManager->snapshot().document(hFile);
|
||||||
|
QCOMPARE(hDocumentAfter->globalSymbolAt(1)->asScope()->memberCount(), 4U);
|
||||||
|
QVERIFY(containsSymbol(hDocumentAfter->globalSymbolAt(1)->asScope(), functionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
EditorManager::instance()->closeAllEditors(/*askAboutModifiedEditors =*/ false);
|
||||||
|
QVERIFY(EditorManager::documentModel()->openedDocuments().isEmpty());
|
||||||
|
|
||||||
|
m_modelManager->GC();
|
||||||
|
QVERIFY(m_modelManager->snapshot().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CppModelManagerInterface *m_modelManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
/// Check: Executes "Go To Slot..." on a QPushButton in a *.ui file and checks if the respective
|
||||||
|
/// header and source files are updated.
|
||||||
|
void FormEditorPlugin::test_gotoslot_withoutProject()
|
||||||
|
{
|
||||||
|
GoToSlotTest test;
|
||||||
|
test.run();
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "editordata.h"
|
#include "editordata.h"
|
||||||
#include <widgethost.h>
|
#include <widgethost.h>
|
||||||
|
|
||||||
|
#include <cpptools/cppmodelmanagerinterface.h>
|
||||||
#include <cpptools/cpptoolsconstants.h>
|
#include <cpptools/cpptoolsconstants.h>
|
||||||
#include <cpptools/insertionpointlocator.h>
|
#include <cpptools/insertionpointlocator.h>
|
||||||
#include <cpptools/symbolfinder.h>
|
#include <cpptools/symbolfinder.h>
|
||||||
@@ -131,15 +132,16 @@ static QList<Document::Ptr> findDocumentsIncluding(const Snapshot &docTable,
|
|||||||
{
|
{
|
||||||
QList<Document::Ptr> docList;
|
QList<Document::Ptr> docList;
|
||||||
foreach (const Document::Ptr &doc, docTable) { // we go through all documents
|
foreach (const Document::Ptr &doc, docTable) { // we go through all documents
|
||||||
const QStringList includes = doc->includedFiles();
|
const QList<Document::Include> includes = doc->resolvedIncludes()
|
||||||
foreach (const QString &include, includes) {
|
+ doc->unresolvedIncludes();
|
||||||
|
foreach (const Document::Include &include, includes) {
|
||||||
if (checkFileNameOnly) {
|
if (checkFileNameOnly) {
|
||||||
const QFileInfo fi(include);
|
const QFileInfo fi(include.unresolvedFileName());
|
||||||
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
|
||||||
docList.append(doc);
|
docList.append(doc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (include == fileName)
|
if (include.resolvedFileName() == fileName)
|
||||||
docList.append(doc);
|
docList.append(doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -530,21 +532,29 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
|
|||||||
const QString uiFolder = fi.absolutePath();
|
const QString uiFolder = fi.absolutePath();
|
||||||
const QString uicedName = QLatin1String("ui_") + fi.completeBaseName() + QLatin1String(".h");
|
const QString uicedName = QLatin1String("ui_") + fi.completeBaseName() + QLatin1String(".h");
|
||||||
|
|
||||||
// Retrieve code model snapshot restricted to project of ui file.
|
// Retrieve code model snapshot restricted to project of ui file or the working copy.
|
||||||
const ProjectExplorer::Project *uiProject = ProjectExplorer::ProjectExplorerPlugin::instance()->session()->projectForFile(currentUiFile);
|
|
||||||
if (!uiProject) {
|
|
||||||
*errorMessage = tr("Internal error: No project could be found for %1.").arg(currentUiFile);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Snapshot docTable = CppTools::CppModelManagerInterface::instance()->snapshot();
|
Snapshot docTable = CppTools::CppModelManagerInterface::instance()->snapshot();
|
||||||
Snapshot newDocTable;
|
Snapshot newDocTable;
|
||||||
|
ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
|
||||||
for (Snapshot::iterator it = docTable.begin(); it != docTable.end(); ++it) {
|
const ProjectExplorer::Project *uiProject = pe->session()->projectForFile(currentUiFile);
|
||||||
const ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::instance()->session()->projectForFile(it.key());
|
if (uiProject) {
|
||||||
if (project == uiProject)
|
Snapshot::const_iterator end = docTable.end();
|
||||||
newDocTable.insert(it.value());
|
for (Snapshot::iterator it = docTable.begin(); it != end; ++it) {
|
||||||
|
const ProjectExplorer::Project *project = pe->session()->projectForFile(it.key());
|
||||||
|
if (project == uiProject)
|
||||||
|
newDocTable.insert(it.value());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const CppTools::CppModelManagerInterface::WorkingCopy workingCopy =
|
||||||
|
CppTools::CppModelManagerInterface::instance()->workingCopy();
|
||||||
|
QHashIterator<QString, QPair<QString, unsigned> > it = workingCopy.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
const QString fileName = it.key();
|
||||||
|
if (fileName != CppTools::CppModelManagerInterface::configurationFileName())
|
||||||
|
newDocTable.insert(docTable.document(fileName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
docTable = newDocTable;
|
docTable = newDocTable;
|
||||||
|
|
||||||
// take all docs, find the ones that include the ui_xx.h.
|
// take all docs, find the ones that include the ui_xx.h.
|
||||||
|
|||||||
17
tests/designer/gotoslot_withoutProject/form.cpp
Normal file
17
tests/designer/gotoslot_withoutProject/form.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright header
|
||||||
|
|
||||||
|
#include "form.h"
|
||||||
|
#include "ui_form.h"
|
||||||
|
|
||||||
|
Form::Form(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::Form)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Form::~Form()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
24
tests/designer/gotoslot_withoutProject/form.h
Normal file
24
tests/designer/gotoslot_withoutProject/form.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright header
|
||||||
|
|
||||||
|
#ifndef FORM_H
|
||||||
|
#define FORM_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class Form;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Form : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Form(QWidget *parent = 0);
|
||||||
|
~Form();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::Form *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FORM_H
|
||||||
32
tests/designer/gotoslot_withoutProject/form.ui
Normal file
32
tests/designer/gotoslot_withoutProject/form.ui
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QPushButton" name="pushButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>60</y>
|
||||||
|
<width>87</width>
|
||||||
|
<height>27</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>PushButton</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user