ProjectExplorer::Project*
ProjectManager::openProject(QString const& fileName, QString* errorString)
{
    BBPM_QDEBUG("opening project:" << fileName);

    if (!QFileInfo(fileName).isFile())
    {
        if (errorString)
            *errorString = tr("Failed opening project '%1': Project is not a file")
                           .arg(fileName);
        return 0;
    }

    return new Project(this, fileName);
}
void BoostBuildParser::stdOutput(QString const& rawLine)
{
    setToolsetParser(findToolset(rawLine));

    QString const line
        = rightTrimmed(rawLine).replace(rxTestFileLineN_, QLatin1String("\\1:\\2"));
    if (!toolsetName_.isEmpty() && line.startsWith(toolsetName_))
        lineMode_ = Toolset;
    else if (line.startsWith(QLatin1String("testing"))
            || line.startsWith(QLatin1String("(failed-as-expected)")))
        lineMode_ = Testing;
    else if (line.startsWith(QLatin1String("common")))
        lineMode_ = Common;

    // TODO: Why forwarding stdOutput to ProjectExplorer::IOutputParser::stdError?
    // Because of a bug (or feature?) in Boost.Build:
    // stdout and stderr not forwarded to respective channels
    // https://svn.boost.org/trac/boost/ticket/9485

    if (lineMode_ == Toolset)
    {
        ProjectExplorer::IOutputParser::stdError(line);
    }
    else if (lineMode_ == Testing)
    {
        if (rxTestPassed_.indexIn(line) > -1)
        {
            BBPM_QDEBUG(rxTestPassed_.capturedTexts());
            // TODO: issue #3
            ProjectExplorer::Task task(ProjectExplorer::Task::Unknown
                , rxTestPassed_.cap(0)
                , Utils::FileName::fromString(rxTestPassed_.cap(1))
                , -1 // line
                , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
            setTask(task);
            lineMode_ = Common;
        }
        else if (rxTestFailed_.indexIn(line) > -1)
        {
            BBPM_QDEBUG(rxTestFailed_.capturedTexts());

            // Report summary task for "...failed testing.capture-output /myfile.run"
            ProjectExplorer::Task task(ProjectExplorer::Task::Error
                , rxTestFailed_.cap(0)
                , Utils::FileName::fromString(rxTestFailed_.cap(1))
                , -1 // line
                , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
            setTask(task);

            lineMode_ = Common;
        }
        else if (rxTestFailedAsExpected_.indexIn(line) > -1)
        {
            BBPM_QDEBUG(rxTestFailedAsExpected_.capturedTexts());

            // TODO: Handling of "(failed-as-expected)" is not great, might be confusing.
            // Boost.Build spits out compile command first, so compilation errors arrive
            // and are parsed immediately (issue tasks are created)
            // due to lineMode_==Toolset.
            // Then, "(failed-as-expected)" status arrives and there seem to be no way to
            // look back and clear all the issue tasks created for compilation errors.
            // TODO: Ask Volodya if b2 could announce "testing." before compile command
            // for a compile-time test.

            QString fileName(rxTestFailedAsExpected_.cap(1));
            if (rxTestFileObj_.indexIn(fileName))
                fileName = rxTestFileObj_.cap(1) + QLatin1String(".cpp");// FIXME:hardcoded ext

            // ATM, we can only indicate in UI that test failed-as-expected
            ProjectExplorer::Task task(ProjectExplorer::Task::Error
                , rxTestFailedAsExpected_.cap(0)
                , Utils::FileName::fromString(fileName)
                , -1 // line
                , ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
            setTask(task);

            lineMode_ = Common;
        }
        else
        {
            // Parses compilation errors of run-time tests, creates issue tasks
            ProjectExplorer::IOutputParser::stdError(line);
        }
    }
    else
    {
        doFlush();
        ProjectExplorer::IOutputParser::stdOutput(line);
    }
}
QString ProjectManager::mimeType() const
{
    BBPM_QDEBUG(Constants::MIMETYPE_PROJECT);

    return QLatin1String(Constants::MIMETYPE_PROJECT);
}