qtcreatorintegration.cpp 27.2 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 13 14
** 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.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

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

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

48 49
#include <QDesignerFormWindowInterface>
#include <QDesignerFormEditorInterface>
con's avatar
con committed
50

51
#include <QMessageBox>
con's avatar
con committed
52

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

58
enum { indentation = 4 };
59

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

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

78
QtCreatorIntegration::QtCreatorIntegration(QDesignerFormEditorInterface *core, FormEditorW *parent) :
79 80 81 82 83
#if QT_VERSION >= 0x050000
    QDesignerIntegration(core, parent),
#else
    qdesigner_internal::QDesignerIntegration(core, parent),
#endif
con's avatar
con committed
84 85
    m_few(parent)
{
86 87 88 89 90 91 92
#if QT_VERSION >= 0x050000
    setResourceFileWatcherBehaviour(ReloadResourceFileSilently);
    Feature f = features();
    f |= SlotNavigationFeature;
    f &= ~ResourceEditorFeature;
    setFeatures(f);
#else
con's avatar
con committed
93 94 95
    setResourceFileWatcherBehaviour(QDesignerIntegration::ReloadSilently);
    setResourceEditingEnabled(false);
    setSlotNavigationEnabled(true);
96
#endif
Robert Loehning's avatar
Robert Loehning committed
97 98
    connect(this, SIGNAL(navigateToSlot(QString,QString,QStringList)),
            this, SLOT(slotNavigateToSlot(QString,QString,QStringList)));
99 100
    connect(this, SIGNAL(helpRequested(QString,QString)),
            this, SLOT(slotDesignerHelpRequested(QString,QString)));
101 102 103
    slotSyncSettingsToDesigner();
    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
            this, SLOT(slotSyncSettingsToDesigner()));
104 105 106 107 108
}

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

113
void QtCreatorIntegration::updateSelection()
con's avatar
con committed
114
{
115
    if (const EditorData ed = m_few->activeEditor())
116
        ed.widgetHost->updateFormWindowSelectionHandles(true);
117 118 119
#if QT_VERSION >= 0x050000
    QDesignerIntegration::updateSelection();
#else
con's avatar
con committed
120
    qdesigner_internal::QDesignerIntegration::updateSelection();
121
#endif
con's avatar
con committed
122 123
}

124
QWidget *QtCreatorIntegration::containerWindow(QWidget * /*widget*/) const
con's avatar
con committed
125
{
126
    if (const EditorData ed = m_few->activeEditor())
127
        return ed.widgetHost->integrationContainer();
128
    return 0;
con's avatar
con committed
129 130
}

131
static QList<Document::Ptr> findDocumentsIncluding(const Snapshot &docTable,
132
                                                   const QString &fileName, bool checkFileNameOnly)
con's avatar
con committed
133 134
{
    QList<Document::Ptr> docList;
135
    foreach (const Document::Ptr &doc, docTable) { // we go through all documents
136 137 138
        const QList<Document::Include> includes = doc->resolvedIncludes()
            + doc->unresolvedIncludes();
        foreach (const Document::Include &include, includes) {
139
            if (checkFileNameOnly) {
140
                const QFileInfo fi(include.unresolvedFileName());
141 142 143 144
                if (fi.fileName() == fileName) { // we are only interested in docs which includes fileName only
                    docList.append(doc);
                }
            } else {
145
                if (include.resolvedFileName() == fileName)
146
                    docList.append(doc);
con's avatar
con committed
147 148 149 150 151 152
            }
        }
    }
    return docList;
}

153 154 155 156 157 158 159 160 161 162
// 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;
}

163
QString fullyQualifiedName(const LookupContext &context, const Name *name, Scope *scope)
164
{
165 166 167 168 169 170 171 172 173 174 175
    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();
176
}
con's avatar
con committed
177

178 179 180
// 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
181 182
static const Class *findClass(const Namespace *parentNameSpace, const LookupContext &context,
                              const QString &className, QString *namespaceName)
