diff --git a/share/qtcreator/qml-type-descriptions/qmlproject-types.xml b/share/qtcreator/qml-type-descriptions/qmlproject-types.xml index 0a7a68e03485ea08c52cbe8f3e7ef48048eafd60..192b45d6860fc78d221f92de25a55ae4b4ca1dfd 100644 --- a/share/qtcreator/qml-type-descriptions/qmlproject-types.xml +++ b/share/qtcreator/qml-type-descriptions/qmlproject-types.xml @@ -6,6 +6,7 @@ <export module="QmlProject" version="1.1" type="Project"/> </exports> <property name="sourceDirectory" type="string"/> + <property name="mainFile" type="string"/> <property name="importPaths" type="string" isList="true"/> <property name="content" type="QmlProjectItem" isList="true"/> </type> diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp index 8abc6eac7d60d5dbabe390cd974ebc3cd5109550..a0a7b275bb94c68b85b7d61bc516e1361b8642e3 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp @@ -11,6 +11,7 @@ public: QString sourceDirectory; QStringList importPaths; QStringList absoluteImportPaths; + QString mainFile; QList<QmlFileFilterItem*> qmlFileFilters() const; @@ -148,6 +149,21 @@ bool QmlProjectItem::matchesFile(const QString &filePath) const return false; } +QString QmlProjectItem::mainFile() const +{ + Q_D(const QmlProjectItem); + return d->mainFile; +} + +void QmlProjectItem::setMainFile(const QString &mainFilePath) +{ + Q_D(QmlProjectItem); + if (mainFilePath == d->mainFile) + return; + d->mainFile = mainFilePath; + emit mainFileChanged(); +} + } // namespace QmlProjectManager #include "qmlprojectitem.moc" diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index 32a2f1df53bb12241a386738dd53382157218b73..ff79f9aa781a631a4134d33daea5296841dc64bc 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -25,6 +25,7 @@ class QmlProjectItem : public QObject { Q_PROPERTY(QDeclarativeListProperty<QmlProjectManager::QmlProjectContentItem> content READ content DESIGNABLE false) Q_PROPERTY(QString sourceDirectory READ sourceDirectory NOTIFY sourceDirectoryChanged) Q_PROPERTY(QStringList importPaths READ importPaths WRITE setImportPaths NOTIFY importPathsChanged) + Q_PROPERTY(QString mainFile READ mainFile WRITE setMainFile NOTIFY mainFileChanged) Q_CLASSINFO("DefaultProperty", "content"); @@ -43,10 +44,15 @@ public: QStringList files() const; bool matchesFile(const QString &filePath) const; + QString mainFile() const; + void setMainFile(const QString &mainFilePath); + + signals: void qmlFilesChanged(const QSet<QString> &, const QSet<QString> &); void sourceDirectoryChanged(); void importPathsChanged(); + void mainFileChanged(); protected: QmlProjectItemPrivate *d_ptr; diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index bb43ea94fd70690f7771bb18fc21cc44360636ed..a6d89362bacc57bec923957bdfe0b12d5c6ce455 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -158,6 +158,13 @@ QStringList QmlProject::files() const return files; } +QString QmlProject::mainFile() const +{ + if (m_projectItem) + return m_projectItem.data()->mainFile(); + return QString(); +} + bool QmlProject::validProjectFile() const { return !m_projectItem.isNull(); diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 0f663eef18bb6b18d5858eaa18a2785e86f86b69..bbdd2ac5b08afa8569d670f0b58e5a6faf8c8df4 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -95,6 +95,7 @@ public: QDir projectDir() const; QStringList files() const; + QString mainFile() const; QStringList importPaths() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/qmlprojectmanager/qmlprojectapplicationwizard.cpp b/src/plugins/qmlprojectmanager/qmlprojectapplicationwizard.cpp index 6c5a072798beebcc28c17fd841bc522b8f022c7e..85cde496b848bb0cc87b9fbf3eddf69e84d8219c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectapplicationwizard.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectapplicationwizard.cpp @@ -31,6 +31,7 @@ #include "qmlprojectconstants.h" +#include <coreplugin/coreconstants.h> #include <projectexplorer/customwizard/customwizard.h> #include <qt4projectmanager/qt4projectmanagerconstants.h> @@ -39,6 +40,7 @@ #include <QtGui/QPainter> #include <QtGui/QPixmap> +#include <QtCore/QDir> #include <QtCore/QTextStream> #include <QtCore/QCoreApplication> @@ -141,12 +143,16 @@ Core::GeneratedFiles QmlProjectApplicationWizard::generateFiles(const QWizard *w out //: Comment added to generated .qmlproject file - << "/* " << tr("File generated by QtCreator", "qmlproject Template") << " */" << endl + << "/* " + << tr("File generated by QtCreator, version %1", + "qmlproject Template").arg(Core::Constants::IDE_VERSION_LONG) << " */" << endl << endl - << "import QmlProject 1.0" << endl + << "import QmlProject 1.1" << endl << endl << "Project {" << endl //: Comment added to generated .qmlproject file + << " mainFile: \"" << QDir(projectPath).relativeFilePath(mainFileName) << "\"" << endl + << endl << " /* " << tr("Include .qml, .js, and image files from current directory and subdirectories", "qmlproject Template") << " */" << endl << " QmlFiles {" << endl << " directory: \".\"" << endl diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 512014cb94156f9951a50c5acb667e5f5b37a21f..e953208d3b783adffbf31f61439fa0c950a8c0fd 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -50,7 +50,7 @@ using namespace QmlProjectManager::Internal; namespace QmlProjectManager { -const char * const M_CURRENT_FILE = "CurrentFile"; +const char * const M_CURRENT_FILE = "CurrentFile"; QmlProjectRunConfiguration::QmlProjectRunConfiguration(QmlProjectTarget *parent) : ProjectExplorer::RunConfiguration(parent, QLatin1String(Constants::QML_RC_ID)), @@ -67,12 +67,13 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(QmlProjectTarget *parent, QmlProjectRunConfiguration *source) : ProjectExplorer::RunConfiguration(parent, source), m_qtVersionId(source->m_qtVersionId), + m_scriptFile(source->m_scriptFile), m_qmlViewerArgs(source->m_qmlViewerArgs), m_projectTarget(parent), + m_usingCurrentFile(source->m_usingCurrentFile), m_userEnvironmentChanges(source->m_userEnvironmentChanges) { ctor(); - setMainScript(source->m_scriptFile); updateQtVersions(); } @@ -191,29 +192,57 @@ ProjectExplorer::OutputFormatter *QmlProjectRunConfiguration::createOutputFormat return new Qt4ProjectManager::QtOutputFormatter(qmlTarget()->qmlProject()); } +QmlProjectRunConfiguration::MainScriptSource QmlProjectRunConfiguration::mainScriptSource() const +{ + if (m_usingCurrentFile) { + return FileInEditor; + } + if (!m_mainScriptFilename.isEmpty()) { + return FileInSettings; + } + return FileInProjectFile; +} + +/** + Returns absolute path to main script file. + */ QString QmlProjectRunConfiguration::mainScript() const { - if (m_usingCurrentFile) + if (m_usingCurrentFile) { return m_currentFileFilename; + } + + if (!m_mainScriptFilename.isEmpty()) { + return m_mainScriptFilename; + } - return m_mainScriptFilename; + QString path = qmlTarget()->qmlProject()->mainFile(); + if (QFileInfo(path).isAbsolute()) { + return path; + } else { + return qmlTarget()->qmlProject()->projectDir().absoluteFilePath(path); + } } -void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile) +void QmlProjectRunConfiguration::setScriptSource(MainScriptSource source, + const QString &settingsPath) { - m_scriptFile = scriptFile; - // replace with locale-agnostic string - if (m_scriptFile == CURRENT_FILE) - m_scriptFile = M_CURRENT_FILE; - - if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) { + if (source == FileInEditor) { m_scriptFile.clear(); + m_mainScriptFilename.clear(); m_usingCurrentFile = true; - changeCurrentFile(Core::EditorManager::instance()->currentEditor()); - } else { + } else if (source == FileInProjectFile) { + m_scriptFile.clear(); + m_mainScriptFilename.clear(); + m_usingCurrentFile = false; + } else { // FileInSettings + m_scriptFile = settingsPath; + m_mainScriptFilename + = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(m_scriptFile); m_usingCurrentFile = false; - m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile); - updateEnabled(); } + updateEnabled(); + if (m_configurationWidget) + m_configurationWidget.data()->updateFileComboBox(); } Utils::Environment QmlProjectRunConfiguration::environment() const @@ -245,7 +274,13 @@ bool QmlProjectRunConfiguration::fromMap(const QVariantMap &map) updateQtVersions(); - setMainScript(m_scriptFile); + if (m_scriptFile == M_CURRENT_FILE) { + setScriptSource(FileInEditor); + } else if (m_scriptFile.isEmpty()) { + setScriptSource(FileInProjectFile); + } else { + setScriptSource(FileInSettings, m_scriptFile); + } return RunConfiguration::fromMap(map); } @@ -284,7 +319,7 @@ void QmlProjectRunConfiguration::updateEnabled() } } } else { // use default one - qmlFileFound = !m_mainScriptFilename.isEmpty(); + qmlFileFound = !mainScript().isEmpty(); } bool newValue = (QFileInfo(viewerPath()).exists() diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h index 75d60e677fbbb578ead5e060c88c6207d3217b97..b0a24930740e3747b7b6ee2ee8472347c88328b4 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h @@ -81,8 +81,15 @@ public: int qtVersionId() const; Qt4ProjectManager::QtVersion *qtVersion() const; + enum MainScriptSource { + FileInEditor, + FileInProjectFile, + FileInSettings + }; + MainScriptSource mainScriptSource() const; + void setScriptSource(MainScriptSource source, const QString &settingsPath = QString()); + QString mainScript() const; - void setMainScript(const QString &scriptFile); Utils::Environment environment() const; diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.cpp index 8a35caac25340a261fe6242ca4a7374aef8c8129..cb1eb2ad1092943a724eef9ea7b30c4d100c609b 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.cpp @@ -44,7 +44,7 @@ #include <QLineEdit> #include <QFormLayout> #include <QPushButton> -#include <QStringListModel> +#include <QStandardItemModel> using Core::ICore; using Utils::DebuggerLanguageChooser; @@ -57,7 +57,7 @@ QmlProjectRunConfigurationWidget::QmlProjectRunConfigurationWidget(QmlProjectRun m_runConfiguration(rc), m_qtVersionComboBox(0), m_fileListCombo(0), - m_fileListModel(new QStringListModel(this)) + m_fileListModel(new QStandardItemModel(this)) { QVBoxLayout *layout = new QVBoxLayout(this); @@ -76,7 +76,7 @@ QmlProjectRunConfigurationWidget::QmlProjectRunConfigurationWidget(QmlProjectRun m_fileListCombo = new QComboBox; m_fileListCombo->setModel(m_fileListModel); - connect(m_fileListCombo, SIGNAL(activated(QString)), this, SLOT(setMainScript(QString))); + connect(m_fileListCombo, SIGNAL(activated(int)), this, SLOT(setMainScript(int))); connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(fileListChanged()), SLOT(updateFileComboBox())); @@ -174,35 +174,73 @@ void QmlProjectRunConfigurationWidget::updateFileComboBox() { QmlProject *project = m_runConfiguration->qmlTarget()->qmlProject(); QDir projectDir = project->projectDir(); - QStringList files; - files.append(CURRENT_FILE); - int currentIndex = -1; + m_fileListModel->clear(); + m_fileListModel->appendRow(new QStandardItem(CURRENT_FILE)); + QModelIndex currentIndex; + QModelIndex fileInQmlProjectIndex; + + const QString mainScriptInFilePath = projectDir.absoluteFilePath(project->mainFile()); + QStringList sortedFiles = project->files(); + if (!sortedFiles.contains(mainScriptInFilePath)) + sortedFiles += mainScriptInFilePath; + + // make paths relative to project directory + QStringList relativeFiles; + foreach (const QString &fn, sortedFiles) { + relativeFiles += projectDir.relativeFilePath(fn); + } + sortedFiles = relativeFiles; + qStableSort(sortedFiles.begin(), sortedFiles.end(), caseInsensitiveLessThan); + QString mainScriptPath; + if (m_runConfiguration->mainScriptSource() != QmlProjectRunConfiguration::FileInEditor) + mainScriptPath = projectDir.relativeFilePath(m_runConfiguration->mainScript()); + foreach (const QString &fn, sortedFiles) { QFileInfo fileInfo(fn); if (fileInfo.suffix() != QLatin1String("qml")) continue; - QString fileName = projectDir.relativeFilePath(fn); - if (fileName == m_runConfiguration->m_scriptFile) - currentIndex = files.size(); + QStandardItem *item = new QStandardItem(fn); + m_fileListModel->appendRow(item); - files.append(fileName); + if (mainScriptPath == fn) + currentIndex = item->index(); + + if (mainScriptInFilePath == fn) + fileInQmlProjectIndex = item->index(); } - m_fileListModel->setStringList(files); - if (currentIndex != -1) - m_fileListCombo->setCurrentIndex(currentIndex); - else + if (currentIndex.isValid()) { + m_fileListCombo->setCurrentIndex(currentIndex.row()); + } else { m_fileListCombo->setCurrentIndex(0); + } + + if (fileInQmlProjectIndex.isValid()) { + QFont font; + font.setBold(true); + m_fileListModel->setData(fileInQmlProjectIndex, font, Qt::FontRole); + } } -void QmlProjectRunConfigurationWidget::setMainScript(const QString &file) +void QmlProjectRunConfigurationWidget::setMainScript(int index) { - m_runConfiguration->setMainScript(file); + QmlProject *project = m_runConfiguration->qmlTarget()->qmlProject(); + QDir projectDir = project->projectDir(); + if (index == 0) { + m_runConfiguration->setScriptSource(QmlProjectRunConfiguration::FileInEditor); + } else { + const QString path = m_fileListModel->data(m_fileListModel->index(index, 0)).toString(); + if (projectDir.relativeFilePath(project->mainFile()) == path) { + m_runConfiguration->setScriptSource(QmlProjectRunConfiguration::FileInProjectFile); + } else { + m_runConfiguration->setScriptSource(QmlProjectRunConfiguration::FileInSettings, path); + } + } } void QmlProjectRunConfigurationWidget::onQtVersionSelectionChanged() diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.h b/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.h index e043eedb6859f538ed6028e9e587bf4cdace4438..7f981b45452e0a4c82396898b495c09247012454 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.h +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfigurationwidget.h @@ -33,7 +33,7 @@ #include <QWidget> QT_FORWARD_DECLARE_CLASS(QComboBox); -QT_FORWARD_DECLARE_CLASS(QStringListModel); +QT_FORWARD_DECLARE_CLASS(QStandardItemModel); namespace ProjectExplorer { @@ -58,11 +58,11 @@ public: public slots: void updateQtVersionComboBox(); void userEnvironmentChangesChanged(); + void updateFileComboBox(); private slots: - void updateFileComboBox(); - void setMainScript(const QString &file); + void setMainScript(int index); void onQtVersionSelectionChanged(); void onViewerArgsChanged(); void useCppDebuggerToggled(bool toggled); @@ -78,7 +78,7 @@ private: QComboBox *m_qtVersionComboBox; QComboBox *m_fileListCombo; - QStringListModel *m_fileListModel; + QStandardItemModel *m_fileListModel; ProjectExplorer::EnvironmentWidget *m_environmentWidget; }; diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp index 376395ea2890768cbadd3ad1812cea4d4407b54c..26df3cf7b54ac65b58140e0dc805ba2219a6e8cb 100644 --- a/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp +++ b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp @@ -20,6 +20,7 @@ private slots: void testFileFilter(); void testMatchesFile(); void testLibraryPaths(); + void testMainFile(); }; tst_FileFormat::tst_FileFormat() @@ -334,6 +335,31 @@ void tst_FileFormat::testLibraryPaths() } } +void tst_FileFormat::testMainFile() +{ + // + // search for qml files in local directory + // + QString projectFile = QLatin1String( + "import QmlProject 1.1\n" + "Project {\n" + " mainFile: \"file1.qml\"\n" + "}\n"); + + { + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData(projectFile.toUtf8(), QUrl()); + if (!component.isReady()) + qDebug() << component.errorString(); + QVERIFY(component.isReady()); + + QmlProjectItem *project = qobject_cast<QmlProjectItem*>(component.create()); + QVERIFY(project); + + QCOMPARE(project->mainFile(), QString("file1.qml")); + } +} QTEST_MAIN(tst_FileFormat); #include "tst_fileformat.moc"