genericproject.cpp 16.6 KB
Newer Older
Roberto Raggi's avatar
Roberto Raggi committed
1 2 3 4 5 6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
Roberto Raggi's avatar
Roberto Raggi committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
**
** 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
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
Roberto Raggi's avatar
Roberto Raggi committed
27 28 29 30
**
**************************************************************************/

#include "genericproject.h"
Tobias Hunger's avatar
Tobias Hunger committed
31

dt's avatar
dt committed
32
#include "genericbuildconfiguration.h"
Tobias Hunger's avatar
Tobias Hunger committed
33 34
#include "genericprojectconstants.h"
#include "generictarget.h"
Roberto Raggi's avatar
Roberto Raggi committed
35

36
#include <projectexplorer/toolchain.h>
Roberto Raggi's avatar
Roberto Raggi committed
37
#include <projectexplorer/projectexplorerconstants.h>
38
#include <projectexplorer/persistentsettings.h>
Roberto Raggi's avatar
Roberto Raggi committed
39 40
#include <cpptools/cppmodelmanagerinterface.h>
#include <extensionsystem/pluginmanager.h>
41
#include <utils/pathchooser.h>
Roberto Raggi's avatar
Roberto Raggi committed
42 43 44
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>

45 46 47 48
#include <QtCore/QtDebug>
#include <QtCore/QDir>
#include <QtCore/QSettings>
#include <QtCore/QProcess>
49
#include <QtCore/QCoreApplication>
Roberto Raggi's avatar
Roberto Raggi committed
50

51 52
#include <QtGui/QFormLayout>
#include <QtGui/QMainWindow>
53
#include <QtGui/QInputDialog>
54
#include <QtGui/QComboBox>
55 56
#include <QtGui/QStringListModel>
#include <QtGui/QListWidget>
57
#include <QtGui/QPushButton>
Roberto Raggi's avatar
Roberto Raggi committed
58 59 60

using namespace GenericProjectManager;
using namespace GenericProjectManager::Internal;
61
using namespace ProjectExplorer;
Roberto Raggi's avatar
Roberto Raggi committed
62

63
namespace {
64
const char * const TOOLCHAIN_KEY("GenericProjectManager.GenericProject.Toolchain");
65

66 67 68 69
/**
 * An editable string list model. New strings can be added by editing the entry
 * called "<new>", displayed at the end.
 */
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
class ListModel: public QStringListModel
{
public:
    ListModel(QObject *parent)
        : QStringListModel(parent) {}

    virtual ~ListModel() {}

    virtual int rowCount(const QModelIndex &parent) const
    { return 1 + QStringListModel::rowCount(parent); }

    virtual Qt::ItemFlags flags(const QModelIndex &index) const
    { return QStringListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; }

    virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
    {
        if (row == stringList().size())
            return createIndex(row, column);

        return QStringListModel::index(row, column, parent);
    }

    virtual QVariant data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
            if (index.row() == stringList().size())
96
                return QCoreApplication::translate("GenericProject", "<new>");
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        }

        return QStringListModel::data(index, role);
    }

    virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
    {
        if (role == Qt::EditRole && index.row() == stringList().size())
            insertRow(index.row(), QModelIndex());

        return QStringListModel::setData(index, value, role);
    }
};

} // end of anonymous namespace

113 114 115 116
////////////////////////////////////////////////////////////////////////////////////
// GenericProject
////////////////////////////////////////////////////////////////////////////////////

Roberto Raggi's avatar
Roberto Raggi committed
117
GenericProject::GenericProject(Manager *manager, const QString &fileName)
118 119
    : m_manager(manager),
      m_fileName(fileName),
Tobias Hunger's avatar
Tobias Hunger committed
120
      m_targetFactory(new GenericTargetFactory(this)),
121
      m_toolChain(0)
