customwizard.cpp 21.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
** 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
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** 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
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company 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
****************************************************************************/
30
31
32
33

#include "customwizard.h"
#include "customwizardparameters.h"
#include "customwizardpage.h"
34
#include "customwizardscriptgenerator.h"
Tobias Hunger's avatar
Tobias Hunger committed
35

36
37
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/baseprojectwizarddialog.h>
38
39

#include <coreplugin/icore.h>
40
#include <coreplugin/messagemanager.h>
41
42

#include <extensionsystem/pluginmanager.h>
43
#include <utils/fileutils.h>
44
45
#include <utils/qtcassert.h>

46
47
48
49
50
51
52
#include <QDebug>
#include <QFile>
#include <QMap>
#include <QDir>
#include <QTextStream>
#include <QFileInfo>
#include <QCoreApplication>
53
54
55
56
57
58

static const char templatePathC[] = "templates/wizards";
static const char configFileC[] = "wizard.xml";

namespace ProjectExplorer {

Tobias Hunger's avatar
Tobias Hunger committed
59
namespace Internal {
60
61
/*!
    \class ProjectExplorer::ICustomWizardFactory
62
63
64
    \brief The ICustomWizardFactory class implements a factory for creating
    custom wizards extending the base classes: CustomWizard and
    CustomProjectWizard.
65
66
67
68
69
70
71
72
73
74

    The factory can be registered under a name in CustomWizard. The name can
    be specified in the  \c <wizard class=''...> attribute in the \c wizard.xml file
    and thus allows for specifying a C++ derived wizard class.
    For example, this is currently used in Qt4ProjectManager to get Qt-specific
    aspects into the custom wizard.

    \sa ProjectExplorer::CustomWizard, ProjectExplorer::CustomProjectWizard
*/

Tobias Hunger's avatar
Tobias Hunger committed
75
76
class CustomWizardPrivate {
public:
Tobias Hunger's avatar
Tobias Hunger committed
77
    CustomWizardPrivate() : m_context(new CustomWizardContext) {}
78

Tobias Hunger's avatar
Tobias Hunger committed
79
80
    QSharedPointer<CustomWizardParameters> m_parameters;
    QSharedPointer<CustomWizardContext> m_context;
81
    static int verbose;
82
83
};

84
85
int CustomWizardPrivate::verbose = 0;

Tobias Hunger's avatar
Tobias Hunger committed
86
87
88
89
} // namespace Internal

using namespace ProjectExplorer::Internal;

90
91
92
/*!
    \class ProjectExplorer::CustomWizard

93
94
    \brief The CustomWizard class is a base class for custom wizards based on
    file templates and an XML
95
96
97
98
99
100
    configuration file (\c share/qtcreator/templates/wizards).

    Presents CustomWizardDialog (fields page containing path control) for wizards
    of type "class" or "file". Serves as base class for project wizards.
*/

hjk's avatar
hjk committed
101
102
CustomWizard::CustomWizard()
    : d(new CustomWizardPrivate)
103
104
105
106
107
108
109
110
{
}

CustomWizard::~CustomWizard()
{
    delete d;
}

111
112
113
114
115
116
117
118
119
120
void CustomWizard::setVerbose(int v)
{
    CustomWizardPrivate::verbose = v;
}

int CustomWizard::verbose()
{
    return CustomWizardPrivate::verbose;
}

121
122
void CustomWizard::setParameters(const CustomWizardParametersPtr &p)
{
Tobias Hunger's avatar
Tobias Hunger committed
123
124
    QTC_ASSERT(p, return);

125
    d->m_parameters = p;
Tobias Hunger's avatar
Tobias Hunger committed
126
127
128
129
130
131
132
133
134
135

    setId(p->id);
    setWizardKind(p->kind);
    setIcon(p->icon);
    setDescription(p->description);
    setDisplayName(p->displayName);
    setCategory(p->category);
    setDisplayCategory(p->displayCategory);
    setRequiredFeatures(p->requiredFeatures);
    setFlags(p->flags);
136
137
}

138
Core::BaseFileWizard *CustomWizard::create(QWidget *parent, const Core::WizardDialogParameters &p) const
139
{
140
141
    QTC_ASSERT(!d->m_parameters.isNull(), return 0);
    Core::BaseFileWizard *wizard = new Core::BaseFileWizard(parent);
142
143

    d->m_context->reset();
Tobias Hunger's avatar
Tobias Hunger committed
144
    CustomWizardPage *customPage = new CustomWizardPage(d->m_context, parameters());
145
    customPage->setPath(p.defaultPath());
146
147
148
149
    if (parameters()->firstPageId >= 0)
        wizard->setPage(parameters()->firstPageId, customPage);
    else
        wizard->addPage(customPage);
150
    foreach (QWizardPage *ep, p.extensionPages())
151
        wizard->addPage(ep);
152
    if (CustomWizardPrivate::verbose)
153
154
155
156
157
158
        qDebug() << "initWizardDialog" << wizard << wizard->pageIds();

    return wizard;
}

// Read out files and store contents with field contents replaced.
Tobias Hunger's avatar
Tobias Hunger committed
159
static inline bool createFile(CustomWizardFile cwFile,
160
161
162
163
164
165
166
167
                              const QString &sourceDirectory,
                              const QString &targetDirectory,
                              const CustomProjectWizard::FieldReplacementMap &fm,
                              Core::GeneratedFiles *files,
                              QString *errorMessage)
{
    const QChar slash =  QLatin1Char('/');
    const QString sourcePath = sourceDirectory + slash + cwFile.source;
168
    // Field replacement on target path
Tobias Hunger's avatar
Tobias Hunger committed
169
    CustomWizardContext::replaceFields(fm, &cwFile.target);
170
    const QString targetPath = targetDirectory + slash + cwFile.target;
171
    if (CustomWizardPrivate::verbose)
172
        qDebug() << "generating " << targetPath << sourcePath << fm;
173
174
175
176

    // Read contents of source file
    const QFile::OpenMode openMode
            = cwFile.binary ? QIODevice::ReadOnly : (QIODevice::ReadOnly|QIODevice::Text);
177
178
    Utils::FileReader reader;
    if (!reader.fetch(sourcePath, openMode, errorMessage))
179
        return false;
180

181
182
    Core::GeneratedFile generatedFile;
    generatedFile.setPath(targetPath);
183
184
185
    if (cwFile.binary) {
        // Binary file: Set data.
        generatedFile.setBinary(true);
186
        generatedFile.setBinaryContents(reader.data());
187
188
    } else {
        // Template file: Preprocess.
189
        const QString contentsIn = QString::fromLocal8Bit(reader.data());
Tobias Hunger's avatar
Tobias Hunger committed
190
        generatedFile.setContents(CustomWizardContext::processFile(fm, contentsIn));
191
192
    }

193
194
195
196
197
198
    Core::GeneratedFile::Attributes attributes = 0;
    if (cwFile.openEditor)
        attributes |= Core::GeneratedFile::OpenEditorAttribute;
    if (cwFile.openProject)
        attributes |= Core::GeneratedFile::OpenProjectAttribute;
    generatedFile.setAttributes(attributes);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    files->push_back(generatedFile);
    return true;
}

// Helper to find a specific wizard page of a wizard by type.
template <class WizardPage>
        WizardPage *findWizardPage(const QWizard *w)
{
    foreach (int pageId, w->pageIds())
        if (WizardPage *wp = qobject_cast<WizardPage *>(w->page(pageId)))
            return wp;
    return 0;
}

213
214
// Determine where to run the generator script. The user may specify
// an expression subject to field replacement, default is the target path.
Tobias Hunger's avatar
Tobias Hunger committed
215
216
static inline QString scriptWorkingDirectory(const QSharedPointer<CustomWizardContext> &ctx,
                                             const QSharedPointer<CustomWizardParameters> &p)
217
218
219
220
{
    if (p->filesGeneratorScriptWorkingDirectory.isEmpty())
        return ctx->targetPath;
    QString path = p->filesGeneratorScriptWorkingDirectory;
Tobias Hunger's avatar
Tobias Hunger committed
221
    CustomWizardContext::replaceFields(ctx->replacements, &path);
222
223
224
    return path;
}

225
226
227
Core::GeneratedFiles CustomWizard::generateFiles(const QWizard *dialog, QString *errorMessage) const
{
    // Look for the Custom field page to find the path
Tobias Hunger's avatar
Tobias Hunger committed
228
    const CustomWizardPage *cwp = findWizardPage<CustomWizardPage>(dialog);
229
    QTC_ASSERT(cwp, return Core::GeneratedFiles());
230
231

    CustomWizardContextPtr ctx = context();
232
    ctx->path = ctx->targetPath = cwp->path();
233
    ctx->replacements = replacementMap(dialog);
234
235
236
    if (CustomWizardPrivate::verbose) {
        QString logText;
        QTextStream str(&logText);
237
238
239
        str << "CustomWizard::generateFiles: " << ctx->targetPath << '\n';
        const FieldReplacementMap::const_iterator cend = context()->replacements.constEnd();
        for (FieldReplacementMap::const_iterator it = context()->replacements.constBegin(); it != cend; ++it)
240
241
242
            str << "  '" << it.key() << "' -> '" << it.value() << "'\n";
        qWarning("%s", qPrintable(logText));
    }
243
    return generateWizardFiles(errorMessage);
244
245
}

246
247
bool CustomWizard::writeFiles(const Core::GeneratedFiles &files, QString *errorMessage)
{
248
    if (!Core::BaseFileWizardFactory::writeFiles(files, errorMessage))
249
250
251
252
253
254
        return false;
    if (d->m_parameters->filesGeneratorScript.isEmpty())
        return true;
    // Prepare run of the custom script to generate. In the case of a
    // project wizard that is entirely created by a script,
    // the target project directory might not exist.
255
256
    // Known issue: By nature, the script does not honor
    // Core::GeneratedFile::KeepExistingFileAttribute.
257
    const CustomWizardContextPtr ctx = context();
258
259
260
    const QString scriptWorkingDir = scriptWorkingDirectory(ctx, d->m_parameters);
    const QDir scriptWorkingDirDir(scriptWorkingDir);
    if (!scriptWorkingDirDir.exists()) {
261
        if (CustomWizardPrivate::verbose)
262
263
            qDebug("Creating directory %s", qPrintable(scriptWorkingDir));
        if (!scriptWorkingDirDir.mkpath(scriptWorkingDir)) {
264
            *errorMessage = QString::fromLatin1("Unable to create the target directory \"%1\"").arg(scriptWorkingDir);
265
266
267
268
            return false;
        }
    }
    // Run the custom script to actually generate the files.
Tobias Hunger's avatar
Tobias Hunger committed
269
    if (!runCustomWizardGeneratorScript(scriptWorkingDir,
270
271
                                                  d->m_parameters->filesGeneratorScript,
                                                  d->m_parameters->filesGeneratorScriptArguments,
272
273
274
275
276
277
278
                                                  ctx->replacements, errorMessage))
        return false;
    // Paranoia: Check on the files generated by the script:
    foreach (const Core::GeneratedFile &generatedFile, files)
        if (generatedFile.attributes() & Core::GeneratedFile::CustomGeneratorAttribute)
            if (!QFileInfo(generatedFile.path()).isFile()) {
                *errorMessage = QString::fromLatin1("%1 failed to generate %2").
279
                        arg(d->m_parameters->filesGeneratorScript.back(), generatedFile.path());
280
281
282
283
284
285
                return false;
            }
    return true;
}

Core::GeneratedFiles CustomWizard::generateWizardFiles(QString *errorMessage) const
286
287
{
    Core::GeneratedFiles rc;
288
289
    const CustomWizardContextPtr ctx = context();

290
    QTC_ASSERT(!ctx->targetPath.isEmpty(), return rc);
291
292
293
294
295
296
297

    if (CustomWizardPrivate::verbose)
        qDebug() << "CustomWizard::generateWizardFiles: in "
                 << ctx->targetPath << ", using: " << ctx->replacements;

    // If generator script is non-empty, do a dry run to get it's files.
    if (!d->m_parameters->filesGeneratorScript.isEmpty()) {
Tobias Hunger's avatar
Tobias Hunger committed
298
        rc += dryRunCustomWizardGeneratorScript(scriptWorkingDirectory(ctx, d->m_parameters),
299
300
                                                          d->m_parameters->filesGeneratorScript,
                                                          d->m_parameters->filesGeneratorScriptArguments,
301
302
                                                          ctx->replacements,
                                                          errorMessage);
303
304
305
306
        if (rc.isEmpty())
            return rc;
    }
    // Add the template files specified by the <file> elements.
Tobias Hunger's avatar
Tobias Hunger committed
307
    foreach (const CustomWizardFile &file, d->m_parameters->files)
308
        if (!createFile(file, d->m_parameters->directory, ctx->targetPath, context()->replacements, &rc, errorMessage))
309
310
311
312
            return Core::GeneratedFiles();
    return rc;
}

313
314
// Create a replacement map of static base fields + wizard dialog fields
CustomWizard::FieldReplacementMap CustomWizard::replacementMap(const QWizard *w) const
315
{
Tobias Hunger's avatar
Tobias Hunger committed
316
    return CustomWizardFieldPage::replacementMap(w, context(), d->m_parameters->fields);
317
318
319
320
321
322
323
}

CustomWizard::CustomWizardParametersPtr CustomWizard::parameters() const
{
    return d->m_parameters;
}

324
325
326
327
328
CustomWizard::CustomWizardContextPtr CustomWizard::context() const
{
    return d->m_context;
}

Tobias Hunger's avatar
Tobias Hunger committed
329
CustomWizard *CustomWizard::createWizard(const CustomProjectWizard::CustomWizardParametersPtr &p)
330
{
331
332
    ICustomWizardMetaFactory *factory = ExtensionSystem::PluginManager::getObject<ICustomWizardMetaFactory>(
        [&p](ICustomWizardMetaFactory *factory) {
Tobias Hunger's avatar
Tobias Hunger committed
333
            return p->klass.isEmpty() ? (p->kind == factory->kind()) : (p->klass == factory->klass());
334
335
        });

336
    CustomWizard *rc = 0;
337
338
339
    if (factory)
        rc = factory->create();

340
341
342
343
    if (!rc) {
        qWarning("Unable to create custom wizard for class %s.", qPrintable(p->klass));
        return 0;
    }
344

345
346
347
348
    rc->setParameters(p);
    return rc;
}

349
/*!
350
    Reads \c share/qtcreator/templates/wizards and creates all custom wizards.
351
352
353
354
355
356
357
358

    As other plugins might register factories for derived
    classes, call it in extensionsInitialized().

    Scans the subdirectories of the template directory for directories
    containing valid configuration files and parse them into wizards.
*/

359
QList<Core::IWizardFactory *> CustomWizard::createWizards()
360
{
361
    QList<Core::IWizardFactory *> rc;
362
    QString errorMessage;
363
    QString verboseLog;
hjk's avatar
hjk committed
364
    const QString templateDirName = Core::ICore::resourcePath() +
365
                                    QLatin1Char('/') + QLatin1String(templatePathC);
366

367

hjk's avatar
hjk committed
368
    const QString userTemplateDirName = Core::ICore::userResourcePath() +
369
370
371
                                        QLatin1Char('/') + QLatin1String(templatePathC);


372
    const QDir templateDir(templateDirName);
373
    if (CustomWizardPrivate::verbose)
374
        verboseLog = QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(templateDirName);
375
    if (!templateDir.exists()) {
376
        if (CustomWizardPrivate::verbose)
377
378
379
380
           qWarning("Custom project template path %s does not exist.", qPrintable(templateDir.absolutePath()));
        return rc;
    }

381
382
    const QDir userTemplateDir(userTemplateDirName);
    if (CustomWizardPrivate::verbose)
383
        verboseLog = QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(userTemplateDirName);
384

385
386
387
    const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
    const QDir::SortFlags sortflags = QDir::Name|QDir::IgnoreCase;
    QList<QFileInfo> dirs = templateDir.entryInfoList(filters, sortflags);
388
389
    if (userTemplateDir.exists()) {
        if (CustomWizardPrivate::verbose)
390
            verboseLog = QString::fromLatin1("### CustomWizard: userTemplateDir \"%1\" found, adding\n").arg(userTemplateDirName);
391
        dirs += userTemplateDir.entryInfoList(filters, sortflags);
392
393
    }

394
395
396
    const QString configFile = QLatin1String(configFileC);
    // Check and parse config file in each directory.

397
398
    while (!dirs.isEmpty()) {
        const QFileInfo dirFi = dirs.takeFirst();
399
        const QDir dir(dirFi.absoluteFilePath());
400
        if (CustomWizardPrivate::verbose)
401
            verboseLog += QString::fromLatin1("CustomWizard: Scanning %1\n").arg(dirFi.absoluteFilePath());
402
        if (dir.exists(configFile)) {
Tobias Hunger's avatar
Tobias Hunger committed
403
            CustomWizardParametersPtr parameters(new CustomWizardParameters);
Tobias Hunger's avatar
Tobias Hunger committed
404
            switch (parameters->parse(dir.absoluteFilePath(configFile), &errorMessage)) {
Tobias Hunger's avatar
Tobias Hunger committed
405
            case CustomWizardParameters::ParseOk:
406
                parameters->directory = dir.absolutePath();
Tobias Hunger's avatar
Tobias Hunger committed
407
                if (CustomWizard *w = createWizard(parameters))
408
                    rc.push_back(w);
409
                else
410
                    qWarning("Custom wizard factory function failed for %s", qPrintable(parameters->id.toString()));
411
                break;
Tobias Hunger's avatar
Tobias Hunger committed
412
            case CustomWizardParameters::ParseDisabled:
413
414
415
                if (CustomWizardPrivate::verbose)
                    qWarning("Ignoring disabled wizard %s...", qPrintable(dir.absolutePath()));
                break;
Tobias Hunger's avatar
Tobias Hunger committed
416
            case CustomWizardParameters::ParseFailed:
417
418
                qWarning("Failed to initialize custom project wizard in %s: %s",
                         qPrintable(dir.absolutePath()), qPrintable(errorMessage));
419
                break;
420
            }
421
        } else {
422
423
424
425
426
427
            QList<QFileInfo> subDirs = dir.entryInfoList(filters, sortflags);
            if (!subDirs.isEmpty()) {
                // There is no QList::prepend(QList)...
                dirs.swap(subDirs);
                dirs.append(subDirs);
            } else if (CustomWizardPrivate::verbose) {
428
                verboseLog += QString::fromLatin1("CustomWizard: \"%1\" not found\n").arg(configFile);
429
            }
430
431
        }
    }
432
433
    if (CustomWizardPrivate::verbose) { // Print to output pane for Windows.
        qWarning("%s", qPrintable(verboseLog));
hjk's avatar
hjk committed
434
        Core::MessageManager::write(verboseLog, Core::MessageManager::ModeSwitch);
435
    }
436
437
438
    return rc;
}

439
440
/*!
    \class ProjectExplorer::CustomProjectWizard
441
    \brief The CustomProjectWizard class provides a custom project wizard.
442
443
444
445
446
447
448
449

    Presents a CustomProjectWizardDialog (Project intro page and fields page)
    for wizards of type "project".
    Overwrites postGenerateFiles() to open the project files according to the
    file attributes. Also inserts \c '%ProjectName%' into the base
    replacement map once the intro page is left to have it available
    for QLineEdit-type fields' default text.
*/
450

hjk's avatar
hjk committed
451
CustomProjectWizard::CustomProjectWizard()
452
453
454
{
}

455
/*!
456
    Can be reimplemented to create custom project wizards.
457
458
459
460

    initProjectWizardDialog() needs to be called.
*/

Tobias Hunger's avatar
Tobias Hunger committed
461
Core::BaseFileWizard *CustomProjectWizard::create(QWidget *parent,
462
                                     const Core::WizardDialogParameters &parameters) const
463
{
464
    BaseProjectWizardDialog *projectDialog = new BaseProjectWizardDialog(parent, parameters);
465
    initProjectWizardDialog(projectDialog,
466
467
                            parameters.defaultPath(),
                            parameters.extensionPages());
468
469
470
471
472
473
474
    return projectDialog;
}

void CustomProjectWizard::initProjectWizardDialog(BaseProjectWizardDialog *w,
                                                  const QString &defaultPath,
                                                  const WizardPageList &extensionPages) const
{
475
476
477
478
479
480
    const CustomWizardParametersPtr pa = parameters();
    QTC_ASSERT(!pa.isNull(), return);

    const CustomWizardContextPtr ctx = context();
    ctx->reset();

481
482
483
    if (!displayName().isEmpty())
        w->setWindowTitle(displayName());

484
    if (!pa->fields.isEmpty()) {
485
        if (parameters()->firstPageId >= 0)
Tobias Hunger's avatar
Tobias Hunger committed
486
            w->setPage(parameters()->firstPageId, new CustomWizardFieldPage(ctx, pa));
487
        else
Tobias Hunger's avatar
Tobias Hunger committed
488
            w->addPage(new CustomWizardFieldPage(ctx, pa));
489
    }
490
    foreach (QWizardPage *ep, extensionPages)
491
        w->addPage(ep);
492
493
    w->setPath(defaultPath);
    w->setProjectName(BaseProjectWizardDialog::uniqueProjectName(defaultPath));
494

495
    connect(w, SIGNAL(projectParametersChanged(QString,QString)), this, SLOT(projectParametersChanged(QString,QString)));
496

497
    if (CustomWizardPrivate::verbose)
498
499
500
501
502
503
        qDebug() << "initProjectWizardDialog" << w << w->pageIds();
}

Core::GeneratedFiles CustomProjectWizard::generateFiles(const QWizard *w, QString *errorMessage) const
{
    const BaseProjectWizardDialog *dialog = qobject_cast<const BaseProjectWizardDialog *>(w);
504
    QTC_ASSERT(dialog, return Core::GeneratedFiles());
505
506
    // Add project name as macro. Path is here under project directory
    CustomWizardContextPtr ctx = context();
507
508
    ctx->path = dialog->path();
    ctx->targetPath = ctx->path + QLatin1Char('/') + dialog->projectName();
509
    FieldReplacementMap fieldReplacementMap = replacementMap(dialog);
510
    fieldReplacementMap.insert(QLatin1String("ProjectName"), dialog->projectName());
511
    ctx->replacements = fieldReplacementMap;
512
    if (CustomWizardPrivate::verbose)
513
514
515
        qDebug() << "CustomProjectWizard::generateFiles" << dialog << ctx->targetPath << ctx->replacements;
    const Core::GeneratedFiles generatedFiles = generateWizardFiles(errorMessage);
    return generatedFiles;
516
517
}

518
/*!
519
    Opens the projects and editors for the files that have
520
521
522
    the respective attributes set.
*/

523
524
525
bool CustomProjectWizard::postGenerateOpen(const Core::GeneratedFiles &l, QString *errorMessage)
{
    // Post-Generate: Open the project and the editors as desired
526
    foreach (const Core::GeneratedFile &file, l) {
527
        if (file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
528
            if (!ProjectExplorerPlugin::openProject(file.path(), errorMessage))
529
530
531
                return false;
        }
    }
532
    return BaseFileWizardFactory::postGenerateOpenEditors(l, errorMessage);
533
534
}

535
536
bool CustomProjectWizard::postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, QString *errorMessage)
{
537
    if (CustomWizardPrivate::verbose)
538
539
        qDebug() << "CustomProjectWizard::postGenerateFiles()";
    return CustomProjectWizard::postGenerateOpen(l, errorMessage);
540
541
}

542
void CustomProjectWizard::projectParametersChanged(const QString &project, const QString & path)
543
544
545
{
    // Make '%ProjectName%' available in base replacements.
    context()->baseReplacements.insert(QLatin1String("ProjectName"), project);
546

547
    emit projectLocationChanged(path + QLatin1Char('/') + project);
548
549
}

550
} // namespace ProjectExplorer