QmlProject: Add mainFile property

The mainFile property of QmlProject is the default file to run. People
have still the opportunity to override this in their run settings,
though.

The wizard generated code was updated accordingly. Note that this makes
projects generated by the wizard incompatible with QtCreator 2.1!

Task-number: QTCREATORBUG-3249
This commit is contained in:
Kai Koehne
2010-12-03 17:04:29 +01:00
parent efcac96f57
commit c4e4913870
11 changed files with 189 additions and 46 deletions
@@ -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>
@@ -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"
@@ -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;
@@ -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();
@@ -95,6 +95,7 @@ public:
QDir projectDir() const;
QStringList files() const;
QString mainFile() const;
QStringList importPaths() const;
bool addFiles(const QStringList &filePaths);
@@ -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
@@ -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());
}
QString QmlProjectRunConfiguration::mainScript() const
QmlProjectRunConfiguration::MainScriptSource QmlProjectRunConfiguration::mainScriptSource() const
{
if (m_usingCurrentFile)
return m_currentFileFilename;
return m_mainScriptFilename;
if (m_usingCurrentFile) {
return FileInEditor;
}
if (!m_mainScriptFilename.isEmpty()) {
return FileInSettings;
}
return FileInProjectFile;
}
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
/**
Returns absolute path to main script file.
*/
QString QmlProjectRunConfiguration::mainScript() const
{
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) {
m_usingCurrentFile = true;
changeCurrentFile(Core::EditorManager::instance()->currentEditor());
} else {
m_usingCurrentFile = false;
m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
updateEnabled();
if (m_usingCurrentFile) {
return m_currentFileFilename;
}
if (!m_mainScriptFilename.isEmpty()) {
return m_mainScriptFilename;
}
QString path = qmlTarget()->qmlProject()->mainFile();
if (QFileInfo(path).isAbsolute()) {
return path;
} else {
return qmlTarget()->qmlProject()->projectDir().absoluteFilePath(path);
}
}
void QmlProjectRunConfiguration::setScriptSource(MainScriptSource source,
const QString &settingsPath)
{
if (source == FileInEditor) { m_scriptFile.clear();
m_mainScriptFilename.clear();
m_usingCurrentFile = true;
} 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;
}
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()
@@ -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;
@@ -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()
@@ -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();
private slots:
void updateFileComboBox();
void setMainScript(const QString &file);
private slots:
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;
};
@@ -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"