Roberto Raggi's avatar
Roberto Raggi committed
122
{
123
    QFileInfo fileInfo(m_fileName);
124 125
    QDir dir = fileInfo.dir();

126
    m_projectName      = fileInfo.completeBaseName();
127 128 129
    m_filesFileName    = QFileInfo(dir, m_projectName + QLatin1String(".files")).absoluteFilePath();
    m_includesFileName = QFileInfo(dir, m_projectName + QLatin1String(".includes")).absoluteFilePath();
    m_configFileName   = QFileInfo(dir, m_projectName + QLatin1String(".config")).absoluteFilePath();
130

131 132
    m_file = new GenericProjectFile(this, fileName);
    m_rootNode = new GenericProjectNode(this, m_file);
133

134
    m_manager->registerProject(this);
Roberto Raggi's avatar
Roberto Raggi committed
135 136 137 138
}

GenericProject::~GenericProject()
{
139
    m_manager->unregisterProject(this);
140

141 142
    delete m_rootNode;
    delete m_toolChain;
Roberto Raggi's avatar
Roberto Raggi committed
143 144
}

Tobias Hunger's avatar
Tobias Hunger committed
145 146 147 148 149 150
GenericTargetFactory *GenericProject::targetFactory() const
{
    return m_targetFactory;
}

GenericTarget *GenericProject::activeTarget() const
151
{
Tobias Hunger's avatar
Tobias Hunger committed
152
    return static_cast<GenericTarget *>(Project::activeTarget());
153 154
}

155
QString GenericProject::filesFileName() const
156
{ return m_filesFileName; }
157 158

QString GenericProject::includesFileName() const
159
{ return m_includesFileName; }
160 161

QString GenericProject::configFileName() const
162
{ return m_configFileName; }
163

164
static QStringList readLines(const QString &absoluteFileName)
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
{
    QStringList lines;

    QFile file(absoluteFileName);
    if (file.open(QFile::ReadOnly)) {
        QTextStream stream(&file);

        forever {
            QString line = stream.readLine();
            if (line.isNull())
                break;

            line = line.trimmed();
            if (line.isEmpty())
                continue;

            lines.append(line);
        }
    }

    return lines;
}

188
bool GenericProject::setFiles(const QStringList &filePaths)
189
{
190
    // Make sure we can open the file for writing
191
    QFile file(filesFileName());
192 193 194 195 196
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;

    QTextStream stream(&file);
    QDir baseDir(QFileInfo(m_fileName).dir());
197
    foreach (const QString &filePath, filePaths)
198 199 200 201 202
        stream << baseDir.relativeFilePath(filePath) << QLatin1Char('\n');

    file.close();
    refresh(GenericProject::Files);
    return true;
203
}
204

205 206 207 208 209 210 211 212 213 214
bool GenericProject::addFiles(const QStringList &filePaths)
{
    QStringList newFileList = m_files;
    newFileList.append(filePaths);

    return setFiles(newFileList);
}

bool GenericProject::removeFiles(const QStringList &filePaths)
{
215 216 217 218 219 220 221
    QStringList newFileList;
    QSet<QString> filesToRemove = filePaths.toSet();

    foreach (const QString &file, m_files) {
        if (!filesToRemove.contains(file))
            newFileList.append(file);
    }
222 223 224 225

    return setFiles(newFileList);
}

226
void GenericProject::parseProject(RefreshOptions options)
Roberto Raggi's avatar
Roberto Raggi committed
227
{
228
    if (options & Files)
229
        m_files = convertToAbsoluteFiles(readLines(filesFileName()));
230

231
    if (options & Configuration) {
232
        m_projectIncludePaths = convertToAbsoluteFiles(readLines(includesFileName()));
233

234 235
        QSettings projectInfo(m_fileName, QSettings::IniFormat);
        m_generated = convertToAbsoluteFiles(projectInfo.value(QLatin1String("generated")).toStringList());
Roberto Raggi's avatar
Roberto Raggi committed
236

237
        m_defines.clear();
Roberto Raggi's avatar
Roberto Raggi committed
238

239 240 241 242
        QFile configFile(configFileName());
        if (configFile.open(QFile::ReadOnly))
            m_defines = configFile.readAll();
    }
243

244 245
    if (options & Files)
        emit fileListChanged();
Roberto Raggi's avatar
Roberto Raggi committed
246 247
}

