forked from qt-creator/qt-creator
Wizards/Custom Wizards: Add code.
Task-number: QTCREATORBUG-423
This commit is contained in:
@@ -185,6 +185,7 @@ class BaseFileWizardParameterData : public QSharedData
|
||||
{
|
||||
public:
|
||||
explicit BaseFileWizardParameterData(IWizard::WizardKind kind = IWizard::FileWizard);
|
||||
void clear();
|
||||
|
||||
IWizard::WizardKind kind;
|
||||
QIcon icon;
|
||||
@@ -200,6 +201,17 @@ BaseFileWizardParameterData::BaseFileWizardParameterData(IWizard::WizardKind k)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseFileWizardParameterData::clear()
|
||||
{
|
||||
kind = IWizard::FileWizard;
|
||||
icon = QIcon();
|
||||
description.clear();
|
||||
displayName.clear();
|
||||
id.clear();
|
||||
category.clear();
|
||||
displayCategory.clear();
|
||||
}
|
||||
|
||||
BaseFileWizardParameters::BaseFileWizardParameters(IWizard::WizardKind kind) :
|
||||
m_d(new BaseFileWizardParameterData(kind))
|
||||
{
|
||||
@@ -221,6 +233,21 @@ BaseFileWizardParameters::~BaseFileWizardParameters()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseFileWizardParameters::clear()
|
||||
{
|
||||
m_d->clear();
|
||||
}
|
||||
|
||||
CORE_EXPORT QDebug operator<<(QDebug d, const BaseFileWizardParameters &p)
|
||||
{
|
||||
d.nospace() << "Kind: " << p.kind() << " Id: " << p.id()
|
||||
<< " Category: " << p.category()
|
||||
<< " DisplayName: " << p.displayName()
|
||||
<< " Description: " << p.description()
|
||||
<< " DisplayCategory: " << p.displayCategory();
|
||||
return d;
|
||||
}
|
||||
|
||||
IWizard::WizardKind BaseFileWizardParameters::kind() const
|
||||
{
|
||||
return m_d->kind;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWizard;
|
||||
class QWizardPage;
|
||||
class QDebug;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Core {
|
||||
@@ -105,6 +106,8 @@ public:
|
||||
BaseFileWizardParameters &operator=(const BaseFileWizardParameters&);
|
||||
~BaseFileWizardParameters();
|
||||
|
||||
void clear();
|
||||
|
||||
IWizard::WizardKind kind() const;
|
||||
void setKind(IWizard::WizardKind k);
|
||||
|
||||
@@ -130,6 +133,8 @@ private:
|
||||
QSharedDataPointer<BaseFileWizardParameterData> m_d;
|
||||
};
|
||||
|
||||
CORE_EXPORT QDebug operator<<(QDebug d, const BaseFileWizardParameters &);
|
||||
|
||||
/* A generic wizard for creating files.
|
||||
*
|
||||
* The abstract methods:
|
||||
|
||||
@@ -51,12 +51,13 @@ class PROJECTEXPLORER_EXPORT BaseProjectWizardDialog : public QWizard
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
explicit BaseProjectWizardDialog(QWidget *parent = 0);
|
||||
explicit BaseProjectWizardDialog(Utils::ProjectIntroPage *introPage,
|
||||
int introId = -1,
|
||||
QWidget *parent = 0);
|
||||
|
||||
public:
|
||||
explicit BaseProjectWizardDialog(QWidget *parent = 0);
|
||||
|
||||
virtual ~BaseProjectWizardDialog();
|
||||
|
||||
QString projectName() const;
|
||||
|
||||
396
src/plugins/projectexplorer/customwizard/customwizard.cpp
Normal file
396
src/plugins/projectexplorer/customwizard/customwizard.cpp
Normal file
@@ -0,0 +1,396 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "customwizard.h"
|
||||
#include "customwizardparameters.h"
|
||||
#include "customwizardpage.h"
|
||||
#include "projectexplorer.h"
|
||||
#include "baseprojectwizarddialog.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/mimedatabase.h>
|
||||
#include <cpptools/cpptoolsconstants.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
enum { debug = 0 };
|
||||
|
||||
static const char templatePathC[] = "templates/wizards";
|
||||
static const char configFileC[] = "wizard.xml";
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
struct CustomWizardPrivate {
|
||||
QSharedPointer<Internal::CustomWizardParameters> m_parameters;
|
||||
};
|
||||
|
||||
CustomWizard::CustomWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent) :
|
||||
Core::BaseFileWizard(baseFileParameters, parent),
|
||||
d(new CustomWizardPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
CustomWizard::~CustomWizard()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CustomWizard::setParameters(const CustomWizardParametersPtr &p)
|
||||
{
|
||||
d->m_parameters = p;
|
||||
}
|
||||
|
||||
// Add a wizard page with an id, visibly warn if something goes wrong.
|
||||
static inline void addWizardPage(QWizard *w, QWizardPage *p, int id)
|
||||
{
|
||||
if (id == -1) {
|
||||
w->addPage(p);
|
||||
} else {
|
||||
if (w->pageIds().contains(id)) {
|
||||
qWarning("Page %d already present in custom wizard dialog, defaulting to add.", id);
|
||||
w->addPage(p);
|
||||
} else {
|
||||
w->setPage(id, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a wizard with a custom file page.
|
||||
void CustomWizard::initWizardDialog(QWizard *wizard, const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const
|
||||
{
|
||||
QTC_ASSERT(!parameters().isNull(), return);
|
||||
Internal::CustomWizardPage *customPage = new Internal::CustomWizardPage(parameters()->fields);
|
||||
customPage->setPath(defaultPath);
|
||||
addWizardPage(wizard, customPage, parameters()->firstPageId);
|
||||
if (!parameters()->fieldPageTitle.isEmpty())
|
||||
customPage->setTitle(parameters()->fieldPageTitle);
|
||||
foreach(QWizardPage *ep, extensionPages)
|
||||
wizard->addPage(ep);
|
||||
Core::BaseFileWizard::setupWizard(wizard);
|
||||
if (debug)
|
||||
qDebug() << "initWizardDialog" << wizard << wizard->pageIds();
|
||||
}
|
||||
|
||||
QWizard *CustomWizard::createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const
|
||||
{
|
||||
QTC_ASSERT(!d->m_parameters.isNull(), return 0);
|
||||
QWizard *wizard = new QWizard(parent);
|
||||
initWizardDialog(wizard, defaultPath, extensionPages);
|
||||
return wizard;
|
||||
}
|
||||
|
||||
// Replace field values delimited by '%' with special modifiers:
|
||||
// %Field% -> simple replacement
|
||||
// %Field:l% -> lower case replacement, 'u' for upper case and so on.
|
||||
static void replaceFields(const CustomProjectWizard::FieldReplacementMap &fm, QString *s)
|
||||
{
|
||||
const QChar delimiter = QLatin1Char('%');
|
||||
const QChar modifierDelimiter = QLatin1Char(':');
|
||||
int pos = 0;
|
||||
while (pos < s->size()) {
|
||||
pos = s->indexOf(delimiter, pos);
|
||||
if (pos < 0)
|
||||
break;
|
||||
int nextPos = s->indexOf(delimiter, pos + 1);
|
||||
if (nextPos == -1)
|
||||
break;
|
||||
nextPos++; // Point past 2nd delimiter
|
||||
if (nextPos == pos + 2) {
|
||||
pos = nextPos; // Skip '%%'
|
||||
continue;
|
||||
}
|
||||
// Evaluate field specification for modifiers
|
||||
// "%field:l%"
|
||||
QString fieldSpec = s->mid(pos + 1, nextPos - pos - 2);
|
||||
const int fieldSpecSize = fieldSpec.size();
|
||||
char modifier = '\0';
|
||||
if (fieldSpecSize >= 3 && fieldSpec.at(fieldSpecSize - 2) == modifierDelimiter) {
|
||||
modifier = fieldSpec.at(fieldSpecSize - 1).toLatin1();
|
||||
fieldSpec.truncate(fieldSpecSize - 2);
|
||||
}
|
||||
const CustomProjectWizard::FieldReplacementMap::const_iterator it = fm.constFind(fieldSpec);
|
||||
if (it == fm.constEnd()) {
|
||||
pos = nextPos; // Not found, skip
|
||||
continue;
|
||||
}
|
||||
// Assign
|
||||
QString replacement = it.value();
|
||||
switch (modifier) {
|
||||
case 'l':
|
||||
replacement = it.value().toLower();
|
||||
break;
|
||||
case 'u':
|
||||
replacement = it.value().toUpper();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s->replace(pos, nextPos - pos, replacement);
|
||||
pos += replacement.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Read out files and store contents with field contents replaced.
|
||||
static inline bool createFile(Internal::CustomWizardFile cwFile,
|
||||
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;
|
||||
replaceFields(fm, &cwFile.target);
|
||||
const QString targetPath = QDir::toNativeSeparators(targetDirectory + slash + cwFile.target);
|
||||
if (debug)
|
||||
qDebug() << "generating " << targetPath << sourcePath << fm;
|
||||
QFile file(sourcePath);
|
||||
if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
|
||||
*errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(sourcePath, file.errorString());
|
||||
return false;
|
||||
}
|
||||
QString contents = QString::fromLocal8Bit(file.readAll());
|
||||
if (!contents.isEmpty() && !fm.isEmpty())
|
||||
replaceFields(fm, &contents);
|
||||
Core::GeneratedFile generatedFile;
|
||||
generatedFile.setContents(contents);
|
||||
generatedFile.setPath(targetPath);
|
||||
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;
|
||||
}
|
||||
|
||||
Core::GeneratedFiles CustomWizard::generateFiles(const QWizard *dialog, QString *errorMessage) const
|
||||
{
|
||||
// Look for the Custom field page to find the path
|
||||
const Internal::CustomWizardPage *cwp = findWizardPage<Internal::CustomWizardPage>(dialog);
|
||||
QTC_ASSERT(cwp, return Core::GeneratedFiles())
|
||||
QString path = cwp->path();
|
||||
const FieldReplacementMap fieldMap = defaultReplacementMap(dialog);
|
||||
if (debug)
|
||||
qDebug() << "CustomWizard::generateFiles" << dialog << path << fieldMap;
|
||||
return generateWizardFiles(path, fieldMap, errorMessage);
|
||||
}
|
||||
|
||||
Core::GeneratedFiles CustomWizard::generateWizardFiles(const QString &targetPath,
|
||||
const FieldReplacementMap &fieldReplacementMap,
|
||||
QString *errorMessage) const
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << "Replacements" << fieldReplacementMap;
|
||||
// Create files
|
||||
Core::GeneratedFiles rc;
|
||||
foreach(const Internal::CustomWizardFile &file, d->m_parameters->files)
|
||||
if (!createFile(file, d->m_parameters->directory, targetPath, fieldReplacementMap, &rc, errorMessage))
|
||||
return Core::GeneratedFiles();
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Create a default replacement map from the wizard dialog via fields
|
||||
// and add some useful fields.
|
||||
CustomWizard::FieldReplacementMap CustomWizard::defaultReplacementMap(const QWizard *w) const
|
||||
{
|
||||
FieldReplacementMap fieldReplacementMap;
|
||||
foreach(const Internal::CustomWizardField &field, d->m_parameters->fields) {
|
||||
const QString value = w->field(field.name).toString();
|
||||
fieldReplacementMap.insert(field.name, value);
|
||||
}
|
||||
const Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
|
||||
fieldReplacementMap.insert(QLatin1String("CppSourceSuffix"),
|
||||
mdb->preferredSuffixByType(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE)));
|
||||
fieldReplacementMap.insert(QLatin1String("CppHeaderSuffix"),
|
||||
mdb->preferredSuffixByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)));
|
||||
return fieldReplacementMap;
|
||||
}
|
||||
|
||||
CustomWizard::CustomWizardParametersPtr CustomWizard::parameters() const
|
||||
{
|
||||
return d->m_parameters;
|
||||
}
|
||||
|
||||
// Static factory map
|
||||
typedef QMap<QString, QSharedPointer<ICustomWizardFactory> > CustomWizardFactoryMap;
|
||||
Q_GLOBAL_STATIC(CustomWizardFactoryMap, customWizardFactoryMap)
|
||||
|
||||
void CustomWizard::registerFactory(const QString &name, const ICustomWizardFactoryPtr &f)
|
||||
{
|
||||
customWizardFactoryMap()->insert(name, f);
|
||||
}
|
||||
|
||||
CustomWizard *CustomWizard::createWizard(const CustomWizardParametersPtr &p, const Core::BaseFileWizardParameters &b)
|
||||
{
|
||||
CustomWizard * rc = 0;
|
||||
if (p->klass.isEmpty()) {
|
||||
// Use defaults for empty class names
|
||||
switch (b.kind()) {
|
||||
case Core::IWizard::ProjectWizard:
|
||||
rc = new CustomProjectWizard(b);
|
||||
break;
|
||||
case Core::IWizard::FileWizard:
|
||||
case Core::IWizard::ClassWizard:
|
||||
rc = new CustomWizard(b);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Look up class name in map
|
||||
const CustomWizardFactoryMap::const_iterator it = customWizardFactoryMap()->constFind(p->klass);
|
||||
if (it != customWizardFactoryMap()->constEnd())
|
||||
rc = it.value()->create(b);
|
||||
}
|
||||
if (!rc) {
|
||||
qWarning("Unable to create custom wizard for class %s.", qPrintable(p->klass));
|
||||
return 0;
|
||||
}
|
||||
rc->setParameters(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Scan the subdirectories of the template directory for directories
|
||||
// containing valid configuration files and parse them into wizards.
|
||||
QList<CustomWizard*> CustomWizard::createWizards()
|
||||
{
|
||||
QList<CustomWizard*> rc;
|
||||
QString errorMessage;
|
||||
const QString templateDirName = Core::ICore::instance()->resourcePath() +
|
||||
QLatin1Char('/') + QLatin1String(templatePathC);
|
||||
const QDir templateDir(templateDirName);
|
||||
if (!templateDir.exists()) {
|
||||
if (debug)
|
||||
qWarning("Custom project template path %s does not exist.", qPrintable(templateDir.absolutePath()));
|
||||
return rc;
|
||||
}
|
||||
|
||||
const QList<QFileInfo> dirs = templateDir.entryInfoList(QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot,
|
||||
QDir::Name|QDir::IgnoreCase);
|
||||
const QString configFile = QLatin1String(configFileC);
|
||||
// Check and parse config file in each directory.
|
||||
|
||||
foreach(const QFileInfo &dirFi, dirs) {
|
||||
const QDir dir(dirFi.absoluteFilePath());
|
||||
if (dir.exists(configFile)) {
|
||||
CustomWizardParametersPtr parameters(new Internal::CustomWizardParameters);
|
||||
Core::BaseFileWizardParameters baseFileParameters;
|
||||
if (parameters->parse(dir.absoluteFilePath(configFile), &baseFileParameters, &errorMessage)) {
|
||||
parameters->directory = dir.absolutePath();
|
||||
if (debug)
|
||||
qDebug() << (*parameters);
|
||||
if (CustomWizard *w = createWizard(parameters, baseFileParameters))
|
||||
rc.push_back(w);
|
||||
} else {
|
||||
qWarning("Failed to initialize custom project wizard in %s: %s",
|
||||
qPrintable(dir.absolutePath()), qPrintable(errorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// --------------- CustomProjectWizard
|
||||
|
||||
CustomProjectWizard::CustomProjectWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent) :
|
||||
CustomWizard(baseFileParameters, parent)
|
||||
{
|
||||
}
|
||||
|
||||
QWizard *CustomProjectWizard::createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const
|
||||
{
|
||||
QTC_ASSERT(!parameters().isNull(), return 0);
|
||||
BaseProjectWizardDialog *projectDialog = new BaseProjectWizardDialog(parent);
|
||||
initProjectWizardDialog(projectDialog, defaultPath, extensionPages);
|
||||
return projectDialog;
|
||||
}
|
||||
|
||||
void CustomProjectWizard::initProjectWizardDialog(BaseProjectWizardDialog *w,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const
|
||||
{
|
||||
QTC_ASSERT(!parameters().isNull(), return);
|
||||
if (!parameters()->fields.isEmpty()) {
|
||||
Internal::CustomWizardFieldPage *cp = new Internal::CustomWizardFieldPage(parameters()->fields);
|
||||
addWizardPage(w, cp, parameters()->firstPageId);
|
||||
if (!parameters()->fieldPageTitle.isEmpty())
|
||||
cp->setTitle(parameters()->fieldPageTitle);
|
||||
}
|
||||
foreach(QWizardPage *ep, extensionPages)
|
||||
w->addPage(ep);
|
||||
w->setPath(defaultPath);
|
||||
w->setProjectName(BaseProjectWizardDialog::uniqueProjectName(defaultPath));
|
||||
if (debug)
|
||||
qDebug() << "initProjectWizardDialog" << w << w->pageIds();
|
||||
}
|
||||
|
||||
Core::GeneratedFiles CustomProjectWizard::generateFiles(const QWizard *w, QString *errorMessage) const
|
||||
{
|
||||
const BaseProjectWizardDialog *dialog = qobject_cast<const BaseProjectWizardDialog *>(w);
|
||||
QTC_ASSERT(dialog, return Core::GeneratedFiles())
|
||||
const QString targetPath = dialog->path() + QLatin1Char('/') + dialog->projectName();
|
||||
// Add project name as macro.
|
||||
FieldReplacementMap fieldReplacementMap = defaultReplacementMap(dialog);
|
||||
fieldReplacementMap.insert(QLatin1String("ProjectName"), dialog->projectName());
|
||||
if (debug)
|
||||
qDebug() << "CustomProjectWizard::generateFiles" << dialog << targetPath << fieldReplacementMap;
|
||||
return generateWizardFiles(targetPath, fieldReplacementMap, errorMessage);
|
||||
}
|
||||
|
||||
bool CustomProjectWizard::postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, QString *errorMessage)
|
||||
{
|
||||
// Post-Generate: Open the project
|
||||
const QString proFileName = l.back().path();
|
||||
const bool opened = ProjectExplorer::ProjectExplorerPlugin::instance()->openProject(proFileName);
|
||||
if (debug)
|
||||
qDebug() << "CustomProjectWizard::postGenerateFiles: opened " << proFileName << opened;
|
||||
if (opened) {
|
||||
*errorMessage = tr("The project %1 could not be opened.").arg(proFileName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
153
src/plugins/projectexplorer/customwizard/customwizard.h
Normal file
153
src/plugins/projectexplorer/customwizard/customwizard.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CUSTOMPROJECTWIZARD_H
|
||||
#define CUSTOMPROJECTWIZARD_H
|
||||
|
||||
#include "../projectexplorer_export.h"
|
||||
|
||||
#include <coreplugin/basefilewizard.h>
|
||||
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDir;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class CustomWizard;
|
||||
struct CustomWizardPrivate;
|
||||
class BaseProjectWizardDialog;
|
||||
|
||||
namespace Internal {
|
||||
struct CustomWizardParameters;
|
||||
}
|
||||
|
||||
// Factory for creating wizard. Can be registered under a name
|
||||
// in CustomWizard.
|
||||
class ICustomWizardFactory {
|
||||
public:
|
||||
virtual CustomWizard *create(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent = 0) const = 0;
|
||||
virtual ~ICustomWizardFactory() {}
|
||||
};
|
||||
|
||||
// Convenience template to create wizard classes.
|
||||
template <class Wizard> class CustomWizardFactory : public ICustomWizardFactory {
|
||||
virtual CustomWizard *create(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent = 0) const
|
||||
{ return new Wizard(baseFileParameters, parent); }
|
||||
};
|
||||
|
||||
// A custom wizard presenting CustomWizardDialog (fields page containing
|
||||
// path control) for wizards of type "class" or "file". Serves as base class
|
||||
// for project wizards.
|
||||
|
||||
class PROJECTEXPLORER_EXPORT CustomWizard : public Core::BaseFileWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QMap<QString, QString> FieldReplacementMap;
|
||||
typedef QSharedPointer<ICustomWizardFactory> ICustomWizardFactoryPtr;
|
||||
|
||||
explicit CustomWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent = 0);
|
||||
virtual ~CustomWizard();
|
||||
|
||||
// Can be reimplemented to create custom wizards. initWizardDialog() needs to be
|
||||
// called.
|
||||
virtual QWizard *createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const;
|
||||
|
||||
virtual Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const;
|
||||
|
||||
|
||||
// Register a factory for a derived custom widget
|
||||
static void registerFactory(const QString &name, const ICustomWizardFactoryPtr &f);
|
||||
template <class Wizard> static void registerFactory(const QString &name)
|
||||
{ registerFactory(name, ICustomWizardFactoryPtr(new CustomWizardFactory<Wizard>)); }
|
||||
|
||||
// Create all wizards. As other plugins might register factories for derived
|
||||
// classes, call it in extensionsInitialized().
|
||||
static QList<CustomWizard*> createWizards();
|
||||
|
||||
protected:
|
||||
typedef QSharedPointer<Internal::CustomWizardParameters> CustomWizardParametersPtr;
|
||||
|
||||
void initWizardDialog(QWizard *w, const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const;
|
||||
|
||||
// generate files in path
|
||||
Core::GeneratedFiles generateWizardFiles(const QString &path,
|
||||
const FieldReplacementMap &defaultFields,
|
||||
QString *errorMessage) const;
|
||||
// Create replacement map from QWizard fields with additional useful fields.
|
||||
FieldReplacementMap defaultReplacementMap(const QWizard *w) const;
|
||||
|
||||
CustomWizardParametersPtr parameters() const;
|
||||
|
||||
private:
|
||||
void setParameters(const CustomWizardParametersPtr &p);
|
||||
|
||||
static CustomWizard *createWizard(const CustomWizardParametersPtr &p, const Core::BaseFileWizardParameters &b);
|
||||
CustomWizardPrivate *d;
|
||||
};
|
||||
|
||||
// A custom project wizard presenting CustomProjectWizardDialog
|
||||
// (Project intro page and fields page) for wizards of type "project".
|
||||
// Overwrites postGenerateFiles() to open the project file which is the
|
||||
// last one by convention.
|
||||
|
||||
class PROJECTEXPLORER_EXPORT CustomProjectWizard : public CustomWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CustomProjectWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent = 0);
|
||||
|
||||
// Can be reimplemented to create custom project wizards.
|
||||
// initProjectWizardDialog() needs to be called.
|
||||
virtual QWizard *createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const;
|
||||
|
||||
virtual Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const;
|
||||
|
||||
protected:
|
||||
virtual bool postGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage);
|
||||
|
||||
void initProjectWizardDialog(BaseProjectWizardDialog *w, const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const;
|
||||
};
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#endif // CUSTOMPROJECTWIZARD_H
|
||||
@@ -0,0 +1,7 @@
|
||||
INCLUDEPATH *= $$PWD
|
||||
HEADERS += $$PWD/customwizard.h \
|
||||
$$PWD/customwizardparameters.h \
|
||||
$$PWD/customwizardpage.h
|
||||
SOURCES += $$PWD/customwizard.cpp \
|
||||
$$PWD/customwizardparameters.cpp \
|
||||
$$PWD/customwizardpage.cpp
|
||||
160
src/plugins/projectexplorer/customwizard/customwizardpage.cpp
Normal file
160
src/plugins/projectexplorer/customwizard/customwizardpage.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "customwizardpage.h"
|
||||
#include "customwizardparameters.h"
|
||||
|
||||
#include <utils/pathchooser.h>
|
||||
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QtGui/QWizardPage>
|
||||
#include <QtGui/QFormLayout>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QRegExpValidator>
|
||||
#include <QtGui/QComboBox>
|
||||
|
||||
enum { debug = 0 };
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
TextFieldComboBox::TextFieldComboBox(QWidget *parent) :
|
||||
QComboBox(parent)
|
||||
{
|
||||
setEditable(false);
|
||||
connect(this, SIGNAL(currentIndexChanged(QString)), this, SIGNAL(textChanged(QString)));
|
||||
}
|
||||
|
||||
void TextFieldComboBox::setText(const QString &s)
|
||||
{
|
||||
const int index = findText(s);
|
||||
if (index != -1 && index != currentIndex())
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
|
||||
// --------------- CustomWizardFieldPage
|
||||
CustomWizardFieldPage::CustomWizardFieldPage(const FieldList &fields,
|
||||
QWidget *parent) :
|
||||
QWizardPage(parent),
|
||||
m_formLayout(new QFormLayout)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << fields;
|
||||
foreach(const CustomWizardField &f, fields)
|
||||
addField(f);
|
||||
setLayout(m_formLayout);
|
||||
}
|
||||
|
||||
void CustomWizardFieldPage::addRow(const QString &name, QWidget *w)
|
||||
{
|
||||
m_formLayout->addRow(name, w);
|
||||
}
|
||||
|
||||
// Create widget a control based on the control attributes map
|
||||
// and register it with the QWizard.
|
||||
QWidget *CustomWizardFieldPage::registerControl(const CustomWizardField &field)
|
||||
{
|
||||
// Register field, Indicate mandatory by '*' (only when registering)
|
||||
QString fieldName = field.name;
|
||||
if (field.mandatory)
|
||||
fieldName += QLatin1Char('*');
|
||||
// Check known classes: QComboBox
|
||||
const QString className = field.controlAttributes.value(QLatin1String("class"));
|
||||
if (className == QLatin1String("QComboBox")) {
|
||||
TextFieldComboBox *combo = new TextFieldComboBox;
|
||||
// Set up items
|
||||
do {
|
||||
const QString choices = field.controlAttributes.value(QLatin1String("combochoices"));
|
||||
if (choices.isEmpty())
|
||||
break;
|
||||
combo->addItems(choices.split(QLatin1Char(',')));
|
||||
bool ok;
|
||||
const QString currentIndexS = field.controlAttributes.value(QLatin1String("defaultindex"));
|
||||
if (currentIndexS.isEmpty())
|
||||
break;
|
||||
const int currentIndex = currentIndexS.toInt(&ok);
|
||||
if (!ok || currentIndex < 0 || currentIndex >= combo->count())
|
||||
break;
|
||||
combo->setCurrentIndex(currentIndex);
|
||||
} while (false);
|
||||
registerField(fieldName, combo, "text", SIGNAL(text4Changed(QString)));
|
||||
return combo;
|
||||
} // QComboBox
|
||||
// Default to QLineEdit
|
||||
QLineEdit *lineEdit = new QLineEdit;
|
||||
const QString validationRegExp = field.controlAttributes.value(QLatin1String("validator"));
|
||||
if (!validationRegExp.isEmpty()) {
|
||||
QRegExp re(validationRegExp);
|
||||
if (re.isValid()) {
|
||||
lineEdit->setValidator(new QRegExpValidator(re, lineEdit));
|
||||
} else {
|
||||
qWarning("Invalid custom wizard field validator regular expression %s.", qPrintable(validationRegExp));
|
||||
}
|
||||
}
|
||||
lineEdit->setText(field.controlAttributes.value(QLatin1String("defaulttext")));
|
||||
registerField(fieldName, lineEdit, "text", SIGNAL(textEdited(QString)));
|
||||
return lineEdit;
|
||||
}
|
||||
|
||||
void CustomWizardFieldPage::addField(const CustomWizardField &field)
|
||||
{
|
||||
addRow(field.description, registerControl(field));
|
||||
}
|
||||
|
||||
// --------------- CustomWizardPage
|
||||
|
||||
CustomWizardPage::CustomWizardPage(const FieldList &f,
|
||||
QWidget *parent) :
|
||||
CustomWizardFieldPage(f, parent),
|
||||
m_pathChooser(new Utils::PathChooser)
|
||||
{
|
||||
addRow(tr("Path:"), m_pathChooser);
|
||||
connect(m_pathChooser, SIGNAL(validChanged()), this, SIGNAL(completeChanged()));
|
||||
}
|
||||
|
||||
QString CustomWizardPage::path() const
|
||||
{
|
||||
return m_pathChooser->path();
|
||||
}
|
||||
|
||||
void CustomWizardPage::setPath(const QString &path)
|
||||
{
|
||||
m_pathChooser->setPath(path);
|
||||
}
|
||||
|
||||
bool CustomWizardPage::isComplete() const
|
||||
{
|
||||
return m_pathChooser->isValid();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
108
src/plugins/projectexplorer/customwizard/customwizardpage.h
Normal file
108
src/plugins/projectexplorer/customwizard/customwizardpage.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CUSTOMPROJECTWIZARDDIALOG_H
|
||||
#define CUSTOMPROJECTWIZARDDIALOG_H
|
||||
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QWizardPage>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QFormLayout;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils {
|
||||
class PathChooser;
|
||||
}
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
struct CustomWizardField;
|
||||
struct CustomWizardParameters;
|
||||
|
||||
// A non-editable combo for text editing purposes that plays
|
||||
// with QWizard::registerField (providing a settable text property).
|
||||
class TextFieldComboBox : public QComboBox {
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TextFieldComboBox(QWidget *parent = 0);
|
||||
|
||||
QString text() const { return currentText(); }
|
||||
void setText(const QString &s);
|
||||
|
||||
signals:
|
||||
void text4Changed(const QString &); // Do not conflict with Qt 3 compat signal.
|
||||
};
|
||||
|
||||
// A simple custom wizard page presenting the fields to be used
|
||||
// as page 2 of a BaseProjectWizardDialog if there are any fields.
|
||||
// Uses the 'field' functionality of QWizard.
|
||||
class CustomWizardFieldPage : public QWizardPage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QList<CustomWizardField> FieldList;
|
||||
|
||||
explicit CustomWizardFieldPage(const FieldList &f,
|
||||
QWidget *parent = 0);
|
||||
protected:
|
||||
inline void addRow(const QString &name, QWidget *w);
|
||||
|
||||
private:
|
||||
QWidget *registerControl(const CustomWizardField &f);
|
||||
|
||||
void addField(const CustomWizardField &f);
|
||||
QFormLayout *m_formLayout;
|
||||
};
|
||||
|
||||
// A custom wizard page presenting the fields to be used and a path chooser
|
||||
// at the bottom (for use by "class"/"file" wizards). Does validation on
|
||||
// the Path chooser only (as the other fields can by validated by regexps).
|
||||
|
||||
class CustomWizardPage : public CustomWizardFieldPage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CustomWizardPage(const FieldList &f,
|
||||
QWidget *parent = 0);
|
||||
|
||||
QString path() const;
|
||||
void setPath(const QString &path);
|
||||
|
||||
virtual bool isComplete() const;
|
||||
|
||||
private:
|
||||
Utils::PathChooser *m_pathChooser;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#endif // CUSTOMPROJECTWIZARDDIALOG_H
|
||||
@@ -0,0 +1,472 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "customwizardparameters.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <QtCore/QXmlStreamAttribute>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
enum { debug = 0 };
|
||||
|
||||
static const char customWizardElementC[] = "wizard";
|
||||
static const char iconElementC[] = "icon";
|
||||
static const char descriptionElementC[] = "description";
|
||||
static const char displayNameElementC[] = "displayName";
|
||||
static const char idAttributeC[] = "id";
|
||||
static const char kindAttributeC[] = "kind";
|
||||
static const char klassAttributeC[] = "class";
|
||||
static const char firstPageAttributeC[] = "firstpage";
|
||||
static const char langAttributeC[] = "xml:lang";
|
||||
static const char categoryAttributeC[] = "category";
|
||||
static const char displayCategoryElementC[] = "displayCategory";
|
||||
static const char fieldPageTitleElementC[] = "fieldpagetitle";
|
||||
static const char fieldsElementC[] = "fields";
|
||||
static const char fieldElementC[] = "field";
|
||||
|
||||
static const char fieldDescriptionElementC[] = "fielddescription";
|
||||
static const char fieldNameAttributeC[] = "name";
|
||||
static const char fieldMandatoryAttributeC[] = "mandatory";
|
||||
static const char fieldControlElementC[] = "fieldcontrol";
|
||||
|
||||
static const char filesElementC[] = "files";
|
||||
static const char fileElementC[] = "file";
|
||||
static const char fileNameSourceAttributeC[] = "source";
|
||||
static const char fileNameTargetAttributeC[] = "target";
|
||||
|
||||
enum ParseState {
|
||||
ParseBeginning,
|
||||
ParseWithinWizard,
|
||||
ParseWithinFields,
|
||||
ParseWithinField,
|
||||
ParseWithinFiles,
|
||||
ParseWithinFile,
|
||||
ParseError
|
||||
};
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
CustomWizardField::CustomWizardField() :
|
||||
mandatory(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CustomWizardField::clear()
|
||||
{
|
||||
mandatory = false;
|
||||
name.clear();
|
||||
description.clear();
|
||||
controlAttributes.clear();
|
||||
}
|
||||
|
||||
CustomWizardParameters::CustomWizardParameters() :
|
||||
firstPageId(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void CustomWizardParameters::clear()
|
||||
{
|
||||
directory.clear();
|
||||
files.clear();
|
||||
fields.clear();
|
||||
firstPageId = -1;
|
||||
}
|
||||
|
||||
// Resolve icon file path relative to config file directory.
|
||||
static inline QIcon wizardIcon(const QString &configFileFullPath,
|
||||
const QString &xmlIconFileName)
|
||||
{
|
||||
const QFileInfo fi(xmlIconFileName);
|
||||
if (fi.isFile())
|
||||
return QIcon(fi.absoluteFilePath());
|
||||
if (!fi.isRelative())
|
||||
return QIcon();
|
||||
// Expand by config path
|
||||
const QFileInfo absFi(QFileInfo(configFileFullPath).absolutePath() +
|
||||
QLatin1Char('/') + xmlIconFileName);
|
||||
if (absFi.isFile())
|
||||
return QIcon(absFi.absoluteFilePath());
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
// Forward a reader over element text
|
||||
static inline bool skipOverElementText(QXmlStreamReader &reader)
|
||||
{
|
||||
QXmlStreamReader::TokenType next = QXmlStreamReader::EndElement;
|
||||
do {
|
||||
next = reader.readNext();
|
||||
} while (next == QXmlStreamReader::Characters || next == QXmlStreamReader::EntityReference
|
||||
|| next == QXmlStreamReader::ProcessingInstruction || next == QXmlStreamReader::Comment);
|
||||
return next == QXmlStreamReader::EndElement;
|
||||
}
|
||||
|
||||
// Helper for reading text element depending on a language.
|
||||
// Assign the element text to the string passed on if the language matches,
|
||||
// that is, the element has no language attribute or there is an exact match.
|
||||
// If there is no match, skip over the element text.
|
||||
static inline void assignLanguageElementText(QXmlStreamReader &reader,
|
||||
const QString &desiredLanguage,
|
||||
QString *target)
|
||||
{
|
||||
const QStringRef elementLanguage = reader.attributes().value(langAttributeC);
|
||||
if (elementLanguage.isEmpty() || elementLanguage == desiredLanguage) {
|
||||
*target = reader.readElementText();
|
||||
} else {
|
||||
// Language mismatch: forward to end element.
|
||||
skipOverElementText(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy&paste from above to call a setter of BaseFileParameters.
|
||||
// Implementation of a sophisticated mem_fun pattern is left
|
||||
// as an exercise to the reader.
|
||||
static inline void assignLanguageElementText(QXmlStreamReader &reader,
|
||||
const QString &desiredLanguage,
|
||||
Core::BaseFileWizardParameters *bp,
|
||||
void (Core::BaseFileWizardParameters::*setter)(const QString &))
|
||||
{
|
||||
const QStringRef elementLanguage = reader.attributes().value(langAttributeC);
|
||||
if (elementLanguage.isEmpty() || elementLanguage == desiredLanguage) {
|
||||
(bp->*setter)(reader.readElementText());
|
||||
} else {
|
||||
// Language mismatch: forward to end element.
|
||||
skipOverElementText(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Read level sub-elements of "wizard"
|
||||
static bool parseCustomProjectElement(QXmlStreamReader &reader,
|
||||
const QString &configFileFullPath,
|
||||
const QString &language,
|
||||
CustomWizardParameters *p,
|
||||
Core::BaseFileWizardParameters *bp)
|
||||
{
|
||||
const QStringRef elementName = reader.name();
|
||||
if (elementName == QLatin1String(iconElementC)) {
|
||||
const QString path = reader.readElementText();
|
||||
const QIcon icon = wizardIcon(configFileFullPath, path);
|
||||
if (icon.availableSizes().isEmpty()) {
|
||||
qWarning("Invalid icon path '%s' encountered in custom project template %s.",
|
||||
qPrintable(path), qPrintable(configFileFullPath));
|
||||
} else {
|
||||
bp->setIcon(icon);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (elementName == QLatin1String(descriptionElementC)) {
|
||||
assignLanguageElementText(reader, language, bp,
|
||||
&Core::BaseFileWizardParameters::setDescription);
|
||||
return true;
|
||||
}
|
||||
if (elementName == QLatin1String(displayNameElementC)) {
|
||||
assignLanguageElementText(reader, language, bp,
|
||||
&Core::BaseFileWizardParameters::setDisplayName);
|
||||
return true;
|
||||
}
|
||||
if (elementName == QLatin1String(displayCategoryElementC)) {
|
||||
assignLanguageElementText(reader, language, bp,
|
||||
&Core::BaseFileWizardParameters::setDisplayCategory);
|
||||
return true;
|
||||
}
|
||||
if (elementName == QLatin1String(fieldPageTitleElementC)) {
|
||||
assignLanguageElementText(reader, language, &p->fieldPageTitle);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read sub-elements of "fields"
|
||||
static bool parseFieldElement(QXmlStreamReader &reader,
|
||||
const QString &language,
|
||||
CustomWizardField *m)
|
||||
{
|
||||
const QStringRef elementName = reader.name();
|
||||
if (elementName == QLatin1String(fieldDescriptionElementC)) {
|
||||
assignLanguageElementText(reader, language, &m->description);
|
||||
return true;
|
||||
}
|
||||
// Copy widget control attributes
|
||||
if (elementName == QLatin1String(fieldControlElementC)) {
|
||||
foreach(const QXmlStreamAttribute &attribute, reader.attributes())
|
||||
m->controlAttributes.insert(attribute.name().toString(), attribute.value().toString());
|
||||
skipOverElementText(reader);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Switch parser state depending on opening element name.
|
||||
static ParseState nextOpeningState(ParseState in, const QStringRef &name)
|
||||
{
|
||||
switch (in) {
|
||||
case ParseBeginning:
|
||||
if (name == QLatin1String(customWizardElementC))
|
||||
return ParseWithinWizard;
|
||||
break;
|
||||
case ParseWithinWizard:
|
||||
if (name == QLatin1String(fieldsElementC))
|
||||
return ParseWithinFields;
|
||||
if (name == QLatin1String(filesElementC))
|
||||
return ParseWithinFiles;
|
||||
break;
|
||||
case ParseWithinFields:
|
||||
if (name == QLatin1String(fieldElementC))
|
||||
return ParseWithinField;
|
||||
break;
|
||||
case ParseWithinFiles:
|
||||
if (name == QLatin1String(fileElementC))
|
||||
return ParseWithinFile;
|
||||
break;
|
||||
case ParseWithinField:
|
||||
case ParseWithinFile:
|
||||
case ParseError:
|
||||
break;
|
||||
}
|
||||
return ParseError;
|
||||
};
|
||||
|
||||
// Switch parser state depending on closing element name.
|
||||
static ParseState nextClosingState(ParseState in, const QStringRef &name)
|
||||
{
|
||||
switch (in) {
|
||||
case ParseBeginning:
|
||||
break;
|
||||
case ParseWithinWizard:
|
||||
if (name == QLatin1String(customWizardElementC))
|
||||
return ParseBeginning;
|
||||
break;
|
||||
case ParseWithinFields:
|
||||
if (name == QLatin1String(fieldsElementC))
|
||||
return ParseWithinWizard;
|
||||
break;
|
||||
case ParseWithinField:
|
||||
if (name == QLatin1String(fieldElementC))
|
||||
return ParseWithinFields;
|
||||
break;
|
||||
case ParseWithinFiles:
|
||||
if (name == QLatin1String(filesElementC))
|
||||
return ParseWithinWizard;
|
||||
break;
|
||||
case ParseWithinFile:
|
||||
if (name == QLatin1String(fileElementC))
|
||||
return ParseWithinFiles;
|
||||
break;
|
||||
case ParseError:
|
||||
break;
|
||||
}
|
||||
return ParseError;
|
||||
};
|
||||
|
||||
// Parse kind attribute
|
||||
static inline Core::IWizard::WizardKind kindAttribute(const QXmlStreamReader &r)
|
||||
{
|
||||
const QStringRef value = r.attributes().value(QLatin1String(kindAttributeC));
|
||||
if (!value.isEmpty()) {
|
||||
if (value == QLatin1String("file"))
|
||||
return Core::IWizard::FileWizard;
|
||||
if (value == QLatin1String("class"))
|
||||
return Core::IWizard::ClassWizard;
|
||||
}
|
||||
return Core::IWizard::ProjectWizard;
|
||||
}
|
||||
|
||||
static inline QString msgError(const QXmlStreamReader &reader,
|
||||
const QString &fileName,
|
||||
const QString &what)
|
||||
{
|
||||
return QString::fromLatin1("Error in %1 at line %2, column %3: %4").
|
||||
arg(fileName).arg(reader.lineNumber()).arg(reader.columnNumber()).arg(what);
|
||||
}
|
||||
|
||||
static inline bool booleanAttributeValue(const QXmlStreamReader &r, const char *name)
|
||||
{
|
||||
return r.attributes().value(QLatin1String(name)) == QLatin1String("true");
|
||||
}
|
||||
|
||||
static inline int integerAttributeValue(const QXmlStreamReader &r, const char *name, int defaultValue)
|
||||
{
|
||||
const QString sValue = r.attributes().value(QLatin1String(name)).toString();
|
||||
if (sValue.isEmpty())
|
||||
return defaultValue;
|
||||
bool ok;
|
||||
const int value = sValue.toInt(&ok);
|
||||
if (!ok) {
|
||||
qWarning("Invalid integer value specification '%s' for attribute '%s'.",
|
||||
qPrintable(sValue), name);
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline QString attributeValue(const QXmlStreamReader &r, const char *name)
|
||||
{
|
||||
return r.attributes().value(QLatin1String(name)).toString();
|
||||
}
|
||||
|
||||
// Return locale language attribute "de_UTF8" -> "de", empty string for "C"
|
||||
static inline QString localeLanguage()
|
||||
{
|
||||
QLocale loc;
|
||||
QString name = loc.name();
|
||||
const int underScorePos = name.indexOf(QLatin1Char('_'));
|
||||
if (underScorePos != -1)
|
||||
name.truncate(underScorePos);
|
||||
if (name.compare(QLatin1String("C"), Qt::CaseInsensitive) == 0)
|
||||
name.clear();
|
||||
return name;
|
||||
}
|
||||
|
||||
// Main parsing routine
|
||||
bool CustomWizardParameters::parse(QIODevice &device,
|
||||
const QString &configFileFullPath,
|
||||
Core::BaseFileWizardParameters *bp,
|
||||
QString *errorMessage)
|
||||
{
|
||||
QXmlStreamReader reader(&device);
|
||||
QXmlStreamReader::TokenType token = QXmlStreamReader::EndDocument;
|
||||
ParseState state = ParseBeginning;
|
||||
clear();
|
||||
bp->clear();
|
||||
bp->setKind(Core::IWizard::ProjectWizard);
|
||||
const QString language = localeLanguage();
|
||||
CustomWizardField field;
|
||||
do {
|
||||
token = reader.readNext();
|
||||
switch (token) {
|
||||
case QXmlStreamReader::Invalid:
|
||||
*errorMessage = msgError(reader, configFileFullPath, reader.errorString());
|
||||
return false;
|
||||
case QXmlStreamReader::StartElement:
|
||||
do {
|
||||
// Read out subelements applicable to current state
|
||||
if (state == ParseWithinWizard && parseCustomProjectElement(reader, configFileFullPath, language, this, bp))
|
||||
break;
|
||||
if (state == ParseWithinField && parseFieldElement(reader, language, &field))
|
||||
break;
|
||||
// switch to next state
|
||||
state = nextOpeningState(state, reader.name());
|
||||
// Read attributes post state-switching
|
||||
switch (state) {
|
||||
case ParseError:
|
||||
*errorMessage = msgError(reader, configFileFullPath,
|
||||
QString::fromLatin1("Unexpected start element %1").arg(reader.name().toString()));
|
||||
return false;
|
||||
case ParseWithinWizard:
|
||||
bp->setId(attributeValue(reader, idAttributeC));
|
||||
bp->setCategory(attributeValue(reader, categoryAttributeC));
|
||||
bp->setKind(kindAttribute(reader));
|
||||
klass = attributeValue(reader, klassAttributeC);
|
||||
firstPageId = integerAttributeValue(reader, firstPageAttributeC, -1);
|
||||
break;
|
||||
case ParseWithinField: // field attribute
|
||||
field.name = attributeValue(reader, fieldNameAttributeC);
|
||||
field.mandatory = booleanAttributeValue(reader, fieldMandatoryAttributeC);
|
||||
break;
|
||||
case ParseWithinFile: { // file attribute
|
||||
CustomWizardFile file;
|
||||
file.source = attributeValue(reader, fileNameSourceAttributeC);
|
||||
file.target = attributeValue(reader, fileNameTargetAttributeC);
|
||||
if (file.target.isEmpty())
|
||||
file.target = file.source;
|
||||
if (file.source.isEmpty()) {
|
||||
qWarning("Skipping empty file name in custom project.");
|
||||
} else {
|
||||
files.push_back(file);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
break;
|
||||
case QXmlStreamReader::EndElement:
|
||||
state = nextClosingState(state, reader.name());
|
||||
if (state == ParseError) {
|
||||
*errorMessage = msgError(reader, configFileFullPath,
|
||||
QString::fromLatin1("Unexpected end element %1").arg(reader.name().toString()));
|
||||
return false;
|
||||
}
|
||||
if (state == ParseWithinFields) { // Leaving a field element
|
||||
fields.push_back(field);
|
||||
field.clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (token != QXmlStreamReader::EndDocument);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomWizardParameters::parse(const QString &configFileFullPath,
|
||||
Core::BaseFileWizardParameters *bp,
|
||||
QString *errorMessage)
|
||||
{
|
||||
QFile configFile(configFileFullPath);
|
||||
if (!configFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
|
||||
*errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(configFileFullPath, configFile.errorString());
|
||||
return false;
|
||||
}
|
||||
return parse(configFile, configFileFullPath, bp, errorMessage);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const CustomWizardField &m)
|
||||
{
|
||||
QDebug nsp = d.nospace();
|
||||
nsp << "Name: " << m.name;
|
||||
if (m.mandatory)
|
||||
nsp << '*';
|
||||
nsp << " Desc: " << m.description << " Control: " << m.controlAttributes;
|
||||
return d;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const CustomWizardFile &f)
|
||||
{
|
||||
d.nospace() << "source: " << f.source << " target: " << f.target;
|
||||
return d;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const CustomWizardParameters &p)
|
||||
{
|
||||
QDebug nsp = d.nospace();
|
||||
nsp << "Dir: " << p.directory << " klass:" << p.klass << " Files: " << p.files;
|
||||
if (!p.fields.isEmpty())
|
||||
nsp << " Fields: " << p.fields;
|
||||
nsp << "First page: " << p.firstPageId;
|
||||
return d;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CUSTOMPROJECTWIZARDPARAMETERS_H
|
||||
#define CUSTOMPROJECTWIZARDPARAMETERS_H
|
||||
|
||||
#include <coreplugin/basefilewizard.h>
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIODevice;
|
||||
class QDebug;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
struct CustomWizardField {
|
||||
// Parameters of the widget control are stored as map
|
||||
typedef QMap<QString, QString> ControlAttributeMap;
|
||||
CustomWizardField();
|
||||
void clear();
|
||||
|
||||
QString description;
|
||||
QString name;
|
||||
ControlAttributeMap controlAttributes;
|
||||
bool mandatory;
|
||||
};
|
||||
|
||||
struct CustomWizardFile {
|
||||
QString source;
|
||||
QString target;
|
||||
};
|
||||
|
||||
struct CustomWizardParameters
|
||||
{
|
||||
public:
|
||||
CustomWizardParameters();
|
||||
void clear();
|
||||
bool parse(QIODevice &device, const QString &configFileFullPath,
|
||||
Core::BaseFileWizardParameters *bp, QString *errorMessage);
|
||||
bool parse(const QString &configFileFullPath,
|
||||
Core::BaseFileWizardParameters *bp, QString *errorMessage);
|
||||
|
||||
QString directory;
|
||||
QString klass;
|
||||
QList<CustomWizardFile> files;
|
||||
QString fieldPageTitle;
|
||||
QList<CustomWizardField> fields;
|
||||
int firstPageId;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug d, const CustomWizardField &);
|
||||
QDebug operator<<(QDebug d, const CustomWizardFile &);
|
||||
QDebug operator<<(QDebug d, const CustomWizardParameters &);
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#endif // CUSTOMPROJECTWIZARDPARAMETERS_H
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "pluginfilefactory.h"
|
||||
#include "processstep.h"
|
||||
#include "projectexplorerconstants.h"
|
||||
#include "customwizard.h"
|
||||
#include "projectfilewizardextension.h"
|
||||
#include "projecttreewidget.h"
|
||||
#include "projectwindow.h"
|
||||
@@ -902,6 +903,10 @@ void ProjectExplorerPlugin::extensionsInitialized()
|
||||
d->m_profileMimeTypes += pf->mimeTypes();
|
||||
addAutoReleasedObject(pf);
|
||||
}
|
||||
// Add custom wizards, for which other plugins might have registered
|
||||
// class factories
|
||||
foreach(Core::IWizard *cpw, ProjectExplorer::CustomWizard::createWizards())
|
||||
addAutoReleasedObject(cpw);
|
||||
}
|
||||
|
||||
void ProjectExplorerPlugin::shutdown()
|
||||
|
||||
@@ -6,6 +6,7 @@ include(../../qtcreatorplugin.pri)
|
||||
include(projectexplorer_dependencies.pri)
|
||||
include(../../shared/scriptwrapper/scriptwrapper.pri)
|
||||
include(../../libs/utils/utils.pri)
|
||||
include(customwizard/customwizard.pri)
|
||||
INCLUDEPATH += $$PWD/../../libs/utils
|
||||
HEADERS += projectexplorer.h \
|
||||
projectexplorer_export.h \
|
||||
|
||||
@@ -133,6 +133,8 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
|
||||
addAutoReleasedObject(new TestWizard);
|
||||
addAutoReleasedObject(new CustomWidgetWizard);
|
||||
|
||||
CustomQt4ProjectWizard::registerSelf();
|
||||
|
||||
addAutoReleasedObject(new QMakeStepFactory);
|
||||
addAutoReleasedObject(new MakeStepFactory);
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include <coreplugin/icore.h>
|
||||
#include <cpptools/cpptoolsconstants.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
@@ -103,6 +102,11 @@ QString QtWizard::profileSuffix()
|
||||
}
|
||||
|
||||
bool QtWizard::postGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage)
|
||||
{
|
||||
return QtWizard::qt4ProjectPostGenerateFiles(w, l, errorMessage);
|
||||
}
|
||||
|
||||
bool QtWizard::qt4ProjectPostGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage)
|
||||
{
|
||||
const QString proFileName = l.back().path();
|
||||
const BaseQt4ProjectWizardDialog *dialog = qobject_cast<const BaseQt4ProjectWizardDialog *>(w);
|
||||
@@ -144,6 +148,35 @@ bool QtWizard::showModulesPageForLibraries()
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------ CustomQt4ProjectWizard
|
||||
CustomQt4ProjectWizard::CustomQt4ProjectWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent) :
|
||||
ProjectExplorer::CustomProjectWizard(baseFileParameters, parent)
|
||||
{
|
||||
}
|
||||
|
||||
QWizard *CustomQt4ProjectWizard::createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const
|
||||
{
|
||||
BaseQt4ProjectWizardDialog *wizard = new BaseQt4ProjectWizardDialog(false, parent);
|
||||
initProjectWizardDialog(wizard, defaultPath, extensionPages);
|
||||
if (wizard->pageIds().contains(targetPageId))
|
||||
qWarning("CustomQt4ProjectWizard: Unable to insert target page at %d", int(targetPageId));
|
||||
wizard->addTargetsPage(QSet<QString>(), targetPageId);
|
||||
return wizard;
|
||||
}
|
||||
|
||||
bool CustomQt4ProjectWizard::postGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage)
|
||||
{
|
||||
return QtWizard::qt4ProjectPostGenerateFiles(w, l, errorMessage);
|
||||
}
|
||||
|
||||
void CustomQt4ProjectWizard::registerSelf()
|
||||
{
|
||||
ProjectExplorer::CustomWizard::registerFactory<CustomQt4ProjectWizard>(QLatin1String("qt4project"));
|
||||
}
|
||||
|
||||
// ----------------- BaseQt4ProjectWizardDialog
|
||||
BaseQt4ProjectWizardDialog::BaseQt4ProjectWizardDialog(bool showModulesPage, QWidget *parent) :
|
||||
ProjectExplorer::BaseProjectWizardDialog(parent),
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "qtprojectparameters.h"
|
||||
#include <projectexplorer/baseprojectwizarddialog.h>
|
||||
#include <projectexplorer/customwizard/customwizard.h>
|
||||
|
||||
#include <coreplugin/basefilewizard.h>
|
||||
|
||||
@@ -77,6 +78,8 @@ public:
|
||||
// Query CppTools settings for the class wizard settings
|
||||
static bool lowerCaseFiles();
|
||||
|
||||
static bool qt4ProjectPostGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage);
|
||||
|
||||
protected:
|
||||
static bool showModulesPageForApplications();
|
||||
static bool showModulesPageForLibraries();
|
||||
@@ -85,6 +88,25 @@ private:
|
||||
bool postGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage);
|
||||
};
|
||||
|
||||
// A custom wizard with an additional Qt 4 target page
|
||||
class CustomQt4ProjectWizard : public ProjectExplorer::CustomProjectWizard {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CustomQt4ProjectWizard(const Core::BaseFileWizardParameters& baseFileParameters,
|
||||
QObject *parent = 0);
|
||||
|
||||
virtual QWizard *createWizardDialog(QWidget *parent,
|
||||
const QString &defaultPath,
|
||||
const WizardPageList &extensionPages) const;
|
||||
static void registerSelf();
|
||||
|
||||
protected:
|
||||
virtual bool postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, QString *errorMessage);
|
||||
|
||||
private:
|
||||
enum { targetPageId = 2 };
|
||||
};
|
||||
|
||||
/* BaseQt4ProjectWizardDialog: Additionally offers modules page
|
||||
* and getter/setter for blank-delimited modules list, transparently
|
||||
* handling the visibility of the modules page list as well as a page
|
||||
@@ -93,13 +115,13 @@ private:
|
||||
|
||||
class BaseQt4ProjectWizardDialog : public ProjectExplorer::BaseProjectWizardDialog {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
explicit BaseQt4ProjectWizardDialog(bool showModulesPage, QWidget *parent = 0);
|
||||
explicit BaseQt4ProjectWizardDialog(bool showModulesPage,
|
||||
Utils::ProjectIntroPage *introPage,
|
||||
int introId = -1,
|
||||
QWidget *parent = 0);
|
||||
public:
|
||||
explicit BaseQt4ProjectWizardDialog(bool showModulesPage, QWidget *parent = 0);
|
||||
virtual ~BaseQt4ProjectWizardDialog();
|
||||
|
||||
int addModulesPage(int id = -1);
|
||||
@@ -107,7 +129,6 @@ protected:
|
||||
|
||||
static QSet<QString> desktopTarget();
|
||||
|
||||
public:
|
||||
QString selectedModules() const;
|
||||
void setSelectedModules(const QString &, bool lock = false);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user