qtcreatorintegration.cpp 26.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12
** 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
Eike Ziller's avatar
Eike Ziller committed
13 14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24 25 26
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

31
#include "qtcreatorintegration.h"
32
#include "formwindoweditor.h"
con's avatar
con committed
33
#include "formeditorw.h"
34
#include "editordata.h"
35
#include <widgethost.h>
36
#include <designer/cpp/formclasswizardpage.h>
con's avatar
con committed
37

38
#include <cpptools/cppmodelmanager.h>
39
#include <cpptools/cpptoolsconstants.h>
40
#include <cpptools/cppworkingcopy.h>
41
#include <cpptools/insertionpointlocator.h>
42
#include <cpptools/symbolfinder.h>
con's avatar
con committed
43 44
#include <cplusplus/Overview.h>
#include <coreplugin/icore.h>
45
#include <texteditor/texteditor.h>
46 47
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
48
#include <utils/qtcassert.h>
con's avatar
con committed
49

50 51
#include <QDesignerFormWindowInterface>
#include <QDesignerFormEditorInterface>
con's avatar
con committed
52

53
#include <QMessageBox>
con's avatar
con committed
54

55 56 57 58
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QUrl>
con's avatar
con committed
59

60
enum { indentation = 4 };
61

con's avatar
con committed
62 63 64
using namespace Designer::Internal;
using namespace CPlusPlus;
using namespace TextEditor;
hjk's avatar
hjk committed
65
using namespace ProjectExplorer;
con's avatar
con committed
66

67 68 69 70
static QString msgClassNotFound(const QString &uiClassName, const QList<Document::Ptr> &docList)
{
    QString files;
    foreach (const Document::Ptr &doc, docList) {
71 72
        files += QLatin1Char('\n');
        files += QDir::toNativeSeparators(doc->fileName());
73
    }
74
    return QtCreatorIntegration::tr(
75
        "The class containing \"%1\" could not be found in %2.\n"
76 77
        "Please verify the #include-directives.")
        .arg(uiClassName, files);
78 79
}

80 81
QtCreatorIntegration::QtCreatorIntegration(QDesignerFormEditorInterface *core, QObject *parent)
    : QDesignerIntegration(core, parent)
con's avatar
con committed
82
{
83 84 85 86 87
    setResourceFileWatcherBehaviour(ReloadResourceFileSilently);
    Feature f = features();
    f |= SlotNavigationFeature;
    f &= ~ResourceEditorFeature;
    setFeatures(f);
Robert Loehning's avatar
Robert Loehning committed
88 89
    connect(this, SIGNAL(navigateToSlot(QString,QString,QStringList)),
            this, SLOT(slotNavigateToSlot(QString,QString,QStringList)));
90 91
    connect(this, SIGNAL(helpRequested(QString,QString)),
            this, SLOT(slotDesignerHelpRequested(QString,QString)));
92 93 94
    slotSyncSettingsToDesigner();
    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
            this, SLOT(slotSyncSettingsToDesigner()));
95 96 97 98 99
}

void QtCreatorIntegration::slotDesignerHelpRequested(const QString &manual, const QString &document)
{
    // Pass on as URL.
kh1's avatar
kh1 committed
100 101
    emit creatorHelpRequested(QUrl(QString::fromLatin1("qthelp://com.trolltech.%1/qdoc/%2")
        .arg(manual, document)));
con's avatar
con committed
102 103
}

104
void QtCreatorIntegration::updateSelection()
con's avatar
con committed
105
{
106 107
    if (SharedTools::WidgetHost *host = FormEditorW::activeWidgetHost())
        host->updateFormWindowSelectionHandles(true);
108
    QDesignerIntegration::updateSelection();
con's avatar
con committed
109 110
}

111
QWidget *QtCreatorIntegration::containerWindow(QWidget * /*widget*/) const
con's avatar
con committed
112
{
113 114
    if (SharedTools::WidgetHost *host = FormEditorW::activeWidgetHost())
        return host->integrationContainer();
115
    return 0;
con's avatar
con committed
116 117
}

118
static QList<Document::Ptr> findDocumentsIncluding(const Snapshot &docTable,
119
                                                   const QString &fileName, bool checkFileNameOnly)