248
void GenericProject::refresh(RefreshOptions options)
Roberto Raggi's avatar
Roberto Raggi committed
249
{
250 251 252
    QSet<QString> oldFileList;
    if (!(options & Configuration))
        oldFileList = m_files.toSet();
253

254 255 256 257
    parseProject(options);

    if (options & Files)
        m_rootNode->refresh();
Roberto Raggi's avatar
Roberto Raggi committed
258 259 260 261

    CppTools::CppModelManagerInterface *modelManager =
        ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();

262 263 264
    if (m_toolChain && modelManager) {
        const QByteArray predefinedMacros = m_toolChain->predefinedMacros();
        const QList<ProjectExplorer::HeaderPath> systemHeaderPaths = m_toolChain->systemHeaderPaths();
Roberto Raggi's avatar
Roberto Raggi committed
265 266 267

        CppTools::CppModelManagerInterface::ProjectInfo pinfo = modelManager->projectInfo(this);
        pinfo.defines = predefinedMacros;
Roberto Raggi's avatar
Roberto Raggi committed
268
        pinfo.defines += '\n';
269
        pinfo.defines += m_defines;
Roberto Raggi's avatar
Roberto Raggi committed
270 271 272

        QStringList allIncludePaths, allFrameworkPaths;

273
        foreach (const ProjectExplorer::HeaderPath &headerPath, m_toolChain->systemHeaderPaths()) {
Roberto Raggi's avatar
Roberto Raggi committed
274 275 276 277 278 279
            if (headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath)
                allFrameworkPaths.append(headerPath.path());
            else
                allIncludePaths.append(headerPath.path());
        }

Roberto Raggi's avatar
Roberto Raggi committed
280
        allIncludePaths += this->allIncludePaths();
Roberto Raggi's avatar
Roberto Raggi committed
281 282 283 284 285

        pinfo.frameworkPaths = allFrameworkPaths;
        pinfo.includePaths = allIncludePaths;

        // ### add _defines.
Roberto Raggi's avatar
Roberto Raggi committed
286 287
        pinfo.sourceFiles = files();
        pinfo.sourceFiles += generated();
Roberto Raggi's avatar
Roberto Raggi committed
288

289 290 291 292 293 294 295 296 297 298 299
        QStringList filesToUpdate;

        if (options & Configuration) {
            filesToUpdate = pinfo.sourceFiles;
            filesToUpdate.append(QLatin1String("<configuration>")); // XXX don't hardcode configuration file name
        } else if (options & Files) {
            // Only update files that got added to the list
            QSet<QString> newFileList = m_files.toSet();
            newFileList.subtract(oldFileList);
            filesToUpdate.append(newFileList.toList());
        }
300

Roberto Raggi's avatar
Roberto Raggi committed
301
        modelManager->updateProjectInfo(pinfo);
302
        modelManager->updateSourceFiles(filesToUpdate);
Roberto Raggi's avatar
Roberto Raggi committed
303 304 305
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
306 307
QStringList GenericProject::convertToAbsoluteFiles(const QStringList &paths) const
{
308
    const QDir projectDir(QFileInfo(m_fileName).dir());
Roberto Raggi's avatar
Roberto Raggi committed
309 310 311 312 313 314 315 316 317
    QStringList absolutePaths;
    foreach (const QString &file, paths) {
        QFileInfo fileInfo(projectDir, file);
        absolutePaths.append(fileInfo.absoluteFilePath());
    }
    absolutePaths.removeDuplicates();
    return absolutePaths;
}

Roberto Raggi's avatar
Roberto Raggi committed
318 319 320
QStringList GenericProject::allIncludePaths() const
{
    QStringList paths;
321 322
    paths += m_includePaths;
    paths += m_projectIncludePaths;
Roberto Raggi's avatar
Roberto Raggi committed
323 324 325 326 327
    paths.removeDuplicates();
    return paths;
}

QStringList GenericProject::projectIncludePaths() const
328
{ return m_projectIncludePaths; }
Roberto Raggi's avatar
Roberto Raggi committed
329

Roberto Raggi's avatar
Roberto Raggi committed
330
QStringList GenericProject::files() const
331
{ return m_files; }
Roberto Raggi's avatar
Roberto Raggi committed
332 333

QStringList GenericProject::generated() const
334
{ return m_generated; }
Roberto Raggi's avatar
Roberto Raggi committed
335 336

QStringList GenericProject::includePaths() const
337
{ return m_includePaths; }
Roberto Raggi's avatar
Roberto Raggi committed
338 339

void GenericProject::setIncludePaths(const QStringList &includePaths)
340
{ m_includePaths = includePaths; }
Roberto Raggi's avatar
Roberto Raggi committed
341

Roberto Raggi's avatar
Roberto Raggi committed
342
QByteArray GenericProject::defines() const
343
{ return m_defines; }
Roberto Raggi's avatar
Roberto Raggi committed
344

345
void GenericProject::setToolChainType(ProjectExplorer::ToolChain::ToolChainType type)
Roberto Raggi's avatar
Roberto Raggi committed
346 347 348
{
    using namespace ProjectExplorer;

349
    m_toolChainType = type;
350

351 352
    delete m_toolChain;
    m_toolChain = 0;
Roberto Raggi's avatar
Roberto Raggi committed
353

354
    if (type == ToolChain::MinGW) {
Roberto Raggi's avatar
Roberto Raggi committed
355 356 357
        const QLatin1String qmake_cxx("g++"); // ### FIXME
        const QString mingwDirectory; // ### FIXME

358
        m_toolChain = ToolChain::createMinGWToolChain(qmake_cxx, mingwDirectory);
Roberto Raggi's avatar
Roberto Raggi committed
359

360
    } else if (type == ToolChain::MSVC) {
Roberto Raggi's avatar
Roberto Raggi committed
361
        const QString msvcVersion; // ### FIXME
362
        m_toolChain = ToolChain::createMSVCToolChain(msvcVersion, false);
Roberto Raggi's avatar
Roberto Raggi committed
363

364
    } else if (type == ToolChain::WINCE) {
Roberto Raggi's avatar
Roberto Raggi committed
365
        const QString msvcVersion, wincePlatform; // ### FIXME
366
        m_toolChain = ToolChain::createWinCEToolChain(msvcVersion, wincePlatform);
Roberto Raggi's avatar
Roberto Raggi committed
367

368
    } else if (type == ToolChain::GCC || type == ToolChain::GCC) {
Roberto Raggi's avatar
Roberto Raggi committed
369
        const QLatin1String qmake_cxx("g++"); // ### FIXME
370
        m_toolChain = ToolChain::createGccToolChain(qmake_cxx);
Roberto Raggi's avatar
Roberto Raggi committed
371 372 373
    }
}

374 375 376 377 378
ProjectExplorer::ToolChain *GenericProject::toolChain() const
{
    return m_toolChain;
}

379 380
ProjectExplorer::ToolChain::ToolChainType GenericProject::toolChainType() const
{ return m_toolChainType; }
381

382
QString GenericProject::displayName() const
Roberto Raggi's avatar
Roberto Raggi committed
383
{
384
    return m_projectName;
Roberto Raggi's avatar
Roberto Raggi committed
385 386
}

Tobias Hunger's avatar
Tobias Hunger committed
387 388 389 390 391
QString GenericProject::id() const
{
    return QLatin1String("GenericProjectManager.GenericProject");
}

Roberto Raggi's avatar
Roberto Raggi committed
392 393
Core::IFile *GenericProject::file() const
{
394
    return m_file;
Roberto Raggi's avatar
Roberto Raggi committed
395 396 397 398
}

ProjectExplorer::IProjectManager *GenericProject::projectManager() const
{
399
    return m_manager;
Roberto Raggi's avatar
Roberto Raggi committed
400 401 402 403 404 405 406 407 408 409 410 411
}

QList<ProjectExplorer::Project *> GenericProject::dependsOn()
{
    return QList<Project *>();
}

bool GenericProject::isApplication() const
{
    return true;
}

dt's avatar
dt committed
412
ProjectExplorer::BuildConfigWidget *GenericProject::createConfigWidget()
Roberto Raggi's avatar
Roberto Raggi committed
413 414 415 416
{
    return new GenericBuildSettingsWidget(this);
}

dt's avatar
dt committed
417
QList<ProjectExplorer::BuildConfigWidget*> GenericProject::subConfigWidgets()
Roberto Raggi's avatar
Roberto Raggi committed
418
{
dt's avatar
dt committed
419
    return QList<ProjectExplorer::BuildConfigWidget*>();
Roberto Raggi's avatar
Roberto Raggi committed
420 421
}

422
GenericProjectNode *GenericProject::rootProjectNode() const
Roberto Raggi's avatar
Roberto Raggi committed
423
{
424
    return m_rootNode;
Roberto Raggi's avatar
Roberto Raggi committed
425 426 427 428
}

QStringList GenericProject::files(FilesMode fileMode) const
{
429
    Q_UNUSED(fileMode)
430
    return m_files; // ### TODO: handle generated files here.
Roberto Raggi's avatar
Roberto Raggi committed
431 432
}

Tobias Hunger's avatar
Tobias Hunger committed
433
QStringList GenericProject::buildTargets() const
Roberto Raggi's avatar
Roberto Raggi committed
434 435 436 437 438 439 440
{
    QStringList targets;
    targets.append(QLatin1String("all"));
    targets.append(QLatin1String("clean"));
    return targets;
}

441
QVariantMap GenericProject::toMap() const
Roberto Raggi's avatar
Roberto Raggi committed
442
{
443 444 445 446 447 448 449 450 451
    QVariantMap map(Project::toMap());
    map.insert(QLatin1String(TOOLCHAIN_KEY), static_cast<int>(m_toolChainType));
    return map;
}

bool GenericProject::fromMap(const QVariantMap &map)
{
    if (!Project::fromMap(map))
        return false;
Roberto Raggi's avatar
Roberto Raggi committed
452

453
    // Add default BC:
Tobias Hunger's avatar
Tobias Hunger committed
454 455
    if (targets().isEmpty())
        addTarget(targetFactory()->create(this, QLatin1String(GENERIC_DESKTOP_TARGET_ID)));
456

457 458 459
    ToolChain::ToolChainType type =
            static_cast<ProjectExplorer::ToolChain::ToolChainType>
            (map.value(QLatin1String(TOOLCHAIN_KEY), 0).toInt());
Roberto Raggi's avatar
Roberto Raggi committed
460

461
    setToolChainType(type);
Roberto Raggi's avatar
Roberto Raggi committed
462 463

    setIncludePaths(allIncludePaths());
464

465
    refresh(Everything);
dt's avatar
dt committed
466
    return true;
467 468
}

Roberto Raggi's avatar
Roberto Raggi committed
469 470 471
////////////////////////////////////////////////////////////////////////////////////
// GenericBuildSettingsWidget
////////////////////////////////////////////////////////////////////////////////////
472

Roberto Raggi's avatar
Roberto Raggi committed
473
GenericBuildSettingsWidget::GenericBuildSettingsWidget(GenericProject *project)
dt's avatar
dt committed
474
    : m_project(project), m_buildConfiguration(0)
Roberto Raggi's avatar
Roberto Raggi committed
475 476
{
    QFormLayout *fl = new QFormLayout(this);
477 478
    fl->setContentsMargins(0, -1, 0, -1);
    fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
479 480

    // build directory
481
    m_pathChooser = new Utils::PathChooser(this);
482 483
    m_pathChooser->setEnabled(true);
    fl->addRow(tr("Build directory:"), m_pathChooser);
con's avatar
con committed
484
    connect(m_pathChooser, SIGNAL(changed(QString)), this, SLOT(buildDirectoryChanged()));
485

486
    // tool chain
487
    QComboBox *toolChainChooser = new QComboBox;
488
    toolChainChooser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
489
    using namespace ProjectExplorer;
490 491
    int index = 0;
    int selectedIndex = -1;
492
    foreach (ToolChain::ToolChainType tc, ToolChain::supportedToolChains()) {
493 494 495 496
        toolChainChooser->addItem(ToolChain::toolChainName(tc), QVariant::fromValue<ToolChain::ToolChainType>(tc));
        if (m_project->toolChainType() == tc)
            selectedIndex = index;
        ++index;
497 498
    }

499
    toolChainChooser->setCurrentIndex(selectedIndex);
500
    fl->addRow(tr("Tool Chain:"), toolChainChooser);
501
    connect(toolChainChooser, SIGNAL(activated(int)), this, SLOT(toolChainSelected(int)));
Roberto Raggi's avatar
Roberto Raggi committed
502 503 504 505 506 507 508 509
}

GenericBuildSettingsWidget::~GenericBuildSettingsWidget()
{ }

QString GenericBuildSettingsWidget::displayName() const
{ return tr("Generic Manager"); }

dt's avatar
dt committed
510
void GenericBuildSettingsWidget::init(BuildConfiguration *bc)
Roberto Raggi's avatar
Roberto Raggi committed
511
{
512 513
    m_buildConfiguration = static_cast<GenericBuildConfiguration *>(bc);
    m_pathChooser->setPath(m_buildConfiguration->buildDirectory());
Roberto Raggi's avatar
Roberto Raggi committed
514 515 516 517
}

void GenericBuildSettingsWidget::buildDirectoryChanged()
{
518
    m_buildConfiguration->setBuildDirectory(m_pathChooser->path());
Roberto Raggi's avatar
Roberto Raggi committed
519 520
}

521 522 523 524 525 526 527 528 529
void GenericBuildSettingsWidget::toolChainSelected(int index)
{
    using namespace ProjectExplorer;

    QComboBox *toolChainChooser = qobject_cast<QComboBox*>(sender());
    ToolChain::ToolChainType type = toolChainChooser->itemData(index).value<ToolChain::ToolChainType>();
    m_project->setToolChainType(type);
}

Roberto Raggi's avatar
Roberto Raggi committed
530 531 532
////////////////////////////////////////////////////////////////////////////////////
// GenericProjectFile
////////////////////////////////////////////////////////////////////////////////////
533

Roberto Raggi's avatar
Roberto Raggi committed
534 535
GenericProjectFile::GenericProjectFile(GenericProject *parent, QString fileName)
    : Core::IFile(parent),
536 537
      m_project(parent),
      m_fileName(fileName)
Roberto Raggi's avatar
Roberto Raggi committed
538 539 540 541 542 543 544 545 546 547 548 549
{ }

GenericProjectFile::~GenericProjectFile()
{ }

bool GenericProjectFile::save(const QString &)
{
    return false;
}

QString GenericProjectFile::fileName() const
{
550
    return m_fileName;
Roberto Raggi's avatar
Roberto Raggi committed
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
}

QString GenericProjectFile::defaultPath() const
{
    return QString();
}

QString GenericProjectFile::suggestedFileName() const
{
    return QString();
}

QString GenericProjectFile::mimeType() const
{
    return Constants::GENERICMIMETYPE;
}

bool GenericProjectFile::isModified() const
{
    return false;
}

bool GenericProjectFile::isReadOnly() const
{
    return true;
}

bool GenericProjectFile::isSaveAsAllowed() const
{
    return false;
}

void GenericProjectFile::modified(ReloadBehavior *)
{
}