183
{
184
    if (Designer::Constants::Internal::debug)
185 186 187 188
        qDebug() << Q_FUNC_INFO << className;

    const Overview o;
    const unsigned namespaceMemberCount = parentNameSpace->memberCount();
Friedemann Kleint's avatar
Friedemann Kleint committed
189
    for (unsigned i = 0; i < namespaceMemberCount; ++i) { // we go through all namespace members
190 191 192
        const Symbol *sym = parentNameSpace->memberAt(i);
        // we have found a class - we are interested in classes only
        if (const Class *cl = sym->asClass()) {
193
            // 1) we go through class members
194
            const unsigned classMemberCount = cl->memberCount();
Friedemann Kleint's avatar
Friedemann Kleint committed
195
            for (unsigned j = 0; j < classMemberCount; ++j)
196
                if (Declaration *decl = cl->memberAt(j)->asDeclaration()) {
197 198
                // we want to know if the class contains a member (so we look into
                // a declaration) of uiClassName type
199 200 201 202
                    QString nameToMatch;
                    if (const NamedType *nt = decl->type()->asNamedType()) {
                        nameToMatch = fullyQualifiedName(context, nt->name(),
                                                         decl->enclosingScope());
con's avatar
con committed
203
                    // handle pointers to member variables
204 205 206 207 208 209 210 211
                    } 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;
212
                } // decl
213 214 215
            // 2) does it inherit the desired class
            if (inherits(o, cl, className))
                return cl;
216 217 218 219 220 221
        } else {
            // Check namespaces
            if (const Namespace *ns = sym->asNamespace()) {
                QString tempNS = *namespaceName;
                tempNS += o.prettyName(ns->name());
                tempNS += QLatin1String("::");
222
                if (const Class *cl = findClass(ns, context, className, &tempNS)) {
223 224
                    *namespaceName = tempNS;
                    return cl;
con's avatar
con committed
225
                }
226 227 228
            } // member is namespave
        } // member is no class
    } // for members
con's avatar
con committed
229 230 231
    return 0;
}

232
static Function *findDeclaration(const Class *cl, const QString &functionName)
con's avatar
con committed
233
{
234
    const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
235
    const unsigned mCount = cl->memberCount();
236 237
    // we are interested only in declarations (can be decl of function or of a field)
    // we are only interested in declarations of functions
238
    const Overview overview;
239
    for (unsigned j = 0; j < mCount; ++j) { // go through all members
240 241
        if (Declaration *decl = cl->memberAt(j)->asDeclaration())
            if (Function *fun = decl->type()->asFunctionType()) {
242 243 244 245 246 247
                // 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();
248 249 250 251 252 253 254 255
                    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
256 257 258 259 260 261
                    return fun;
            }
    }
    return 0;
}

262
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this function
263
static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
con's avatar
con committed
264
{
265
    if (CppTools::CppModelManagerInterface *cppModelManager = CppTools::CppModelManagerInterface::instance()) {
266
        const Snapshot snapshot = cppModelManager->snapshot();
267
        CppTools::SymbolFinder symbolFinder;
268
        if (Function *fun = symbolFinder.findMatchingDefinition(functionDeclaration, snapshot)) {
269
            if (line)
270
                *line = fun->line();
271

272
            return snapshot.document(QString::fromUtf8(fun->fileName(), fun->fileNameLength()));
con's avatar
con committed
273 274 275 276 277 278
        }
    }

    return Document::Ptr();
}

279
static inline ITextEditor *editableAt(const QString &fileName, int line, int column)
280
{
Eike Ziller's avatar
Eike Ziller committed
281 282 283
    return qobject_cast<ITextEditor *>(Core::EditorManager::openEditorAt(fileName, line, column,
                                                                         Core::Id(),
                                                                         Core::EditorManager::DoNotMakeVisible));
284 285
}

286 287 288 289
static void addDeclaration(const Snapshot &snapshot,
                           const QString &fileName,
                           const Class *cl,
                           const QString &functionName)