con's avatar
con committed
120 121
{
    QList<Document::Ptr> docList;
122
    foreach (const Document::Ptr &doc, docTable) { // we go through all documents
123 124 125
        const QList<Document::Include> includes = doc->resolvedIncludes()
            + doc->unresolvedIncludes();
        foreach (const Document::Include &include, includes) {
126
            if (checkFileNameOnly) {
127
                const QFileInfo fi(include.unresolvedFileName());
128 129 130 131
                if (fi.fileName() == fileName) { // we are only interested in docs which includes fileName only
                    docList.append(doc);
                }
            } else {
132
                if (include.resolvedFileName() == fileName)
133
                    docList.append(doc);
con's avatar
con committed
134 135 136 137 138 139
            }
        }
    }
    return docList;
}

140 141 142 143 144 145 146 147 148 149
// Does klass inherit baseClass?
static bool inherits(const Overview &o, const Class *klass, const QString &baseClass)
{
    const int baseClassCount = klass->baseClassCount();
    for (int b = 0; b < baseClassCount; b++)
        if (o.prettyName(klass->baseClassAt(b)->name()) == baseClass)
            return true;
    return false;
}

150
QString fullyQualifiedName(const LookupContext &context, const Name *name, Scope *scope)
151
{
152 153 154 155 156 157 158 159 160 161 162
    if (!name || !scope)
        return QString();

    const QList<LookupItem> items = context.lookup(name, scope);
    if (items.isEmpty()) { // "ui_xxx.h" might not be generated and nothing is forward declared.
        return Overview().prettyName(name);
    } else {
        Symbol *symbol = items.first().declaration();
        return Overview().prettyName(LookupContext::fullyQualifiedName(symbol));
    }
    return QString();
163
}
con's avatar
con committed
164

165 166 167
// Find class definition in namespace (that is, the outer class
// containing a member of the desired class type) or inheriting the desired class
// in case of forms using the Multiple Inheritance approach
168 169
static const Class *findClass(const Namespace *parentNameSpace, const LookupContext &context,
                              const QString &className, QString *namespaceName)
170
{
171
    if (Designer::Constants::Internal::debug)
172 173 174 175
        qDebug() << Q_FUNC_INFO << className;

    const Overview o;
    const unsigned namespaceMemberCount = parentNameSpace->memberCount();
Friedemann Kleint's avatar
Friedemann Kleint committed
176
    for (unsigned i = 0; i < namespaceMemberCount; ++i) { // we go through all namespace members
177 178 179
        const Symbol *sym = parentNameSpace->memberAt(i);
        // we have found a class - we are interested in classes only
        if (const Class *cl = sym->asClass()) {
180
            // 1) we go through class members
181
            const unsigned classMemberCount = cl->memberCount();
Friedemann Kleint's avatar
Friedemann Kleint committed
182
            for (unsigned j = 0; j < classMemberCount; ++j)
183
                if (Declaration *decl = cl->memberAt(j)->asDeclaration()) {
184 185
                // we want to know if the class contains a member (so we look into
                // a declaration) of uiClassName type
186 187 188 189
                    QString nameToMatch;
                    if (const NamedType *nt = decl->type()->asNamedType()) {
                        nameToMatch = fullyQualifiedName(context, nt->name(),
                                                         decl->enclosingScope());
con's avatar
con committed
190
                    // handle pointers to member variables
191 192 193 194 195 196 197 198
                    } else if (PointerType *pt = decl->type()->asPointerType()) {
                        if (NamedType *nt = pt->elementType()->asNamedType()) {
                            nameToMatch = fullyQualifiedName(context, nt->name(),
                                                             decl->enclosingScope());
                        }
                    }
                    if (!nameToMatch.isEmpty() && className == nameToMatch)
                        return cl;
199
                } // decl
200 201 202
            // 2) does it inherit the desired class
            if (inherits(o, cl, className))
                return cl;
203 204 205 206 207 208
        } else {
            // Check namespaces
            if (const Namespace *ns = sym->asNamespace()) {
                QString tempNS = *namespaceName;
                tempNS += o.prettyName(ns->name());
                tempNS += QLatin1String("::");
209
                if (const Class *cl = findClass(ns, context, className, &tempNS)) {
210 211
                    *namespaceName = tempNS;
                    return cl;
con's avatar
con committed
212
                }
213 214 215
            } // member is namespave
        } // member is no class
    } // for members
con's avatar
con committed
216 217 218
    return 0;
}

