Commit 516116c5 authored by Sergey Shambir's avatar Sergey Shambir

PythonEditor: added class wizard

Contains SourceGenerator class which was also used to generate app
template in PythonProjectManager; it saved for future use.

Change-Id: I3d44e6d33a3beabc73030acdd6740edf1745e485
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent ecacaab7
......@@ -18,6 +18,10 @@ HEADERS += \
pythoneditorwidget.h \
pythoneditorconstants.h \
wizard/pythonfilewizard.h \
wizard/pythonclasswizard.h \
wizard/pythonclassnamepage.h \
wizard/pythonclasswizarddialog.h \
wizard/pythonsourcegenerator.h \
tools/pythonhighlighter.h \
tools/pythonindenter.h \
tools/lexical/pythonformattoken.h \
......@@ -30,6 +34,10 @@ SOURCES += \
pythoneditor.cpp \
pythoneditorwidget.cpp \
wizard/pythonfilewizard.cpp \
wizard/pythonclasswizarddialog.cpp \
wizard/pythonclasswizard.cpp \
wizard/pythonclassnamepage.cpp \
wizard/pythonsourcegenerator.cpp \
tools/pythonhighlighter.cpp \
tools/pythonindenter.cpp \
tools/lexical/pythonscanner.cpp
......@@ -37,6 +37,14 @@ QtcPlugin {
"tools/pythonindenter.h",
"wizard/pythonfilewizard.h",
"wizard/pythonfilewizard.cpp",
"wizard/pythonclasswizard.h",
"wizard/pythonclassnamepage.h",
"wizard/pythonclasswizarddialog.h",
"wizard/pythonsourcegenerator.h",
"wizard/pythonclasswizarddialog.cpp",
"wizard/pythonclasswizard.cpp",
"wizard/pythonclassnamepage.cpp",
"wizard/pythonsourcegenerator.cpp"
]
}
......@@ -2,4 +2,6 @@ QTC_PLUGIN_NAME = PythonEditor
QTC_PLUGIN_DEPENDS += \
coreplugin \
texteditor \
cpptools
cpptools \
qtsupport \
projectexplorer
......@@ -30,6 +30,7 @@
#include "pythoneditorplugin.h"
#include "pythoneditorconstants.h"
#include "wizard/pythonfilewizard.h"
#include "wizard/pythonclasswizard.h"
#include "pythoneditorwidget.h"
#include "pythoneditorfactory.h"
......@@ -249,6 +250,7 @@ bool PythonEditorPlugin::initialize(
// Add Python files and classes creation dialogs
////////////////////////////////////////////////////////////////////////////
addAutoReleasedObject(new FileWizard(Core::ICore::instance()));
addAutoReleasedObject(new ClassWizard(Core::ICore::instance()));
return true;
}
......
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pythonclassnamepage.h"
#include "../pythoneditorconstants.h"
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <utils/newclasswidget.h>
#include <QVBoxLayout>
namespace PythonEditor {
ClassNamePage::ClassNamePage(QWidget *parent)
: QWizardPage(parent)
, m_isValid(false)
{
setTitle(tr("Enter Class Name"));
setSubTitle(tr("The source file name will be derived from the class name"));
m_newClassWidget.reset(new Utils::NewClassWidget);
// Order, set extensions first before suggested name is derived
m_newClassWidget->setClassTypeComboVisible(true);
m_newClassWidget->setBaseClassChoices(QStringList()
<< QString()
<< QLatin1String("QObject")
<< QLatin1String("QWidget")
<< QLatin1String("QMainWindow")
<< QLatin1String("QDeclarativeItem"));
m_newClassWidget->setBaseClassEditable(true);
m_newClassWidget->setFormInputVisible(false);
m_newClassWidget->setHeaderInputVisible(false);
m_newClassWidget->setNamespacesEnabled(true);
m_newClassWidget->setBaseClassInputVisible(true);
m_newClassWidget->setNamesDelimiter(QLatin1String("."));
m_newClassWidget->setAllowDirectories(true);
connect(m_newClassWidget.data(), SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
QVBoxLayout *pageLayout = new QVBoxLayout(this);
pageLayout->addWidget(m_newClassWidget.data());
QSpacerItem *vSpacer = new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding);
pageLayout->addItem(vSpacer);
initParameters();
}
ClassNamePage::~ClassNamePage()
{
}
void ClassNamePage::initParameters()
{
m_newClassWidget->setSourceExtension(QLatin1String(Constants::C_PY_EXTENSION));
}
void ClassNamePage::slotValidChanged()
{
const bool validNow = m_newClassWidget->isValid();
if (m_isValid != validNow) {
m_isValid = validNow;
emit completeChanged();
}
}
} // namespace PythonEditor
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef PYTHONEDITOR_CLASSNAMEPAGE_H
#define PYTHONEDITOR_CLASSNAMEPAGE_H
#include <QWizardPage>
#include <QScopedPointer>
namespace Utils { class NewClassWidget; }
namespace PythonEditor {
class ClassNamePage : public QWizardPage
{
Q_OBJECT
public:
explicit ClassNamePage(QWidget *parent = 0);
virtual ~ClassNamePage();
bool isComplete() const { return m_isValid; }
Utils::NewClassWidget *newClassWidget() const { return m_newClassWidget.data(); }
private slots:
void slotValidChanged();
private:
void initParameters();
QScopedPointer<Utils::NewClassWidget> m_newClassWidget;
bool m_isValid;
};
} // namespace PythonEditor
#endif // PYTHONEDITOR_CLASSNAMEPAGE_H
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pythonclasswizard.h"
#include "pythonclasswizarddialog.h"
#include "pythonclassnamepage.h"
#include "pythonsourcegenerator.h"
#include "../pythoneditorconstants.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/baseqtversion.h>
using namespace ProjectExplorer;
namespace PythonEditor {
static Core::BaseFileWizardParameters getDefaultParams()
{
Core::BaseFileWizardParameters p(Core::IWizard::FileWizard);
p.setId(QLatin1String(Constants::C_PY_CLASS_WIZARD_ID));
p.setCategory(QLatin1String(Constants::C_PY_WIZARD_CATEGORY));
p.setDisplayCategory(QLatin1String(Constants::C_PY_DISPLAY_CATEGORY));
p.setDisplayName(ClassWizard::tr(Constants::EN_PY_CLASS_DISPLAY_NAME));
p.setDescription(ClassWizard::tr(Constants::EN_PY_CLASS_DESCRIPTION));
return p;
}
ClassWizard::ClassWizard(QObject *parent) :
Core::BaseFileWizard(getDefaultParams(), parent)
{
}
QWizard *ClassWizard::createWizardDialog(
QWidget *parent,
const Core::WizardDialogParameters &params) const
{
ClassWizardDialog *wizard = new ClassWizardDialog(parent);
foreach (QWizardPage *p, params.extensionPages())
BaseFileWizard::applyExtensionPageShortTitle(wizard, wizard->addPage(p));
wizard->setPath(params.defaultPath());
wizard->setExtraValues(params.extraValues());
return wizard;
}
Core::GeneratedFiles ClassWizard::generateFiles(const QWizard *w,
QString *errorMessage) const
{
Q_UNUSED(errorMessage);
const ClassWizardDialog *wizard = qobject_cast<const ClassWizardDialog *>(w);
const ClassWizardParameters params = wizard->parameters();
const QString fileName = Core::BaseFileWizard::buildFileName(
params.path, params.fileName, QLatin1String(Constants::C_PY_EXTENSION));
Core::GeneratedFile sourceFile(fileName);
SourceGenerator generator;
generator.setPythonQtBinding(SourceGenerator::PySide);
Kit *kit = kitForWizard(wizard);
if (kit) {
QtSupport::BaseQtVersion *baseVersion = QtSupport::QtKitInformation::qtVersion(kit);
if (baseVersion && baseVersion->qtVersion().majorVersion == 5)
generator.setPythonQtVersion(SourceGenerator::Qt5);
else
generator.setPythonQtVersion(SourceGenerator::Qt4);
}
QString sourceContent = generator.generateClass(
params.className, params.baseClass, params.classType
);
sourceFile.setContents(sourceContent);
sourceFile.setAttributes(Core::GeneratedFile::OpenEditorAttribute);
return Core::GeneratedFiles() << sourceFile;
}
Kit *ClassWizard::kitForWizard(const ClassWizardDialog *wizard) const
{
const QString key = QLatin1String(ProjectExplorer::Constants::PREFERED_PROJECT_NODE);
const QString nodePath = wizard->extraValues().value(key).toString();
// projectForFile doesn't find project if project file path passed
Node *node = ProjectExplorerPlugin::instance()->session()->nodeForFile(nodePath);
Project *proj = ProjectExplorerPlugin::instance()->session()->projectForNode(node);
if (proj && proj->activeTarget())
return proj->activeTarget()->kit();
return KitManager::instance()->defaultKit();
}
} // namespace PythonEditor
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef PYTHONEDITOR_CLASSWIZARD_H
#define PYTHONEDITOR_CLASSWIZARD_H
#include <coreplugin/basefilewizard.h>
#include <utils/wizard.h>
namespace Utils { class NewClassWidget; }
namespace ProjectExplorer { class Kit; }
namespace PythonEditor {
class ClassWizardDialog;
class ClassWizard : public Core::BaseFileWizard
{
Q_OBJECT
public:
explicit ClassWizard(QObject *parent = 0);
protected:
QWizard *createWizardDialog(QWidget *parent,
const Core::WizardDialogParameters &params) const;
Core::GeneratedFiles generateFiles(const QWizard *w,
QString *errorMessage) const;
ProjectExplorer::Kit *kitForWizard(const ClassWizardDialog *wizard) const;
};
} // namespace PythonEditor
#endif // PYTHONEDITOR_CLASSWIZARD_H
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pythonclasswizarddialog.h"
#include "pythonclassnamepage.h"
#include <utils/newclasswidget.h>
#include <coreplugin/basefilewizard.h>
namespace PythonEditor {
ClassWizardDialog::ClassWizardDialog(QWidget *parent)
: Utils::Wizard(parent)
, m_classNamePage(new ClassNamePage(this))
{
setWindowTitle(tr("Python Class Wizard"));
Core::BaseFileWizard::setupWizard(this);
const int classNameId = addPage(m_classNamePage.data());
wizardProgress()->item(classNameId)->setTitle(tr("Details"));
}
ClassWizardDialog::~ClassWizardDialog()
{
}
ClassWizardParameters ClassWizardDialog::parameters() const
{
ClassWizardParameters p;
const Utils::NewClassWidget *ncw = m_classNamePage->newClassWidget();
p.className = ncw->className();
p.fileName = ncw->sourceFileName();
p.baseClass = ncw->baseClassName();
p.path = ncw->path();
p.classType = ncw->classType();
return p;
}
void ClassWizardDialog::setExtraValues(const QVariantMap &extraValues)
{
m_extraValues = extraValues;
}
const QVariantMap &ClassWizardDialog::extraValues() const
{
return m_extraValues;
}
void ClassWizardDialog::setPath(const QString &path)
{
m_classNamePage->newClassWidget()->setPath(path);
}
} // namespace PythonEditor
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef PYTHONEDITOR_CLASSWIZARDDIALOG_H
#define PYTHONEDITOR_CLASSWIZARDDIALOG_H
#include <utils/wizard.h>
#include <utils/newclasswidget.h>
#include <QScopedPointer>
#include <QVariantMap>
namespace PythonEditor {
class ClassNamePage;
class ClassWizardParameters
{
public:
QString className;
QString fileName;
QString path;
QString baseClass;
Utils::NewClassWidget::ClassType classType;
};
class ClassWizardDialog : public Utils::Wizard
{
Q_OBJECT
public:
explicit ClassWizardDialog(QWidget *parent = 0);
virtual ~ClassWizardDialog();
void setPath(const QString &path);
ClassWizardParameters parameters() const;
void setExtraValues(const QVariantMap &extraValues);
const QVariantMap &extraValues() const;
private:
QScopedPointer<ClassNamePage> m_classNamePage;
QVariantMap m_extraValues;
};
} // namespace PythonEditor
#endif // PYTHONEDITOR_CLASSWIZARDDIALOG_H
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pythonsourcegenerator.h"
#include <QSet>
namespace PythonEditor {
static const char BASH_RUN_HEADER[] = "#!/usr/bin/env python\n";
static const char ENCODING_HEADER[] = "# -*- coding: utf-8 -*-\n";
SourceGenerator::SourceGenerator()
: m_pythonQtBinding(PySide)
, m_pythonQtVersion(Qt4)
{
}
SourceGenerator::~SourceGenerator()
{
}
void SourceGenerator::setPythonQtBinding(QtBinding binding)
{
m_pythonQtBinding = binding;
}
void SourceGenerator::setPythonQtVersion(SourceGenerator::QtVersion version)
{
m_pythonQtVersion = version;
}
QString SourceGenerator::generateClass(const QString &className,
const QString &baseClass,
Utils::NewClassWidget::ClassType classType) const
{
QSet<QString> modules;
bool hasUserBaseClass = !baseClass.isEmpty();
// heuristic
bool wasInheritedFromQt = hasUserBaseClass && (baseClass.at(0) == QLatin1Char('Q'));
QString actualBase = baseClass;
switch (classType) {
case Utils::NewClassWidget::NoClassType:
break;
case Utils::NewClassWidget::SharedDataClass:
case Utils::NewClassWidget::ClassInheritsQQuickItem:
break;
case Utils::NewClassWidget::ClassInheritsQObject:
wasInheritedFromQt = true;
modules.insert(QLatin1String("QtCore"));
if (!hasUserBaseClass)
actualBase = QLatin1String("QtCore.QObject");
break;
case Utils::NewClassWidget::ClassInheritsQWidget:
wasInheritedFromQt = true;
modules.insert(QLatin1String("QtCore"));
modules.insert(moduleForQWidget());
if (!hasUserBaseClass)
actualBase = moduleForQWidget() + QLatin1String(".QWidget");
break;
case Utils::NewClassWidget::ClassInheritsQDeclarativeItem:
wasInheritedFromQt = true;
modules.insert(QLatin1String("QtCore"));
modules.insert(QLatin1String("QtDeclarative"));
if (!hasUserBaseClass)
actualBase = QLatin1String("QtDeclarative.QDeclarativeItem");
break;
}
QString nonQtModule; // empty
if (hasUserBaseClass) {
int dotIndex = baseClass.lastIndexOf(QLatin1Char('.'));
if (dotIndex != -1) {
if (wasInheritedFromQt)
modules.insert(baseClass.left(dotIndex));