con's avatar
con committed
290
{
291 292 293 294
    QString declaration = QLatin1String("void ");
    declaration += functionName;
    declaration += QLatin1String(";\n");

295
    CppTools::CppRefactoringChanges refactoring(snapshot);
296
    CppTools::InsertionPointLocator find(refactoring);
297 298
    const CppTools::InsertionLocation loc = find.methodDeclarationInClass(
                fileName, cl, CppTools::InsertionPointLocator::PrivateSlot);
299 300

    //
301
    //! \todo change this to use the Refactoring changes.
302 303
    //

304 305
    if (ITextEditor *editable = editableAt(fileName, loc.line(), loc.column() - 1)) {
        BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(editable->widget());
306 307 308 309
        if (editor) {
            QTextCursor tc = editor->textCursor();
            int pos = tc.position();
            tc.beginEditBlock();
310
            tc.insertText(loc.prefix() + declaration + loc.suffix());
311
            tc.setPosition(pos, QTextCursor::KeepAnchor);
312
            editor->baseTextDocument()->autoIndent(tc);
313
            tc.endEditBlock();
314 315 316 317
        }
    }
}

318
static Document::Ptr addDefinition(const Snapshot &docTable,
319 320 321 322
                                   const QString &headerFileName,
                                   const QString &className,
                                   const QString &functionName,
                                   int *line)
323
{
324 325 326 327 328 329 330 331
    QString definition = QLatin1String("\nvoid ");
    definition += className;
    definition += QLatin1String("::");
    definition += functionName;
    definition += QLatin1String("\n{\n");
    definition += QString(indentation, QLatin1Char(' '));
    definition += QLatin1String("\n}\n");

332
    // we find all documents which include headerFileName
333
    const QList<Document::Ptr> docList = findDocumentsIncluding(docTable, headerFileName, false);
334 335 336 337
    if (docList.isEmpty())
        return Document::Ptr();

    QFileInfo headerFI(headerFileName);
338
    const QString headerBaseName = headerFI.completeBaseName();
339 340
    foreach (const Document::Ptr &doc, docList) {
        const QFileInfo sourceFI(doc->fileName());
341 342
        // we take only those documents which have the same filename
        if (headerBaseName == sourceFI.baseName()) {
Erik Verbruggen's avatar
Erik Verbruggen committed
343
            //
344
            //! \todo change this to use the Refactoring changes.
Erik Verbruggen's avatar
Erik Verbruggen committed
345 346
            //

347
            if (ITextEditor *editable = editableAt(doc->fileName(), 0, 0)) {
348 349

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

353
                const QString contents = editable->textDocument()->plainText();
354 355 356
                int column;
                editable->convertPosition(contents.length(), line, &column);
                editable->gotoLine(*line, column);
357
                editable->insert(definition);
358 359 360 361 362 363
                *line += 1;
            }
            return doc;
        }
    }
    return Document::Ptr();
con's avatar
con committed
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 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
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;
}

411 412
// Insert the parameter names into a signature, "void foo(bool)" ->
// "void foo(bool checked)"
413 414
static QString addParameterNames(const QString &functionSignature, const QStringList &parameterNames)
{
415 416 417 418 419 420
    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);
421
    const QStringList arguments = argumentsString.split(QLatin1Char(','), QString::SkipEmptyParts);
422 423 424
    const int pCount = parameterNames.count();
    const int aCount = arguments.count();
    for (int i = 0; i < aCount; ++i) {
425 426
        if (i > 0)
            functionName += QLatin1String(", ");
427 428
        const QString argument = addConstRefIfNeeded(arguments.at(i));
        functionName += formatArgument(argument);
429
        if (i < pCount) {
430 431 432 433 434 435 436 437
            // 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
438
            if (!parameterName.isEmpty())
439
                functionName += parameterName;
440
        }
441 442 443 444 445
    }
    functionName += QLatin1Char(')');
    return functionName;
}