219
static Function *findDeclaration(const Class *cl, const QString &functionName)
con's avatar
con committed
220
{
221
    const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
222
    const unsigned mCount = cl->memberCount();
223 224
    // we are interested only in declarations (can be decl of function or of a field)
    // we are only interested in declarations of functions
225
    const Overview overview;
226
    for (unsigned j = 0; j < mCount; ++j) { // go through all members
227 228
        if (Declaration *decl = cl->memberAt(j)->asDeclaration())
            if (Function *fun = decl->type()->asFunctionType()) {
229 230 231 232 233 234
                // Format signature
                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();
235 236 237 238 239 240 241 242
                    if (i > 0)
                        memberFunction += QLatin1Char(',');
                    memberFunction += overview.prettyType(arg->type());
                }
                memberFunction += QLatin1Char(')');
                // we compare normalized signatures
                memberFunction = QString::fromUtf8(QMetaObject::normalizedSignature(memberFunction.toUtf8()));
                if (memberFunction == funName) // we match function names and argument lists
con's avatar
con committed
243 244 245 246 247 248
                    return fun;
            }
    }
    return 0;
}

249
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this function
250
static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
con's avatar
con committed
251
{
252
    if (CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance()) {
253
        const Snapshot snapshot = cppModelManager->snapshot();
254
        CppTools::SymbolFinder symbolFinder;
255
        if (Function *fun = symbolFinder.findMatchingDefinition(functionDeclaration, snapshot)) {
256
            if (line)
257
                *line = fun->line();
258

259
            return snapshot.document(QString::fromUtf8(fun->fileName(), fun->fileNameLength()));
con's avatar
con committed
260 261 262 263 264 265
        }
    }

    return Document::Ptr();
}

266
static inline BaseTextEditor *editorAt(const QString &fileName, int line, int column)
267
{
268
    return qobject_cast<BaseTextEditor *>(Core::EditorManager::openEditorAt(fileName, line, column,
Eike Ziller's avatar
Eike Ziller committed
269 270
                                                                         Core::Id(),
                                                                         Core::EditorManager::DoNotMakeVisible));
271 272
}

273 274 275 276
static void addDeclaration(const Snapshot &snapshot,
                           const QString &fileName,
                           const Class *cl,
                           const QString &functionName)
con's avatar
con committed
277
{
278 279 280 281
    QString declaration = QLatin1String("void ");
    declaration += functionName;
    declaration += QLatin1String(";\n");

282
    CppTools::CppRefactoringChanges refactoring(snapshot);
283
    CppTools::InsertionPointLocator find(refactoring);
284 285
    const CppTools::InsertionLocation loc = find.methodDeclarationInClass(
                fileName, cl, CppTools::InsertionPointLocator::PrivateSlot);
286 287

    //
288
    //! \todo change this to use the Refactoring changes.
289 290
    //

291
    if (BaseTextEditor *editor = editorAt(fileName, loc.line(), loc.column() - 1)) {
292 293 294 295 296 297 298
        QTextCursor tc = editor->textCursor();
        int pos = tc.position();
        tc.beginEditBlock();
        tc.insertText(loc.prefix() + declaration + loc.suffix());
        tc.setPosition(pos, QTextCursor::KeepAnchor);
        editor->textDocument()->autoIndent(tc);
        tc.endEditBlock();
299 300 301
    }
}

302
static Document::Ptr addDefinition(const Snapshot &docTable,
303 304 305 306
                                   const QString &headerFileName,
                                   const QString &className,
                                   const QString &functionName,
                                   int *line)
