diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp index ffb7f173216..eca12dc55f7 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,6 +63,7 @@ class Operation: public QmlJSQuickFixOperation QString m_idName, m_componentName; SourceLocation m_firstSourceLocation; SourceLocation m_lastSourceLocation; + UiObjectInitializer *m_initializer; public: void init() { @@ -78,7 +81,8 @@ public: : QmlJSQuickFixOperation(interface, 0), m_idName(idOfObject(objDef)), m_firstSourceLocation(objDef->firstSourceLocation()), - m_lastSourceLocation(objDef->lastSourceLocation()) + m_lastSourceLocation(objDef->lastSourceLocation()), + m_initializer(objDef->initializer) { init(); } @@ -88,7 +92,8 @@ public: : QmlJSQuickFixOperation(interface, 0), m_idName(idOfObject(objDef)), m_firstSourceLocation(objDef->qualifiedTypeNameId->firstSourceLocation()), - m_lastSourceLocation(objDef->lastSourceLocation()) + m_lastSourceLocation(objDef->lastSourceLocation()), + m_initializer(objDef->initializer) { init(); } @@ -98,8 +103,33 @@ public: { QString componentName = m_componentName; QString path = QFileInfo(fileName()).path(); - bool confirm = ComponentNameDialog::go(&componentName, &path, Core::ICore::dialogParent()); + QmlJS::PropertyReader propertyReader(currentFile->qmljsDocument(), m_initializer); + QStringList result; + QStringList sourcePreview; + + if (!m_idName.isEmpty()) + sourcePreview.append(QLatin1String(" id: ") + m_idName); + else + sourcePreview.append(QString()); + + QStringList sortedPropertiesWithoutId; + + foreach (const QString &property, propertyReader.properties()) + if (property != QLatin1String("id")) + sortedPropertiesWithoutId.append(property); + + sortedPropertiesWithoutId.sort(); + + foreach (const QString &property, sortedPropertiesWithoutId) + sourcePreview.append(QLatin1String(" ") + property + QLatin1String(": ") + propertyReader.readAstValue(property)); + + bool confirm = ComponentNameDialog::go(&componentName, &path, + sortedPropertiesWithoutId, + sourcePreview, + QFileInfo(fileName()).fileName(), + &result, + Core::ICore::dialogParent()); if (!confirm) return; @@ -112,18 +142,44 @@ public: QString imports; UiProgram *prog = currentFile->qmljsDocument()->qmlProgram(); if (prog && prog->headers) { - const int start = currentFile->startOf(prog->headers->firstSourceLocation()); - const int end = currentFile->startOf(prog->members->member->firstSourceLocation()); + const unsigned int start = currentFile->startOf(prog->headers->firstSourceLocation()); + const unsigned int end = currentFile->startOf(prog->members->member->firstSourceLocation()); imports = currentFile->textOf(start, end); } - const int start = currentFile->startOf(m_firstSourceLocation); - const int end = currentFile->startOf(m_lastSourceLocation); - const QString txt = imports + currentFile->textOf(start, end) + const unsigned int start = currentFile->startOf(m_firstSourceLocation); + const unsigned int end = currentFile->startOf(m_lastSourceLocation); + QString newComponentSource = imports + currentFile->textOf(start, end) + QLatin1String("}\n"); + //Remove properties from resulting code... + + Utils::ChangeSet changeSet; + QmlJS::Rewriter rewriter(newComponentSource, &changeSet, QStringList()); + + QmlJS::Dialect dialect = QmlJS::Dialect::Qml; + + QmlJS::Document::MutablePtr doc = QmlJS::Document::create(newFileName, dialect); + doc->setSource(newComponentSource); + doc->parseQml(); + + if (doc->isParsedCorrectly()) { + + UiObjectMember *astRootNode = 0; + if (UiProgram *program = doc->qmlProgram()) + if (program->members) + astRootNode = program->members->member; + + foreach (const QString &property, result) + rewriter.removeBindingByName(initializerOfObject(astRootNode), property); + } else { + qWarning() << Q_FUNC_INFO << "parsing failed:" << newComponentSource; + } + + changeSet.apply(&newComponentSource); + // stop if we can't create the new file - if (!refactoring.createFile(newFileName, txt)) + if (!refactoring.createFile(newFileName, newComponentSource)) return; if (path == QFileInfo(fileName()).path()) { @@ -151,10 +207,14 @@ public: Core::VcsManager::msgToAddToVcsFailed(QStringList(newFileName), versionControl)); } } + QString replacement = componentName + QLatin1String(" {\n"); if (!m_idName.isEmpty()) replacement += QLatin1String("id: ") + m_idName + QLatin1Char('\n'); + foreach (const QString &property, result) + replacement += property + QLatin1String(": ") + propertyReader.readAstValue(property) + QLatin1Char('\n'); + Utils::ChangeSet changes; changes.replace(start, end, replacement); currentFile->setChangeSet(changes); @@ -174,6 +234,7 @@ void ComponentFromObjectDef::match(const QmlJSQuickFixInterface &interface, Quic for (int i = path.size() - 1; i >= 0; --i) { Node *node = path.at(i); if (UiObjectDefinition *objDef = cast(node)) { + if (!interface->currentFile()->isCursorOn(objDef->qualifiedTypeNameId)) return; // check that the node is not the root node diff --git a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp index d45b340d9aa..3f9ce30019a 100644 --- a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp +++ b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp @@ -51,6 +51,10 @@ ComponentNameDialog::~ComponentNameDialog() bool ComponentNameDialog::go(QString *proposedName, QString *proposedPath, + const QStringList &properties, + const QStringList &sourcePreview, + const QString &oldFileName, + QStringList *result, QWidget *parent) { Q_ASSERT(proposedName); @@ -60,20 +64,81 @@ bool ComponentNameDialog::go(QString *proposedName, d.ui->componentNameEdit->setNamespacesEnabled(false); d.ui->componentNameEdit->setLowerCaseFileName(false); d.ui->componentNameEdit->setForceFirstCapitalLetter(true); + if (proposedName->isEmpty()) + *proposedName = QLatin1String("MyComponent"); d.ui->componentNameEdit->setText(*proposedName); d.ui->pathEdit->setExpectedKind(Utils::PathChooser::ExistingDirectory); d.ui->pathEdit->setHistoryCompleter(QLatin1String("QmlJs.Component.History")); d.ui->pathEdit->setPath(*proposedPath); + d.ui->label->setText(tr("Property assignments for %1:").arg(oldFileName)); + d.m_sourcePreview = sourcePreview; + + d.setProperties(properties); + + d.generateCodePreview(); + + d.connect(d.ui->listWidget, &QListWidget::itemChanged, &d, &ComponentNameDialog::generateCodePreview); + d.connect(d.ui->componentNameEdit, &QLineEdit::textChanged, &d, &ComponentNameDialog::generateCodePreview); if (QDialog::Accepted == d.exec()) { *proposedName = d.ui->componentNameEdit->text(); *proposedPath = d.ui->pathEdit->path(); + + if (result) + *result = d.propertiesToKeep(); return true; } return false; } +void ComponentNameDialog::setProperties(const QStringList &properties) +{ + ui->listWidget->addItems(properties); + + for (int i = 0; i < ui->listWidget->count(); ++i) { + QListWidgetItem *item = ui->listWidget->item(i); + item->setFlags(Qt::ItemIsUserCheckable | Qt:: ItemIsEnabled); + if (item->text() == QLatin1String("x") + || item->text() == QLatin1String("y")) + ui->listWidget->item(i)->setCheckState(Qt::Checked); + else + ui->listWidget->item(i)->setCheckState(Qt::Unchecked); + } +} + +QStringList ComponentNameDialog::propertiesToKeep() const +{ + QStringList result; + for (int i = 0; i < ui->listWidget->count(); ++i) { + QListWidgetItem *item = ui->listWidget->item(i); + + if (item->checkState() == Qt::Checked) + result.append(item->text()); + } + + return result; +} + +void ComponentNameDialog::generateCodePreview() +{ + const QString componentName = ui->componentNameEdit->text(); + + ui->plainTextEdit->clear(); + ui->plainTextEdit->appendPlainText(componentName + QLatin1String(" {")); + if (!m_sourcePreview.first().isEmpty()) + ui->plainTextEdit->appendPlainText(m_sourcePreview.first()); + + for (int i = 0; i < ui->listWidget->count(); ++i) { + QListWidgetItem *item = ui->listWidget->item(i); + + if (item->checkState() == Qt::Checked) + ui->plainTextEdit->appendPlainText(m_sourcePreview.at(i + 1)); + } + + ui->plainTextEdit->appendPlainText(QLatin1String("}")); +} + void ComponentNameDialog::choosePath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Choose a path"), diff --git a/src/plugins/qmljseditor/qmljscomponentnamedialog.h b/src/plugins/qmljseditor/qmljscomponentnamedialog.h index b7c5a7335f1..45309142361 100644 --- a/src/plugins/qmljseditor/qmljscomponentnamedialog.h +++ b/src/plugins/qmljseditor/qmljscomponentnamedialog.h @@ -40,7 +40,16 @@ public: explicit ComponentNameDialog(QWidget *parent = 0); ~ComponentNameDialog(); - static bool go(QString *proposedName, QString *proposedPath, QWidget *parent = 0); + static bool go(QString *proposedName, QString *proposedPath, + const QStringList &properties, const QStringList &sourcePreview, const QString &oldFileName, + QStringList *result, + QWidget *parent = 0); + + void setProperties(const QStringList &properties); + + QStringList propertiesToKeep() const; + + void generateCodePreview(); public slots: void choosePath(); @@ -51,6 +60,7 @@ protected: private: Ui::ComponentNameDialog *ui; + QStringList m_sourcePreview; }; } // namespace Internal diff --git a/src/plugins/qmljseditor/qmljscomponentnamedialog.ui b/src/plugins/qmljseditor/qmljscomponentnamedialog.ui index 1f70caf25ed..17ff4b9b973 100644 --- a/src/plugins/qmljseditor/qmljscomponentnamedialog.ui +++ b/src/plugins/qmljseditor/qmljscomponentnamedialog.ui @@ -7,67 +7,50 @@ 0 0 495 - 138 + 311 Move Component into Separate File - - - 0 - - - - - 8 + + + + + Property assignments for - - 10 + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - - - - - Path: - - - - - - - Component name: - - - - - - - + - - + + + + + 0 + 0 + + + + + + + + + Qt::Vertical - 0 - 0 + 20 + 40 - + Qt::Horizontal @@ -77,6 +60,41 @@ + + + + + + Component name: + + + + + + + Component Name + + + + + + + + + + + + + + Path: + + + + + + + +