446 447 448 449 450 451 452
// 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
453
        findClassRecursively(const LookupContext &context, const QString &className,
454 455
                             unsigned maxIncludeDepth, QString *namespaceName)
{
456 457
    const Document::Ptr doc = context.thisDocument();
    const Snapshot docTable = context.snapshot();
458
    if (Designer::Constants::Internal::debug)
459
        qDebug() << Q_FUNC_INFO << doc->fileName() << className << maxIncludeDepth;
460
    // Check document
461
    if (const Class *cl = findClass(doc->globalNamespace(), context, className, namespaceName))
462 463 464 465 466
        return ClassDocumentPtrPair(cl, doc);
    if (maxIncludeDepth) {
        // Check the includes
        const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u;
        foreach (const QString &include, doc->includedFiles()) {
467
            const Snapshot::const_iterator it = docTable.find(include);
468
            if (it != docTable.end()) {
469
                const Document::Ptr includeDoc = it.value();
470 471 472
                LookupContext context(includeDoc, docTable);
                const ClassDocumentPtrPair irc = findClassRecursively(context, className,
                    recursionMaxIncludeDepth, namespaceName);
473 474 475 476 477 478 479
                if (irc.first)
                    return irc;
            }
        }
    }
    return ClassDocumentPtrPair(0, Document::Ptr());
}
480

481
void QtCreatorIntegration::slotNavigateToSlot(const QString &objectName, const QString &signalSignature,
482
        const QStringList &parameterNames)
483 484
{
    QString errorMessage;
485
    if (!navigateToSlot(objectName, signalSignature, parameterNames, &errorMessage) && !errorMessage.isEmpty())
486
        QMessageBox::warning(m_few->designerEditor()->topLevel(), tr("Error finding/adding a slot."), errorMessage);
487 488
}

489 490 491 492 493 494
// 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("::"));
495
    const int uiNameSpaceInsertionPos = indexOfScope >= 0 ? indexOfScope + 2 : 0;
496 497 498 499
    formObjectName.insert(uiNameSpaceInsertionPos, QLatin1String("Ui::"));
    return formObjectName;
}

500 501 502
static Document::Ptr getParsedDocument(const QString &fileName,
                                       CppTools::CppModelManagerInterface::WorkingCopy &workingCopy,
                                       Snapshot &snapshot)
503
{
504
    QByteArray src;
505 506 507
    if (workingCopy.contains(fileName)) {
        src = workingCopy.source(fileName);
    } else {
508 509
        Utils::FileReader reader;
        if (reader.fetch(fileName)) // ### FIXME error reporting
510
            src = QString::fromLocal8Bit(reader.data()).toUtf8();
511 512
    }

513
    Document::Ptr doc = snapshot.preprocessedDocument(src, fileName);
514
    doc->check();
515
    snapshot.insert(doc);
516 517 518
    return doc;
}

519 520 521
// Goto slot invoked by the designer context menu. Either navigates
// to an existing slot function or create a new one.

522
bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
523 524 525
                                          const QString &signalSignature,
                                          const QStringList &parameterNames,
                                          QString *errorMessage)
con's avatar
con committed
526
{
527 528
    typedef QMap<int, Document::Ptr> DocumentMap;

529
    const EditorData ed = m_few->activeEditor();
530
    QTC_ASSERT(ed, return false);
531
    const QString currentUiFile = ed.formWindowEditor->document()->filePath();
532 533 534
#if 0
    return Designer::Internal::navigateToSlot(currentUiFile, objectName, signalSignature, parameterNames, errorMessage);
#endif
535 536
    // 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
537 538 539 540
    // 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);
541
    const QString uiFolder = fi.absolutePath();
542
    const QString uicedName = QLatin1String("ui_") + fi.completeBaseName() + QLatin1String(".h");
con's avatar
con committed
543

544
    // Retrieve code model snapshot restricted to project of ui file or the working copy.
545 546
    Snapshot docTable = CppTools::CppModelManagerInterface::instance()->snapshot();
    Snapshot newDocTable;
hjk's avatar
hjk committed
547
    const Project *uiProject = SessionManager::projectForFile(currentUiFile);
548 549 550
    if (uiProject) {
        Snapshot::const_iterator end = docTable.end();
        for (Snapshot::iterator it = docTable.begin(); it != end; ++it) {
hjk's avatar
hjk committed
551
            const Project *project = SessionManager::projectForFile(it.key());
552 553 554 555 556 557
            if (project == uiProject)
                newDocTable.insert(it.value());
        }
    } else {
        const CppTools::CppModelManagerInterface::WorkingCopy workingCopy =
                CppTools::CppModelManagerInterface::instance()->workingCopy();
558
        QHashIterator<QString, QPair<QByteArray, unsigned> > it = workingCopy.iterator();
559 560 561 562 563 564
        while (it.hasNext()) {
            it.next();
            const QString fileName = it.key();
            if (fileName != CppTools::CppModelManagerInterface::configurationFileName())
                newDocTable.insert(docTable.document(fileName));
        }
565
    }
566 567
    docTable = newDocTable;

568
    // take all docs, find the ones that include the ui_xx.h.
569 570 571 572 573 574 575 576
    // 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);
    }