307
{
308 309 310 311 312 313 314 315
    QString definition = QLatin1String("\nvoid ");
    definition += className;
    definition += QLatin1String("::");
    definition += functionName;
    definition += QLatin1String("\n{\n");
    definition += QString(indentation, QLatin1Char(' '));
    definition += QLatin1String("\n}\n");

316
    // we find all documents which include headerFileName
317
    const QList<Document::Ptr> docList = findDocumentsIncluding(docTable, headerFileName, false);
318 319 320 321
    if (docList.isEmpty())
        return Document::Ptr();

    QFileInfo headerFI(headerFileName);
322
    const QString headerBaseName = headerFI.completeBaseName();
323 324
    foreach (const Document::Ptr &doc, docList) {
        const QFileInfo sourceFI(doc->fileName());
325 326
        // we take only those documents which have the same filename
        if (headerBaseName == sourceFI.baseName()) {
Erik Verbruggen's avatar
Erik Verbruggen committed
327
            //
328
            //! \todo change this to use the Refactoring changes.
Erik Verbruggen's avatar
Erik Verbruggen committed
329 330
            //

331
            if (BaseTextEditor *editor = editorAt(doc->fileName(), 0, 0)) {
332 333

                //
334
                //! \todo use the InsertionPointLocator to insert at the correct place.
Erik Verbruggen's avatar
Erik Verbruggen committed
335
                // (we'll have to extend that class first to do definition insertions)
336

337
                const QString contents = editor->textDocument()->plainText();
338
                int column;
339 340 341
                editor->convertPosition(contents.length(), line, &column);
                editor->gotoLine(*line, column);
                editor->insert(definition);
342 343 344 345 346 347
                *line += 1;
            }
            return doc;
        }
    }
    return Document::Ptr();
con's avatar
con committed
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
static QString addConstRefIfNeeded(const QString &argument)
{
    if (argument.startsWith(QLatin1String("const "))
            || argument.endsWith(QLatin1Char('&'))
            || argument.endsWith(QLatin1Char('*')))
        return argument;

    // for those types we don't want to add "const &"
    static const QStringList nonConstRefs = QStringList()
            << QLatin1String("bool")
            << QLatin1String("int")
            << QLatin1String("uint")
            << QLatin1String("float")
            << QLatin1String("double")
            << QLatin1String("long")
            << QLatin1String("short")
            << QLatin1String("char")
            << QLatin1String("signed")
            << QLatin1String("unsigned")
            << QLatin1String("qint64")
            << QLatin1String("quint64");

    for (int i = 0; i < nonConstRefs.count(); i++) {
        const QString nonConstRef = nonConstRefs.at(i);
        if (argument == nonConstRef || argument.startsWith(nonConstRef + QLatin1Char(' ')))
            return argument;
    }
    return QLatin1String("const ") + argument + QLatin1Char('&');
}

static QString formatArgument(const QString &argument)
{
    QString formattedArgument = argument;
    int i = argument.count();
    while (i > 0) { // from the end of the "argument" string
        i--;
        const QChar c = argument.at(i); // take the char
        if (c != QLatin1Char('*') && c != QLatin1Char('&')) { // if it's not the * or &
            formattedArgument.insert(i + 1, QLatin1Char(' ')); // insert space after that char or just append space (to separate it from the parameter name)
            break;
        }
    }
    return formattedArgument;
}

395 396
// Insert the parameter names into a signature, "void foo(bool)" ->
// "void foo(bool checked)"
397 398
static QString addParameterNames(const QString &functionSignature, const QStringList &parameterNames)
{
399 400 401 402 403 404
    const int firstParen = functionSignature.indexOf(QLatin1Char('('));
    QString functionName = functionSignature.left(firstParen + 1);
    QString argumentsString = functionSignature.mid(firstParen + 1);
    const int lastParen = argumentsString.lastIndexOf(QLatin1Char(')'));
    if (lastParen != -1)
        argumentsString.truncate(lastParen);
405
    const QStringList arguments = argumentsString.split(QLatin1Char(','), QString::SkipEmptyParts);
406 407 408
    const int pCount = parameterNames.count();
    const int aCount = arguments.count();
    for (int i = 0; i < aCount; ++i) {
409 410
        if (i > 0)
            functionName += QLatin1String(", ");
411 412
        const QString argument = addConstRefIfNeeded(arguments.at(i));
        functionName += formatArgument(argument);
413
        if (i < pCount) {
414 415 416 417 418 419 420 421
            // prepare parameterName
            QString parameterName = parameterNames.at(i);
            if (parameterName.isEmpty()) {
                const QString generatedName = QLatin1String("arg") + QString::number(i + 1);
                if (!parameterNames.contains(generatedName))
                    parameterName = generatedName;
            }
            // add parameterName if not empty
422
            if (!parameterName.isEmpty())
423
                functionName += parameterName;
424
        }
425 426 427 428 429
    }
    functionName += QLatin1Char(')');
    return functionName;
}

430 431 432 433 434 435 436
// 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
437
        findClassRecursively(const LookupContext &context, const QString &className,
438 439
                             unsigned maxIncludeDepth, QString *namespaceName)
{
440 441
    const Document::Ptr doc = context.thisDocument();
    const Snapshot docTable = context.snapshot();
442
    if (Designer::Constants::Internal::debug)
443
        qDebug() << Q_FUNC_INFO << doc->fileName() << className << maxIncludeDepth;
444
    // Check document
445
    if (const Class *cl = findClass(doc->globalNamespace(), context, className, namespaceName))
446 447 448 449 450
        return ClassDocumentPtrPair(cl, doc);
    if (maxIncludeDepth) {
        // Check the includes
        const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u;
        foreach (const QString &include, doc->includedFiles()) {
451
            const Snapshot::const_iterator it = docTable.find(include);
452
            if (it != docTable.end()) {
453
                const Document::Ptr includeDoc = it.value();
454 455 456
                LookupContext context(includeDoc, docTable);
                const ClassDocumentPtrPair irc = findClassRecursively(context, className,
                    recursionMaxIncludeDepth, namespaceName);
457 458 459 460 461 462 463
                if (irc.first)
                    return irc;
            }
        }
    }
    return ClassDocumentPtrPair(0, Document::Ptr());
}
464

465
void QtCreatorIntegration::slotNavigateToSlot(const QString &objectName, const QString &signalSignature,
466
        const QStringList &parameterNames)
467 468
{
    QString errorMessage;
469
    if (!navigateToSlot(objectName, signalSignature, parameterNames, &errorMessage) && !errorMessage.isEmpty())
470
        QMessageBox::warning(FormEditorW::designerEditor()->topLevel(), tr("Error finding/adding a slot."), errorMessage);
471 472
}

473 474 475 476 477 478
// 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("::"));
479
    const int uiNameSpaceInsertionPos = indexOfScope >= 0 ? indexOfScope + 2 : 0;
480 481 482 483
    formObjectName.insert(uiNameSpaceInsertionPos, QLatin1String("Ui::"));
    return formObjectName;
}

484
static Document::Ptr getParsedDocument(const QString &fileName,
485
                                       CppTools::WorkingCopy &workingCopy,
486
                                       Snapshot &snapshot)
487
{
488
    QByteArray src;
489 490 491
    if (workingCopy.contains(fileName)) {
        src = workingCopy.source(fileName);
    } else {
492 493
        Utils::FileReader reader;
        if (reader.fetch(fileName)) // ### FIXME error reporting
494
            src = QString::fromLocal8Bit(reader.data()).toUtf8();
495 496
    }

497
    Document::Ptr doc = snapshot.preprocessedDocument(src, fileName);
498
    doc->check();
499
    snapshot.insert(doc);
500 501 502
    return doc;
}

503 504 505
// Goto slot invoked by the designer context menu. Either navigates
// to an existing slot function or create a new one.

506
bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
507 508 509
                                          const QString &signalSignature,
                                          const QStringList &parameterNames,
                                          QString *errorMessage)
con's avatar
con committed
510
{
511 512
    typedef QMap<int, Document::Ptr> DocumentMap;

513
    const QString currentUiFile = FormEditorW::activeEditor()->document()->filePath();
514 515 516
#if 0
    return Designer::Internal::navigateToSlot(currentUiFile, objectName, signalSignature, parameterNames, errorMessage);
#endif
517 518
    // 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().
con's avatar
con committed
519 520 521 522
    // The idea is that the .pro file knows if the .ui files is inside, and the .pro file knows it will
    // be generating the ui_<>.h file for it, and the .pro file knows what the generated file's name and its absolute path will be.
    // So we should somehow get that info from project manager (?)
    const QFileInfo fi(currentUiFile);
523
    const QString uiFolder = fi.absolutePath();
524
    const QString uicedName = QLatin1String("ui_") + fi.completeBaseName() + QLatin1String(".h");
con's avatar
con committed
525

526
    // Retrieve code model snapshot restricted to project of ui file or the working copy.
527
    Snapshot docTable = CppTools::CppModelManager::instance()->snapshot();
528
    Snapshot newDocTable;
hjk's avatar
hjk committed
529
    const Project *uiProject = SessionManager::projectForFile(currentUiFile);
530
    if (uiProject) {
531 532
        for (Snapshot::const_iterator i = docTable.begin(), ei = docTable.end(); i != ei; ++i) {
            const Project *project = SessionManager::projectForFile(i.key().toString());
533
            if (project == uiProject)
534
                newDocTable.insert(i.value());
535 536
        }
    } else {
537
        const CppTools::WorkingCopy workingCopy =
538
                CppTools::CppModelManager::instance()->workingCopy();
539 540 541
        const Utils::FileName configFileName =
                Utils::FileName::fromString(CppTools::CppModelManager::configurationFileName());
        QHashIterator<Utils::FileName, QPair<QByteArray, unsigned> > it = workingCopy.iterator();
542 543
        while (it.hasNext()) {
            it.next();
544 545 546
            const Utils::FileName &fileName = it.key();
            if (fileName != configFileName)
                newDocTable.insert(docTable.document(fileName.toString()));
547
        }
548
    }
549 550
    docTable = newDocTable;

551
    // take all docs, find the ones that include the ui_xx.h.
552 553 554 555 556 557 558 559
    // Sort into a map, putting the ones whose path closely matches the ui-folder path
    // first in case there are project subdirectories that contain identical file names.
    const QList<Document::Ptr> docList = findDocumentsIncluding(docTable, uicedName, true); // change to false when we know the absolute path to generated ui_<>.h file
    DocumentMap docMap;
    foreach (const Document::Ptr &d, docList) {
        const QFileInfo docFi(d->fileName());
        docMap.insert(qAbs(docFi.absolutePath().compare(uiFolder, Qt::CaseInsensitive)), d);
    }
560

561 562
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << objectName << signalSignature << "Looking for " << uicedName << " returned " << docList.size();
563
    if (docMap.isEmpty()) {
564
        *errorMessage = tr("No documents matching \"%1\" could be found.\nRebuilding the project might help.").arg(uicedName);
565 566
        return false;
    }
con's avatar
con committed
567

568
    QDesignerFormWindowInterface *fwi = FormEditorW::activeWidgetHost()->formWindow();
con's avatar
con committed
569

570
    const QString uiClass = uiClassName(fwi->mainContainer()->objectName());
con's avatar
con committed
571

572
    if (Designer::Constants::Internal::debug)
573 574
        qDebug() << "Checking docs for " << uiClass;

575 576
    // Find the class definition (ui class defined as member or base class)
    // in the file itself or in the directly included files (order 1).
577
    QString namespaceName;
578
    const Class *cl = 0;
579 580
    Document::Ptr doc;

581
    foreach (const Document::Ptr &d, docMap) {
582 583
        LookupContext context(d, docTable);
        const ClassDocumentPtrPair cd = findClassRecursively(context, uiClass, 1u , &namespaceName);
584 585 586 587 588 589 590 591 592 593
        if (cd.first) {
            cl = cd.first;
            doc = cd.second;
            break;
        }
    }
    if (!cl) {
        *errorMessage = msgClassNotFound(uiClass, docList);
        return false;
    }
594

595 596
    Overview o;
    const QString className = namespaceName + o.prettyName(cl->name());
597 598
    if (Designer::Constants::Internal::debug)
        qDebug() << "Found class  " << className << doc->fileName();
599 600 601 602

    const QString functionName = QLatin1String("on_") + objectName + QLatin1Char('_') + signalSignature;
    const QString functionNameWithParameterNames = addParameterNames(functionName, parameterNames);

603 604
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << "Found " << uiClass << doc->fileName() << " checking " << functionName  << functionNameWithParameterNames;
605 606 607 608

    int line = 0;
    Document::Ptr sourceDoc;

609
    if (Function *fun = findDeclaration(cl, functionName)) {
610 611 612 613
        sourceDoc = findDefinition(fun, &line);
        if (!sourceDoc) {
            // add function definition to cpp file
            sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line);
con's avatar
con committed
614
        }
615 616
    } else {
        // add function declaration to cl
617
        CppTools::WorkingCopy workingCopy =
618
            CppTools::CppModelManager::instance()->workingCopy();
619 620 621
        const QString fileName = doc->fileName();
        getParsedDocument(fileName, workingCopy, docTable);
        addDeclaration(docTable, fileName, cl, functionNameWithParameterNames);
622 623

        // add function definition to cpp file
624
        sourceDoc = addDefinition(docTable, fileName, className, functionNameWithParameterNames, &line);
con's avatar
con committed
625 626
    }

627 628 629 630 631 632
    if (!sourceDoc) {
        *errorMessage = tr("Unable to add the method definition.");
        return false;
    }

    // jump to function definition, position within code
633
    Core::EditorManager::openEditorAt(sourceDoc->fileName(), line + 2, indentation);
634 635 636

    return true;
}
637 638 639 640

void QtCreatorIntegration::slotSyncSettingsToDesigner()
{
    // Set promotion-relevant parameters on integration.
hjk's avatar
hjk committed
641
    setHeaderSuffix(Core::MimeDatabase::preferredSuffixByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)));
642 643
    setHeaderLowercase(FormClassWizardPage::lowercaseHeaderFiles());
}