577

578 579
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << objectName << signalSignature << "Looking for " << uicedName << " returned " << docList.size();
580
    if (docMap.isEmpty()) {
581
        *errorMessage = tr("No documents matching '%1' could be found.\nRebuilding the project might help.").arg(uicedName);
582 583
        return false;
    }
con's avatar
con committed
584

585
    QDesignerFormWindowInterface *fwi = ed.widgetHost->formWindow();
con's avatar
con committed
586

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

589
    if (Designer::Constants::Internal::debug)
590 591
        qDebug() << "Checking docs for " << uiClass;

592 593
    // Find the class definition (ui class defined as member or base class)
    // in the file itself or in the directly included files (order 1).
594
    QString namespaceName;
595
    const Class *cl = 0;
596 597
    Document::Ptr doc;

598
    foreach (const Document::Ptr &d, docMap) {
599 600
        LookupContext context(d, docTable);
        const ClassDocumentPtrPair cd = findClassRecursively(context, uiClass, 1u , &namespaceName);
601 602 603 604 605 606 607 608 609 610
        if (cd.first) {
            cl = cd.first;
            doc = cd.second;
            break;
        }
    }
    if (!cl) {
        *errorMessage = msgClassNotFound(uiClass, docList);
        return false;
    }
611

612 613
    Overview o;
    const QString className = namespaceName + o.prettyName(cl->name());
614 615
    if (Designer::Constants::Internal::debug)
        qDebug() << "Found class  " << className << doc->fileName();
616 617 618 619

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

620 621
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << "Found " << uiClass << doc->fileName() << " checking " << functionName  << functionNameWithParameterNames;
622 623 624 625

    int line = 0;
    Document::Ptr sourceDoc;

626
    if (Function *fun = findDeclaration(cl, functionName)) {
627 628 629 630
        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
631
        }
632 633
    } else {
        // add function declaration to cl
634 635
        CppTools::CppModelManagerInterface::WorkingCopy workingCopy =
            CppTools::CppModelManagerInterface::instance()->workingCopy();
636 637 638
        const QString fileName = doc->fileName();
        getParsedDocument(fileName, workingCopy, docTable);
        addDeclaration(docTable, fileName, cl, functionNameWithParameterNames);
639 640

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

644 645 646 647 648 649
    if (!sourceDoc) {
        *errorMessage = tr("Unable to add the method definition.");
        return false;
    }

    // jump to function definition, position within code
650
    Core::EditorManager::openEditorAt(sourceDoc->fileName(), line + 2, indentation);
651 652 653

    return true;
}
654 655 656

void QtCreatorIntegration::slotSyncSettingsToDesigner()
{
657
#if QT_VERSION > 0x040800
658
    // Set promotion-relevant parameters on integration.
hjk's avatar
hjk committed
659
    setHeaderSuffix(Core::MimeDatabase::preferredSuffixByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)));
660 661 662
    setHeaderLowercase(FormClassWizardPage::lowercaseHeaderFiles());
#endif
}