<commit_before>/**************************************************************************
**
** Copyright (c) 2013 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "androidtoolchain.h"
#include "androidconstants.h"
#include "androidconfigurations.h"
#include "androidqtversion.h"

#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>

#include <projectexplorer/target.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/projectexplorer.h>

#include <utils/environment.h>
#include <utils/hostosinfo.h>

#include <QDir>
#include <QDirIterator>
#include <QFormLayout>
#include <QLabel>
#include <QVBoxLayout>

namespace {
    const QLatin1String NDKGccVersionRegExp("-\\d[\\.\\d]+");
}

namespace Android {
namespace Internal {

using namespace ProjectExplorer;
using namespace Utils;

static const char ANDROID_QT_VERSION_KEY[] = "Qt4ProjectManager.Android.QtVersion";
static const char ANDROID_NDK_TC_VERION[] = "Qt4ProjectManager.Android.NDK_TC_VERION";

AndroidToolChain::AndroidToolChain(Abi::Architecture arch, const QString &ndkToolChainVersion, bool autodetected)
    : GccToolChain(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID), autodetected),
      m_ndkToolChainVersion(ndkToolChainVersion)
{
    ProjectExplorer::Abi abi = ProjectExplorer::Abi(arch, ProjectExplorer::Abi::LinuxOS,
                                                    ProjectExplorer::Abi::AndroidLinuxFlavor, ProjectExplorer::Abi::ElfFormat,
                                                    32);
    setTargetAbi(abi);
    setDisplayName(QString::fromLatin1("Android GCC (%1-%2)")
                   .arg(Abi::toString(targetAbi().architecture()))
                   .arg(ndkToolChainVersion));
}

// for fromMap
AndroidToolChain::AndroidToolChain()
    : GccToolChain(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID), false)
{
}

AndroidToolChain::AndroidToolChain(const AndroidToolChain &tc) :
    GccToolChain(tc), m_ndkToolChainVersion(tc.m_ndkToolChainVersion)
{ }

AndroidToolChain::~AndroidToolChain()
{ }

QString AndroidToolChain::type() const
{
    return QLatin1String(Android::Constants::ANDROID_TOOLCHAIN_TYPE);
}

QString AndroidToolChain::typeDisplayName() const
{
    return AndroidToolChainFactory::tr("Android GCC");
}

bool AndroidToolChain::isValid() const
{
    return GccToolChain::isValid() && targetAbi().isValid() && !m_ndkToolChainVersion.isEmpty()
            && compilerCommand().isChildOf(AndroidConfigurations::instance().config().ndkLocation);
}

void AndroidToolChain::addToEnvironment(Environment &env) const
{

// TODO this vars should be configurable in projects -> build tab
// TODO invalidate all .pro files !!!

    env.set(QLatin1String("ANDROID_NDK_HOST"), AndroidConfigurations::instance().config().toolchainHost);
    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_PREFIX"), AndroidConfigurations::toolchainPrefix(targetAbi().architecture()));
    env.set(QLatin1String("ANDROID_NDK_TOOLS_PREFIX"), AndroidConfigurations::toolsPrefix(targetAbi().architecture()));
    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_VERSION"), m_ndkToolChainVersion);
    QString javaHome = AndroidConfigurations::instance().openJDKPath().toString();
    if (!javaHome.isEmpty() && QFileInfo(javaHome).exists())
        env.set(QLatin1String("JAVA_HOME"), javaHome);
}

bool AndroidToolChain::operator ==(const ToolChain &tc) const
{
    if (!GccToolChain::operator ==(tc))
        return false;

    return m_ndkToolChainVersion == static_cast<const AndroidToolChain &>(tc).m_ndkToolChainVersion;
}

ToolChainConfigWidget *AndroidToolChain::configurationWidget()
{
    return new AndroidToolChainConfigWidget(this);
}

FileName AndroidToolChain::suggestedDebugger() const
{
    return AndroidConfigurations::instance().gdbPath(targetAbi().architecture(), m_ndkToolChainVersion);
}

FileName AndroidToolChain::suggestedGdbServer() const
{
    Utils::FileName path = AndroidConfigurations::instance().config().ndkLocation;
    path.appendPath(QString::fromLatin1("prebuilt/android-%1/gdbserver/gdbserver")
                    .arg(Abi::toString(targetAbi().architecture())));
    if (path.toFileInfo().exists())
        return path;
    path = AndroidConfigurations::instance().config().ndkLocation;
    path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/gdbserver")
                               .arg(AndroidConfigurations::toolchainPrefix(targetAbi().architecture()))
                               .arg(m_ndkToolChainVersion));
    if (path.toFileInfo().exists())
        return path;

    return Utils::FileName();
}

QVariantMap AndroidToolChain::toMap() const
{
    QVariantMap result = GccToolChain::toMap();
    result.insert(QLatin1String(ANDROID_NDK_TC_VERION), m_ndkToolChainVersion);
    return result;
}

bool AndroidToolChain::fromMap(const QVariantMap &data)
{
    if (!GccToolChain::fromMap(data))
        return false;

    if (data.contains(QLatin1String(ANDROID_QT_VERSION_KEY))) {
        QString command = compilerCommand().toString();
        QString ndkPath = AndroidConfigurations::instance().config().ndkLocation.toString();
        if (!command.startsWith(ndkPath))
            return false;
        command = command.mid(ndkPath.length());
        if (!command.startsWith(QLatin1String("/toolchains/")))
            return false;
        command = command.mid(12);
        int index = command.indexOf(QLatin1Char('/'));
        if (index == -1)
            return false;
        command = command.left(index);
        QRegExp versionRegExp(NDKGccVersionRegExp);
        index = versionRegExp.indexIn(command);
        if (index == -1)
            return false;
        m_ndkToolChainVersion = command.mid(index + 1);
        QString platform = command.left(index);
        Abi::Architecture arch = AndroidConfigurations::architectureForToolChainPrefix(platform);
        ProjectExplorer::Abi abi = ProjectExplorer::Abi(arch, ProjectExplorer::Abi::LinuxOS,
                                                        ProjectExplorer::Abi::AndroidLinuxFlavor, ProjectExplorer::Abi::ElfFormat,
                                                        32);
        setTargetAbi(abi);
    } else {
        m_ndkToolChainVersion = data.value(QLatin1String(ANDROID_NDK_TC_VERION)).toString();
    }

    return isValid();
}

QList<FileName> AndroidToolChain::suggestedMkspecList() const
{
    return QList<FileName>()<< FileName::fromString(QLatin1String("android-g++"));
}

QString AndroidToolChain::makeCommand(const Utils::Environment &env) const
{
    QStringList extraDirectories = AndroidConfigurations::instance().makeExtraSearchDirectories();
    if (HostOsInfo::isWindowsHost()) {
        QString tmp = env.searchInPath(QLatin1String("ma-make.exe"), extraDirectories);
        if (!tmp.isEmpty())
            return tmp;
        tmp = env.searchInPath(QLatin1String("mingw32-make"), extraDirectories);
        return tmp.isEmpty() ? QLatin1String("mingw32-make") : tmp;
    }

    QString make = QLatin1String("make");
    QString tmp = env.searchInPath(make, extraDirectories);
    return tmp.isEmpty() ? make : tmp;
}

QString AndroidToolChain::ndkToolChainVersion()
{
    return m_ndkToolChainVersion;
}

QList<Abi> AndroidToolChain::detectSupportedAbis() const
{
    return QList<Abi>() << targetAbi();
}

// --------------------------------------------------------------------------
// ToolChainConfigWidget
// --------------------------------------------------------------------------

AndroidToolChainConfigWidget::AndroidToolChainConfigWidget(AndroidToolChain *tc) :
   ToolChainConfigWidget(tc)
{
    QLabel *label = new QLabel(AndroidConfigurations::instance().config().ndkLocation.toUserOutput());
    m_mainLayout->addRow(tr("NDK Root:"), label);
}

// --------------------------------------------------------------------------
// ToolChainFactory
// --------------------------------------------------------------------------

AndroidToolChainFactory::AndroidToolChainFactory() :
    ToolChainFactory()
{ }

QString AndroidToolChainFactory::displayName() const
{
    return tr("Android GCC");
}

QString AndroidToolChainFactory::id() const
{
    return QLatin1String(Constants::ANDROID_TOOLCHAIN_ID);
}

QList<ToolChain *> AndroidToolChainFactory::autoDetect()
{
    return createToolChainsForNdk(AndroidConfigurations::instance().config().ndkLocation);
}

bool AndroidToolChainFactory::canRestore(const QVariantMap &data)
{
    return idFromMap(data).startsWith(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID) + QLatin1Char(':'));
}

ToolChain *AndroidToolChainFactory::restore(const QVariantMap &data)
{
    AndroidToolChain *tc = new AndroidToolChain();
    if (tc->fromMap(data))
        return tc;

    delete tc;
    return 0;
}

QList<AndroidToolChainFactory::AndroidToolChainInformation> AndroidToolChainFactory::toolchainPathsForNdk(const Utils::FileName &ndkPath)
{
    QList<AndroidToolChainInformation> result;
    if (ndkPath.isEmpty())
        return result;
    QRegExp versionRegExp(NDKGccVersionRegExp);
    FileName path = ndkPath;
    QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
                    QStringList() << QLatin1String("*"), QDir::Dirs);
    while (it.hasNext()) {
        const QString &fileName = QFileInfo(it.next()).fileName();
        int idx = versionRegExp.indexIn(fileName);
        if (idx == -1)
            continue;
        AndroidToolChainInformation ati;
        ati.version = fileName.mid(idx + 1);
        QString platform = fileName.left(idx);
        ati.architecture = AndroidConfigurations::architectureForToolChainPrefix(platform);
        if (ati.architecture == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
            continue;
        // AndroidToolChain *tc = new AndroidToolChain(arch, version, true);
        ati.compilerCommand = AndroidConfigurations::instance().gccPath(ati.architecture, ati.version);
        // tc->setCompilerCommand(compilerPath);
        result.append(ati);
    }
    return result;
}

QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const Utils::FileName &ndkPath)
{
    QList<ToolChain *> result;
    if (ndkPath.isEmpty())
        return result;
    QRegExp versionRegExp(NDKGccVersionRegExp);
    FileName path = ndkPath;
    QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
                    QStringList() << QLatin1String("*"), QDir::Dirs);
    while (it.hasNext()) {
        const QString &fileName = QFileInfo(it.next()).fileName();
        int idx = versionRegExp.indexIn(fileName);
        if (idx == -1)
            continue;
        QString version = fileName.mid(idx + 1);
        QString platform = fileName.left(idx);
        Abi::Architecture arch = AndroidConfigurations::architectureForToolChainPrefix(platform);
        if (arch == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
            continue;
        AndroidToolChain *tc = new AndroidToolChain(arch, version, true);
        FileName compilerPath = AndroidConfigurations::instance().gccPath(arch, version);
        tc->setCompilerCommand(compilerPath);
        result.append(tc);
    }
    return result;
}

} // namespace Internal
} // namespace Android
<commit_msg>Android: Set ANDROID_HOME environment variable<commit_after>/**************************************************************************
**
** Copyright (c) 2013 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "androidtoolchain.h"
#include "androidconstants.h"
#include "androidconfigurations.h"
#include "androidqtversion.h"

#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>

#include <projectexplorer/target.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/projectexplorer.h>

#include <utils/environment.h>
#include <utils/hostosinfo.h>

#include <QDir>
#include <QDirIterator>
#include <QFormLayout>
#include <QLabel>
#include <QVBoxLayout>

namespace {
    const QLatin1String NDKGccVersionRegExp("-\\d[\\.\\d]+");
}

namespace Android {
namespace Internal {

using namespace ProjectExplorer;
using namespace Utils;

static const char ANDROID_QT_VERSION_KEY[] = "Qt4ProjectManager.Android.QtVersion";
static const char ANDROID_NDK_TC_VERION[] = "Qt4ProjectManager.Android.NDK_TC_VERION";

AndroidToolChain::AndroidToolChain(Abi::Architecture arch, const QString &ndkToolChainVersion, bool autodetected)
    : GccToolChain(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID), autodetected),
      m_ndkToolChainVersion(ndkToolChainVersion)
{
    ProjectExplorer::Abi abi = ProjectExplorer::Abi(arch, ProjectExplorer::Abi::LinuxOS,
                                                    ProjectExplorer::Abi::AndroidLinuxFlavor, ProjectExplorer::Abi::ElfFormat,
                                                    32);
    setTargetAbi(abi);
    setDisplayName(QString::fromLatin1("Android GCC (%1-%2)")
                   .arg(Abi::toString(targetAbi().architecture()))
                   .arg(ndkToolChainVersion));
}

// for fromMap
AndroidToolChain::AndroidToolChain()
    : GccToolChain(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID), false)
{
}

AndroidToolChain::AndroidToolChain(const AndroidToolChain &tc) :
    GccToolChain(tc), m_ndkToolChainVersion(tc.m_ndkToolChainVersion)
{ }

AndroidToolChain::~AndroidToolChain()
{ }

QString AndroidToolChain::type() const
{
    return QLatin1String(Android::Constants::ANDROID_TOOLCHAIN_TYPE);
}

QString AndroidToolChain::typeDisplayName() const
{
    return AndroidToolChainFactory::tr("Android GCC");
}

bool AndroidToolChain::isValid() const
{
    return GccToolChain::isValid() && targetAbi().isValid() && !m_ndkToolChainVersion.isEmpty()
            && compilerCommand().isChildOf(AndroidConfigurations::instance().config().ndkLocation);
}

void AndroidToolChain::addToEnvironment(Environment &env) const
{

// TODO this vars should be configurable in projects -> build tab
// TODO invalidate all .pro files !!!

    env.set(QLatin1String("ANDROID_NDK_HOST"), AndroidConfigurations::instance().config().toolchainHost);
    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_PREFIX"), AndroidConfigurations::toolchainPrefix(targetAbi().architecture()));
    env.set(QLatin1String("ANDROID_NDK_TOOLS_PREFIX"), AndroidConfigurations::toolsPrefix(targetAbi().architecture()));
    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_VERSION"), m_ndkToolChainVersion);
    QString javaHome = AndroidConfigurations::instance().openJDKPath().toString();
    if (!javaHome.isEmpty() && QFileInfo(javaHome).exists())
        env.set(QLatin1String("JAVA_HOME"), javaHome);
    env.set(QLatin1String("ANDROID_HOME"), AndroidConfigurations::instance().config().sdkLocation.toString());
}

bool AndroidToolChain::operator ==(const ToolChain &tc) const
{
    if (!GccToolChain::operator ==(tc))
        return false;

    return m_ndkToolChainVersion == static_cast<const AndroidToolChain &>(tc).m_ndkToolChainVersion;
}

ToolChainConfigWidget *AndroidToolChain::configurationWidget()
{
    return new AndroidToolChainConfigWidget(this);
}

FileName AndroidToolChain::suggestedDebugger() const
{
    return AndroidConfigurations::instance().gdbPath(targetAbi().architecture(), m_ndkToolChainVersion);
}

FileName AndroidToolChain::suggestedGdbServer() const
{
    Utils::FileName path = AndroidConfigurations::instance().config().ndkLocation;
    path.appendPath(QString::fromLatin1("prebuilt/android-%1/gdbserver/gdbserver")
                    .arg(Abi::toString(targetAbi().architecture())));
    if (path.toFileInfo().exists())
        return path;
    path = AndroidConfigurations::instance().config().ndkLocation;
    path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/gdbserver")
                               .arg(AndroidConfigurations::toolchainPrefix(targetAbi().architecture()))
                               .arg(m_ndkToolChainVersion));
    if (path.toFileInfo().exists())
        return path;

    return Utils::FileName();
}

QVariantMap AndroidToolChain::toMap() const
{
    QVariantMap result = GccToolChain::toMap();
    result.insert(QLatin1String(ANDROID_NDK_TC_VERION), m_ndkToolChainVersion);
    return result;
}

bool AndroidToolChain::fromMap(const QVariantMap &data)
{
    if (!GccToolChain::fromMap(data))
        return false;

    if (data.contains(QLatin1String(ANDROID_QT_VERSION_KEY))) {
        QString command = compilerCommand().toString();
        QString ndkPath = AndroidConfigurations::instance().config().ndkLocation.toString();
        if (!command.startsWith(ndkPath))
            return false;
        command = command.mid(ndkPath.length());
        if (!command.startsWith(QLatin1String("/toolchains/")))
            return false;
        command = command.mid(12);
        int index = command.indexOf(QLatin1Char('/'));
        if (index == -1)
            return false;
        command = command.left(index);
        QRegExp versionRegExp(NDKGccVersionRegExp);
        index = versionRegExp.indexIn(command);
        if (index == -1)
            return false;
        m_ndkToolChainVersion = command.mid(index + 1);
        QString platform = command.left(index);
        Abi::Architecture arch = AndroidConfigurations::architectureForToolChainPrefix(platform);
        ProjectExplorer::Abi abi = ProjectExplorer::Abi(arch, ProjectExplorer::Abi::LinuxOS,
                                                        ProjectExplorer::Abi::AndroidLinuxFlavor, ProjectExplorer::Abi::ElfFormat,
                                                        32);
        setTargetAbi(abi);
    } else {
        m_ndkToolChainVersion = data.value(QLatin1String(ANDROID_NDK_TC_VERION)).toString();
    }

    return isValid();
}

QList<FileName> AndroidToolChain::suggestedMkspecList() const
{
    return QList<FileName>()<< FileName::fromString(QLatin1String("android-g++"));
}

QString AndroidToolChain::makeCommand(const Utils::Environment &env) const
{
    QStringList extraDirectories = AndroidConfigurations::instance().makeExtraSearchDirectories();
    if (HostOsInfo::isWindowsHost()) {
        QString tmp = env.searchInPath(QLatin1String("ma-make.exe"), extraDirectories);
        if (!tmp.isEmpty())
            return tmp;
        tmp = env.searchInPath(QLatin1String("mingw32-make"), extraDirectories);
        return tmp.isEmpty() ? QLatin1String("mingw32-make") : tmp;
    }

    QString make = QLatin1String("make");
    QString tmp = env.searchInPath(make, extraDirectories);
    return tmp.isEmpty() ? make : tmp;
}

QString AndroidToolChain::ndkToolChainVersion()
{
    return m_ndkToolChainVersion;
}

QList<Abi> AndroidToolChain::detectSupportedAbis() const
{
    return QList<Abi>() << targetAbi();
}

// --------------------------------------------------------------------------
// ToolChainConfigWidget
// --------------------------------------------------------------------------

AndroidToolChainConfigWidget::AndroidToolChainConfigWidget(AndroidToolChain *tc) :
   ToolChainConfigWidget(tc)
{
    QLabel *label = new QLabel(AndroidConfigurations::instance().config().ndkLocation.toUserOutput());
    m_mainLayout->addRow(tr("NDK Root:"), label);
}

// --------------------------------------------------------------------------
// ToolChainFactory
// --------------------------------------------------------------------------

AndroidToolChainFactory::AndroidToolChainFactory() :
    ToolChainFactory()
{ }

QString AndroidToolChainFactory::displayName() const
{
    return tr("Android GCC");
}

QString AndroidToolChainFactory::id() const
{
    return QLatin1String(Constants::ANDROID_TOOLCHAIN_ID);
}

QList<ToolChain *> AndroidToolChainFactory::autoDetect()
{
    return createToolChainsForNdk(AndroidConfigurations::instance().config().ndkLocation);
}

bool AndroidToolChainFactory::canRestore(const QVariantMap &data)
{
    return idFromMap(data).startsWith(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID) + QLatin1Char(':'));
}

ToolChain *AndroidToolChainFactory::restore(const QVariantMap &data)
{
    AndroidToolChain *tc = new AndroidToolChain();
    if (tc->fromMap(data))
        return tc;

    delete tc;
    return 0;
}

QList<AndroidToolChainFactory::AndroidToolChainInformation> AndroidToolChainFactory::toolchainPathsForNdk(const Utils::FileName &ndkPath)
{
    QList<AndroidToolChainInformation> result;
    if (ndkPath.isEmpty())
        return result;
    QRegExp versionRegExp(NDKGccVersionRegExp);
    FileName path = ndkPath;
    QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
                    QStringList() << QLatin1String("*"), QDir::Dirs);
    while (it.hasNext()) {
        const QString &fileName = QFileInfo(it.next()).fileName();
        int idx = versionRegExp.indexIn(fileName);
        if (idx == -1)
            continue;
        AndroidToolChainInformation ati;
        ati.version = fileName.mid(idx + 1);
        QString platform = fileName.left(idx);
        ati.architecture = AndroidConfigurations::architectureForToolChainPrefix(platform);
        if (ati.architecture == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
            continue;
        // AndroidToolChain *tc = new AndroidToolChain(arch, version, true);
        ati.compilerCommand = AndroidConfigurations::instance().gccPath(ati.architecture, ati.version);
        // tc->setCompilerCommand(compilerPath);
        result.append(ati);
    }
    return result;
}

QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const Utils::FileName &ndkPath)
{
    QList<ToolChain *> result;
    if (ndkPath.isEmpty())
        return result;
    QRegExp versionRegExp(NDKGccVersionRegExp);
    FileName path = ndkPath;
    QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
                    QStringList() << QLatin1String("*"), QDir::Dirs);
    while (it.hasNext()) {
        const QString &fileName = QFileInfo(it.next()).fileName();
        int idx = versionRegExp.indexIn(fileName);
        if (idx == -1)
            continue;
        QString version = fileName.mid(idx + 1);
        QString platform = fileName.left(idx);
        Abi::Architecture arch = AndroidConfigurations::architectureForToolChainPrefix(platform);
        if (arch == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
            continue;
        AndroidToolChain *tc = new AndroidToolChain(arch, version, true);
        FileName compilerPath = AndroidConfigurations::instance().gccPath(arch, version);
        tc->setCompilerCommand(compilerPath);
        result.append(tc);
    }
    return result;
}

} // namespace Internal
} // namespace Android
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** 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
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "designersettings.h"
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h"
#include "settingspage.h"

#include <QtCore/QTextStream>
#include <QtGui/QCheckBox>

using namespace QmlDesigner;
using namespace QmlDesigner::Internal;

SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
    QWidget(parent)
{
    m_ui.setupUi(this);
}

DesignerSettings SettingsPageWidget::settings() const
{
    DesignerSettings ds;
    ds.itemSpacing = m_ui.spinItemSpacing->value();
    ds.snapMargin = m_ui.spinSnapMargin->value();
    ds.enableContextPane = m_ui.textEditHelperCheckBox->isChecked();
    return ds;
}

void SettingsPageWidget::setSettings(const DesignerSettings &s)
{
    m_ui.spinItemSpacing->setValue(s.itemSpacing);
    m_ui.spinSnapMargin->setValue(s.snapMargin);
    m_ui.textEditHelperCheckBox->setChecked(s.enableContextPane);
}

QString SettingsPageWidget::searchKeywords() const
{
    QString rc;
    QTextStream(&rc)
            << ' ' << m_ui.snapMarginLabel
            << ' ' << m_ui.itemSpacingLabel;
    rc.remove(QLatin1Char('&'));
    return rc;
}

SettingsPage::SettingsPage() :
    m_widget(0)
{
}

QString SettingsPage::id() const
{
    return QLatin1String("QmlDesigner");
}

QString SettingsPage::displayName() const
{
    return tr("Qt Quick Designer");
}

QString SettingsPage::category() const
{
    return QLatin1String("Qt Quick");
}

QString SettingsPage::displayCategory() const
{
    return QCoreApplication::translate("Qt Quick", "Qt Quick");
}

QIcon SettingsPage::categoryIcon() const
{
    return QIcon(QLatin1String(Constants::SETTINGS_CATEGORY_QML_ICON));
}

QWidget *SettingsPage::createPage(QWidget *parent)
{
    m_widget = new SettingsPageWidget(parent);
    m_widget->setSettings(BauhausPlugin::pluginInstance()->settings());
    if (m_searchKeywords.isEmpty())
        m_searchKeywords = m_widget->searchKeywords();
    return m_widget;
}

void SettingsPage::apply()
{
    BauhausPlugin::pluginInstance()->setSettings(m_widget->settings());
}

bool SettingsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
<commit_msg>QuickToolBar: syncing settings properly<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** 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
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "designersettings.h"
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h"
#include "settingspage.h"

#include <QtCore/QTextStream>
#include <QtGui/QCheckBox>

using namespace QmlDesigner;
using namespace QmlDesigner::Internal;

SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
    QWidget(parent)
{
    m_ui.setupUi(this);
}

DesignerSettings SettingsPageWidget::settings() const
{
    DesignerSettings ds;
    ds.itemSpacing = m_ui.spinItemSpacing->value();
    ds.snapMargin = m_ui.spinSnapMargin->value();
    ds.enableContextPane = m_ui.textEditHelperCheckBox->isChecked();
    ds.pinContextPane = m_ui.textEditHelperCheckBoxPin->isChecked();
    return ds;
}

void SettingsPageWidget::setSettings(const DesignerSettings &s)
{
    m_ui.spinItemSpacing->setValue(s.itemSpacing);
    m_ui.spinSnapMargin->setValue(s.snapMargin);
    m_ui.textEditHelperCheckBox->setChecked(s.enableContextPane);
    m_ui.textEditHelperCheckBoxPin->setChecked(s.pinContextPane);
}

QString SettingsPageWidget::searchKeywords() const
{
    QString rc;
    QTextStream(&rc)
            << ' ' << m_ui.snapMarginLabel
            << ' ' << m_ui.itemSpacingLabel;
    rc.remove(QLatin1Char('&'));
    return rc;
}

SettingsPage::SettingsPage() :
    m_widget(0)
{
}

QString SettingsPage::id() const
{
    return QLatin1String("QmlDesigner");
}

QString SettingsPage::displayName() const
{
    return tr("Qt Quick Designer");
}

QString SettingsPage::category() const
{
    return QLatin1String("Qt Quick");
}

QString SettingsPage::displayCategory() const
{
    return QCoreApplication::translate("Qt Quick", "Qt Quick");
}

QIcon SettingsPage::categoryIcon() const
{
    return QIcon(QLatin1String(Constants::SETTINGS_CATEGORY_QML_ICON));
}

QWidget *SettingsPage::createPage(QWidget *parent)
{
    m_widget = new SettingsPageWidget(parent);
    m_widget->setSettings(BauhausPlugin::pluginInstance()->settings());
    if (m_searchKeywords.isEmpty())
        m_searchKeywords = m_widget->searchKeywords();
    return m_widget;
}

void SettingsPage::apply()
{
    BauhausPlugin::pluginInstance()->setSettings(m_widget->settings());
}

bool SettingsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010 Wes Hardaker <hardaker@users.sourceforge.net>
//

#include "AprsGatherer.h"

#include <QtGui/QPixmap>

#include "MarbleDirs.h"
#include "MarbleDebug.h"

using namespace Marble;

AprsGatherer::AprsGatherer( AprsSource *from,
                            QMap<QString, AprsObject *> *objects,
                            QMutex *mutex,
                            QString *filter )
    : m_source( from ),
      m_socket( 0 ),
      m_filter( filter ),
      m_running( true ),
      m_dumpOutput( false ),
      m_seenFrom( GeoAprsCoordinates::FromNowhere ),
      m_sourceName( ),
      m_mutex( mutex ),
      m_objects( objects )
{
    m_sourceName = from->sourceName();
    initMicETables();
}

AprsGatherer::AprsGatherer( QIODevice *from,
                            QMap<QString, AprsObject *> *objects,
                            QMutex *mutex,
                            QString *filter )
    : m_source( 0 ),
      m_socket( from ),
      m_filter( filter ),
      m_running( true ),
      m_dumpOutput( false ),
      m_seenFrom( GeoAprsCoordinates::FromNowhere ),
      m_sourceName( "unknown" ),
      m_mutex( mutex ),
      m_objects( objects )
{
    initMicETables();
}

void
AprsGatherer::run()
{
    char buf[4096];
    qint64 linelength;
    // one particular APRS packet sender can add data after the : ( sigh )
    QRegExp matcher( "^([0-9A-Z]+-*[0-9A-Z]*)>([^:]*):([!=@\\/])([0-9][0-9][0-9][0-9][0-9][0-9]|)([hz\\/]|)([0-9][0-9])([0-9][0-9]\\.[0-9][0-9])([NS])(.)([0-9][0-9][0-9])([0-9][0-9]\\.[0-9][0-9])([EW])(.)" );

    // mic-e formatted
    // 1: src
    // 2: dst
    // 3: routes
    // 4: longitude x 3
    // 5: speed and course x3
    // 6: symbol and symbol ID
    // 7: status text
    QRegExp mic_e_matcher( "^([0-9A-Z]+-*[0-9A-Z]*)>([^,:]*),*([^:]*):['`](...)(...)(..)(.*)" );

    // If a source can directly receive a signal (as opposed to
    // through a relay like the internet) will return true.  This
    // prevents accidentially coloring signals heard over some sources
    // as heard directly where it's never possible (such as over the
    // internet).
    bool canDoDirect = m_source->canDoDirect();

    while( m_running ) {

        if ( m_socket && !m_socket->isOpen() ) {
            // connection closed; attempt to reopen
            mDebug() << "aprs: socket closed; attempting to reopen";
            delete m_socket;
            m_socket = 0;
        }

        if ( !m_socket && m_source )
            m_socket = m_source->openSocket();

        if ( !m_socket ) {
            mDebug() << "aprs: failed to open socket from "
                     << m_sourceName.toLocal8Bit().data();
            sleep( 5 );
            continue;
        }

        // wait for data to read in
        if ( m_socket->bytesAvailable() <= 0 )
            // wait no longer than 1s
            if ( ! m_socket->waitForReadyRead( 1000 ) )
                continue; // continue to loop again on "not ready"

        // Read the line to parse
        linelength = m_socket->readLine( buf, sizeof( buf ) );

        // if we got 0 or less bytes this is probably an odd case; ask
        // the source what to do.
        m_source->checkReadReturn( linelength, &m_socket, this );

        if ( linelength <= 0 ) {
            // don't go into an infinite untimed loop of failed sockets
            sleep( 2 );
            continue;
        }

        if ( m_socket && m_filter != NULL ) {
            QMutexLocker locker( m_mutex );
            if ( m_filter->length() > 0 ) {
                m_socket->write( m_filter->toLocal8Bit().data(),
                                 m_filter->length() );
            }
        }

        // Parse the results
        QString line( buf );

        // Dump it out if we wanted it dumped
        if ( m_dumpOutput )
            mDebug() << "aprs: " << m_sourceName.toLocal8Bit().data()
                     << ": " << line;

        if ( matcher.indexIn( line ) != -1 ) {
            QString callSign  = matcher.cap( 1 );
            qreal latitude = matcher.cap( 6 ).toFloat() +
                ( matcher.cap( 7 ).toFloat()/60 );
            if ( matcher.cap( 8 ) == "S" )
                latitude = - latitude;

            qreal longitude = matcher.cap( 10 ).toFloat() +
                ( matcher.cap( 11 ).toFloat()/60 );
            if ( matcher.cap( 12 ) == "W" )
                longitude = - longitude;

            addObject( callSign, latitude, longitude, canDoDirect,
                       QString( matcher.cap( 2 ) ),
                       QChar( matcher.cap( 9 )[0] ),
                       QChar( matcher.cap( 13 )[0] ) );
        }
        else if ( mic_e_matcher.indexIn( line ) != -1 ) {
            // MIC-E formatted compressed packet
            QString myCall  = mic_e_matcher.cap( 1 );
            QString dstCall = mic_e_matcher.cap( 2 );

            qreal latitude =
                // hours
                m_dstCallDigits[dstCall[0]] * 10 +
                m_dstCallDigits[dstCall[1]] +

                // minutes
                ( qreal( m_dstCallDigits[dstCall[2]] * 10 +
                         m_dstCallDigits[dstCall[3]] ) +
                  qreal( m_dstCallDigits[dstCall[4]] ) / 10.0 +
                  qreal( m_dstCallDigits[dstCall[5]] ) / 100 ) / 60.0;

            if ( m_dstCallSouthEast[dstCall[4]] )
                latitude = - latitude;

            qreal longitude =
                calculateLongitude( QString ( mic_e_matcher.cap( 4 ) ),
                                    m_dstCallLongitudeOffset[dstCall[5]],
                                    m_dstCallSouthEast[dstCall[6]] );

//           mDebug() << "  MIC-E: " << line.toLocal8Bit().data();
//           mDebug() << "    lat: " << latitude;
//           mDebug() << "    lon: " << longitude;

            addObject( myCall, latitude, longitude, canDoDirect,
                       QString( mic_e_matcher.cap( 3 ) ),
                       QChar( mic_e_matcher.cap( 6 )[1] ),
                       QChar( mic_e_matcher.cap( 6 )[0] ) );
        }
        else {
            mDebug() << "aprs: UNPARSED: " << line;
        }

        // If the filter should be changed, send it out the socket
        if ( m_filter != NULL ) {
            QMutexLocker locker( m_mutex );
            if ( m_filter->length() > 0 ) {
                m_socket->write( m_filter->toLocal8Bit().data(),
                                 m_filter->length() );
            }
        }
    }
}

void
AprsGatherer::shutDown()
{
    m_running = false;
}

void
AprsGatherer::addObject( const QString &callSign,
                         qreal latitude, qreal longitude, bool canDoDirect,
                         const QString &routePath,
                         const QChar &symbolTable,
                         const QChar &symbolCode )
{
    AprsObject *foundObject = 0;
    QMutexLocker locker( m_mutex );

    GeoAprsCoordinates location( longitude, latitude, m_seenFrom );
    if ( canDoDirect ) {
        if ( !routePath.contains( QChar( '*' ) ) ) {
            location.addSeenFrom( GeoAprsCoordinates::Directly );
        }
    }

    if ( m_objects->contains( callSign ) ) {
        // we already have one for this callSign; just add the new
        // history item.
        ( *m_objects )[callSign]->setLocation( location );

        // mDebug() << "  is old";
    }
    else {
        foundObject = new AprsObject( location, callSign );
        QString s = m_pixmaps[QPair<QChar, QChar>( '/','*' )];
        foundObject->setPixmapId( m_pixmaps[QPair<QChar, QChar>( symbolTable,symbolCode )] );
        ( *m_objects )[callSign] = foundObject;
        mDebug() << "aprs:  new: " << callSign.toLocal8Bit().data();
        // foundObject->setTarget( "earth" );
    }
    //emit repaintNeeded( QRegion() );
}

#include "AprsGatherer.moc"

void AprsGatherer::initMicETables()
{
#include "AprsGatherer_mic_e.h"
}

qreal AprsGatherer::calculateLongitude( const QString &threeBytes, int offset,
                                         bool isEast )
{
    // otherwise known as "fun with funky encoding"
    qreal hours = threeBytes[0].toAscii() - 28 + offset;
    if ( 180 <= hours && hours <= 189 )
        hours -= 80;
    if ( 190 <= hours && hours <= 199 )
        hours -= 190;

    hours +=
        ( qreal( (threeBytes[1].toAscii() - 28 ) % 60 ) +
          ( qreal( threeBytes[2].toAscii() - 28 ) ) / 100 ) / 60.0;

    if ( ! isEast )
        hours = -hours;
    return hours;
}

void
AprsGatherer::setDumpOutput( bool to )
{
    m_dumpOutput = to;
}

bool
AprsGatherer::dumpOutput()
{
    return m_dumpOutput;
}

void
AprsGatherer::setSeenFrom( GeoAprsCoordinates::SeenFrom to )
{
    m_seenFrom = to;
}

GeoAprsCoordinates::SeenFrom
AprsGatherer::seenFrom()
{
    return m_seenFrom;
}

// gets around parent QThread protected sleep as our objects need a sleep
void
AprsGatherer::sleepFor(int seconds)
{
    sleep(seconds);
}
<commit_msg>small cleanup<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010 Wes Hardaker <hardaker@users.sourceforge.net>
//

#include "AprsGatherer.h"

#include <QtGui/QPixmap>

#include "MarbleDirs.h"
#include "MarbleDebug.h"

using namespace Marble;

AprsGatherer::AprsGatherer( AprsSource *from,
                            QMap<QString, AprsObject *> *objects,
                            QMutex *mutex,
                            QString *filter )
    : m_source( from ),
      m_socket( 0 ),
      m_filter( filter ),
      m_running( true ),
      m_dumpOutput( false ),
      m_seenFrom( GeoAprsCoordinates::FromNowhere ),
      m_sourceName( ),
      m_mutex( mutex ),
      m_objects( objects )
{
    m_sourceName = from->sourceName();
    initMicETables();
}

AprsGatherer::AprsGatherer( QIODevice *from,
                            QMap<QString, AprsObject *> *objects,
                            QMutex *mutex,
                            QString *filter )
    : m_source( 0 ),
      m_socket( from ),
      m_filter( filter ),
      m_running( true ),
      m_dumpOutput( false ),
      m_seenFrom( GeoAprsCoordinates::FromNowhere ),
      m_sourceName( "unknown" ),
      m_mutex( mutex ),
      m_objects( objects )
{
    initMicETables();
}

void
AprsGatherer::run()
{
    char buf[4096];
    qint64 linelength;
    // one particular APRS packet sender can add data after the : ( sigh )
    QRegExp matcher( "^([0-9A-Z]+-*[0-9A-Z]*)>([^:]*):([!=@\\/])([0-9][0-9][0-9][0-9][0-9][0-9]|)([hz\\/]|)([0-9][0-9])([0-9][0-9]\\.[0-9][0-9])([NS])(.)([0-9][0-9][0-9])([0-9][0-9]\\.[0-9][0-9])([EW])(.)" );

    // mic-e formatted
    // 1: src
    // 2: dst
    // 3: routes
    // 4: longitude x 3
    // 5: speed and course x3
    // 6: symbol and symbol ID
    // 7: status text
    QRegExp mic_e_matcher( "^([0-9A-Z]+-*[0-9A-Z]*)>([^,:]*),*([^:]*):['`](...)(...)(..)(.*)" );

    // If a source can directly receive a signal (as opposed to
    // through a relay like the internet) will return true.  This
    // prevents accidentially coloring signals heard over some sources
    // as heard directly where it's never possible (such as over the
    // internet).
    bool canDoDirect = m_source->canDoDirect();

    while( m_running ) {

        if ( m_socket && !m_socket->isOpen() ) {
            // connection closed; attempt to reopen
            mDebug() << "aprs: socket closed; attempting to reopen";
            delete m_socket;
            m_socket = 0;
        }

        if ( !m_socket && m_source )
            m_socket = m_source->openSocket();

        if ( !m_socket ) {
            mDebug() << "aprs: failed to open socket from "
                     << m_sourceName.toLocal8Bit().data();
            sleep( 5 );
            continue;
        }

        // wait for data to read in
        if ( m_socket->bytesAvailable() <= 0 )
            // wait no longer than 1s
            if ( ! m_socket->waitForReadyRead( 1000 ) )
                continue; // continue to loop again on "not ready"

        // Read the line to parse
        linelength = m_socket->readLine( buf, sizeof( buf ) );

        // if we got 0 or less bytes this is probably an odd case; ask
        // the source what to do.
        m_source->checkReadReturn( linelength, &m_socket, this );

        if ( linelength <= 0 ) {
            // don't go into an infinite untimed loop of failed sockets
            sleep( 2 );
            continue;
        }

        if ( m_socket && m_filter != NULL ) {
            QMutexLocker locker( m_mutex );
            if ( m_filter->length() > 0 ) {
                m_socket->write( m_filter->toLocal8Bit().data(),
                                 m_filter->length() );
            }
        }

        // Parse the results
        QString line( buf );

        // Dump it out if we wanted it dumped
        if ( m_dumpOutput )
            mDebug() << "aprs: " << m_sourceName.toLocal8Bit().data()
                     << ": " << line;

        if ( matcher.indexIn( line ) != -1 ) {
            QString callSign  = matcher.cap( 1 );
            qreal latitude = matcher.cap( 6 ).toFloat() +
                ( matcher.cap( 7 ).toFloat()/60 );
            if ( matcher.cap( 8 ) == "S" )
                latitude = - latitude;

            qreal longitude = matcher.cap( 10 ).toFloat() +
                ( matcher.cap( 11 ).toFloat()/60 );
            if ( matcher.cap( 12 ) == "W" )
                longitude = - longitude;

            addObject( callSign, latitude, longitude, canDoDirect,
                       QString( matcher.cap( 2 ) ),
                       QChar( matcher.cap( 9 )[0] ),
                       QChar( matcher.cap( 13 )[0] ) );
        }
        else if ( mic_e_matcher.indexIn( line ) != -1 ) {
            // MIC-E formatted compressed packet
            QString myCall  = mic_e_matcher.cap( 1 );
            QString dstCall = mic_e_matcher.cap( 2 );

            qreal latitude =
                // hours
                m_dstCallDigits[dstCall[0]] * 10 +
                m_dstCallDigits[dstCall[1]] +

                // minutes
                ( qreal( m_dstCallDigits[dstCall[2]] * 10 +
                         m_dstCallDigits[dstCall[3]] ) +
                  qreal( m_dstCallDigits[dstCall[4]] ) / 10.0 +
                  qreal( m_dstCallDigits[dstCall[5]] ) / 100 ) / 60.0;

            if ( m_dstCallSouthEast[dstCall[4]] )
                latitude = - latitude;

            qreal longitude =
                calculateLongitude( QString ( mic_e_matcher.cap( 4 ) ),
                                    m_dstCallLongitudeOffset[dstCall[5]],
                                    m_dstCallSouthEast[dstCall[6]] );

//           mDebug() << "  MIC-E: " << line.toLocal8Bit().data();
//           mDebug() << "    lat: " << latitude;
//           mDebug() << "    lon: " << longitude;

            addObject( myCall, latitude, longitude, canDoDirect,
                       QString( mic_e_matcher.cap( 3 ) ),
                       QChar( mic_e_matcher.cap( 6 )[1] ),
                       QChar( mic_e_matcher.cap( 6 )[0] ) );
        }
        else {
            mDebug() << "aprs: UNPARSED: " << line;
        }

        // If the filter should be changed, send it out the socket
        if ( m_filter != NULL ) {
            QMutexLocker locker( m_mutex );
            if ( m_filter->length() > 0 ) {
                m_socket->write( m_filter->toLocal8Bit().data(),
                                 m_filter->length() );
            }
        }
    }
}

void
AprsGatherer::shutDown()
{
    m_running = false;
}

void
AprsGatherer::addObject( const QString &callSign,
                         qreal latitude, qreal longitude, bool canDoDirect,
                         const QString &routePath,
                         const QChar &symbolTable,
                         const QChar &symbolCode )
{
    QMutexLocker locker( m_mutex );

    GeoAprsCoordinates location( longitude, latitude, m_seenFrom );
    if ( canDoDirect ) {
        if ( !routePath.contains( QChar( '*' ) ) ) {
            location.addSeenFrom( GeoAprsCoordinates::Directly );
        }
    }

    if ( m_objects->contains( callSign ) ) {
        // we already have one for this callSign; just add the new
        // history item.
        ( *m_objects )[callSign]->setLocation( location );
    }
    else {
        AprsObject *foundObject = new AprsObject( location, callSign );
        foundObject->setPixmapId( m_pixmaps[QPair<QChar, QChar>( symbolTable,symbolCode )] );
        ( *m_objects )[callSign] = foundObject;
        mDebug() << "aprs:  new: " << callSign.toLocal8Bit().data();
    }
}

void AprsGatherer::initMicETables()
{
#include "AprsGatherer_mic_e.h"
}

qreal AprsGatherer::calculateLongitude( const QString &threeBytes, int offset,
                                         bool isEast )
{
    // otherwise known as "fun with funky encoding"
    qreal hours = threeBytes[0].toAscii() - 28 + offset;
    if ( 180 <= hours && hours <= 189 )
        hours -= 80;
    if ( 190 <= hours && hours <= 199 )
        hours -= 190;

    hours +=
        ( qreal( (threeBytes[1].toAscii() - 28 ) % 60 ) +
          ( qreal( threeBytes[2].toAscii() - 28 ) ) / 100 ) / 60.0;

    if ( ! isEast )
        hours = -hours;
    return hours;
}

void
AprsGatherer::setDumpOutput( bool to )
{
    m_dumpOutput = to;
}

bool
AprsGatherer::dumpOutput()
{
    return m_dumpOutput;
}

void
AprsGatherer::setSeenFrom( GeoAprsCoordinates::SeenFrom to )
{
    m_seenFrom = to;
}

GeoAprsCoordinates::SeenFrom
AprsGatherer::seenFrom()
{
    return m_seenFrom;
}

// gets around parent QThread protected sleep as our objects need a sleep
void
AprsGatherer::sleepFor(int seconds)
{
    sleep(seconds);
}

#include "AprsGatherer.moc"
<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "signals.h"
#include "MonavPlugin.h"
#include "MonavRunner.h"
#include "MarbleDirs.h"
#include "MarbleDebug.h"
#include "GeoDataLatLonBox.h"
#include "GeoDataParser.h"
#include "GeoDataDocument.h"

#include <QtCore/QProcess>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QTimer>
#include <QtNetwork/QLocalSocket>

#include <unistd.h>

namespace Marble
{

class MonavMap
{
public:
    QDir m_directory;

    GeoDataLatLonBox m_boundingBox;

    QVector<GeoDataLinearRing> m_tiles;

    void setDirectory( const QDir &dir );

    bool containsPoint( const GeoDataCoordinates &point ) const;

private:
    void parseBoundingBox( const QFileInfo &file );
};

class MonavPluginPrivate
{
public:
    QDir m_mapDir;

    QVector<MonavMap> m_maps;

    bool m_ownsServer;

    MonavPluginPrivate();

    ~MonavPluginPrivate();

    bool startDaemon();

    void stopDaemon();

    bool isDaemonRunning() const;

    void loadMaps();

    static bool areaLessThan( const MonavMap &first, const MonavMap &second );

private:
    void loadMap( const QString &path );
};

void MonavMap::setDirectory( const QDir &dir )
{
    m_directory = dir;
    QFileInfo boundingBox( dir, dir.dirName() + ".kml" );
    if ( boundingBox.exists() ) {
        parseBoundingBox( boundingBox );
    } else {
        mDebug() << "No monav bounding box given for " << boundingBox.absoluteFilePath();
    }
}

void MonavMap::parseBoundingBox( const QFileInfo &file )
{
    GeoDataLineString points;
    QFile input( file.absoluteFilePath() );
    if ( input.open( QFile::ReadOnly ) ) {
        GeoDataParser parser( GeoData_KML );
        if ( !parser.read( &input ) ) {
            mDebug() << "Could not parse file: " << parser.errorString();
            return;
        }

        GeoDocument *doc = parser.releaseDocument();
        GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( doc );
        QVector<GeoDataPlacemark*> placemarks = document->placemarkList();
        if ( placemarks.size() == 1 ) {
            GeoDataPlacemark* placemark = placemarks.first();
            GeoDataMultiGeometry* geometry = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() );
            for ( int i=0; geometry && i<geometry->size(); ++i ) {
                GeoDataLinearRing* poly = dynamic_cast<GeoDataLinearRing*>( geometry->child( i ) );
                if ( poly ) {
                    for ( int j=0; j<poly->size(); ++j ) {
                        points << poly->at( j );
                    }
                    m_tiles.push_back( *poly );
                }
            }
        } else {
            mDebug() << "File " << file.absoluteFilePath() << " does not contain one placemark, but " << placemarks.size();
        }
    }
    m_boundingBox = points.latLonAltBox();
}

bool MonavMap::containsPoint( const GeoDataCoordinates &point ) const
{
    // If we do not have a bounding box at all, we err on the safe side
    if ( m_tiles.isEmpty() ) {
        return true;
    }

    // Quick check for performance reasons
    if ( !m_boundingBox.contains( point ) ) {
        return false;
    }

    // GeoDataLinearRing does a 3D check, but we only have 2D data for
    // the map bounding box. Therefore the 3D info of e.g. the GPS position
    // must be ignored.
    GeoDataCoordinates flatPosition = point;
    flatPosition.setAltitude( 0.0 );
    foreach( const GeoDataLinearRing &box, m_tiles ) {
        if ( box.contains( flatPosition ) ) {
            return true;
        }
    }

    return false;
}

MonavPluginPrivate::MonavPluginPrivate() : m_ownsServer( false )
{
    // nothing to do
}

MonavPluginPrivate::~MonavPluginPrivate()
{
    stopDaemon();
}

bool MonavPluginPrivate::isDaemonRunning() const
{
    QLocalSocket socket;
    socket.connectToServer( "MoNavD" );
    return socket.waitForConnected();
}

bool MonavPluginPrivate::startDaemon()
{
    if ( !isDaemonRunning() ) {
        QProcess process;
        if ( process.startDetached( "MoNavD" ) ) {
            m_ownsServer = true;

            // Give MoNavD up to one second to set up its server
            // Without that, the first route request would fail
            for ( int i = 0; i < 10; ++i ) {
                if ( isDaemonRunning() ) {
                    break;
                }
                usleep( 100 * 1000 );
            }

            return true;
        }

        return false;
    }

    return true;
}

void MonavPluginPrivate::stopDaemon()
{
    if ( m_ownsServer ) {
        m_ownsServer = false;
        QProcess process;
        process.startDetached( "MoNavD", QStringList() << "-t" );
    }
}

void MonavPluginPrivate::loadMaps()
{
    QString base = MarbleDirs::localPath() + "/maps/earth/monav/";
    loadMap( base );
    QDir::Filters filters = QDir::AllDirs | QDir::Readable | QDir::NoDotAndDotDot;
    QDirIterator::IteratorFlags flags = QDirIterator::Subdirectories | QDirIterator::FollowSymlinks;
    QDirIterator iter( base, filters, flags );
    while ( iter.hasNext() ) {
        iter.next();
        loadMap( iter.filePath() );
    }
    // Prefer maps where bounding boxes are known
    qSort( m_maps.begin(), m_maps.end(), MonavPluginPrivate::areaLessThan );
}

void MonavPluginPrivate::loadMap( const QString &path )
{
    QDir mapDir( path );
    QFileInfo pluginsFile( mapDir, "plugins.ini" );
    if ( pluginsFile.exists() ) {
        MonavMap map;
        map.setDirectory( mapDir );
        m_maps.append( map );
    }
}

bool MonavPluginPrivate::areaLessThan( const MonavMap &first, const MonavMap &second )
{
    if ( !first.m_tiles.isEmpty() && second.m_tiles.isEmpty() ) {
        return true;
    }

    if ( first.m_tiles.isEmpty() && !second.m_tiles.isEmpty() ) {
        return false;
    }

    qreal const areaOne = first.m_boundingBox.width() * first.m_boundingBox.height();
    qreal const areaTwo = second.m_boundingBox.width() * second.m_boundingBox.height();
    return areaOne < areaTwo;
}

MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent ), d( new MonavPluginPrivate )
{
    setSupportedCelestialBodies( QStringList() << "earth" );
    setCanWorkOffline( true );
    setName( tr( "Monav" ) );
    setNameId( "monav" );
    setDescription( tr( "Retrieves routes from monav" ) );
    setGuiString( tr( "Monav Routing" ) );

    // Check installation
    d->loadMaps();
    bool const haveMap = !d->m_maps.isEmpty();
    setCapabilities( haveMap ? Routing /*| ReverseGeocoding */ : None );
}

MonavPlugin::~MonavPlugin()
{
    delete d;
}

MarbleAbstractRunner* MonavPlugin::newRunner() const
{
    if ( !d->startDaemon() ) {
        mDebug() << "Failed to connect to MoNavD daemon";
    }

    return new MonavRunner( this );
}

QString MonavPlugin::mapDirectoryForRequest( RouteRequest* request ) const
{
    for ( int j=0; j<d->m_maps.size(); ++j ) {
        bool containsAllPoints = true;
        for ( int i = 0; i < request->size(); ++i ) {
            GeoDataCoordinates via = request->at( i );
            if ( !d->m_maps[j].containsPoint( via ) ) {
                containsAllPoints = false;
                break;
            }
        }

        if ( containsAllPoints ) {
            if ( j ) {
                // Subsequent route requests will likely be in the same country
                qSwap( d->m_maps[0], d->m_maps[j] );
            }
            // mDebug() << "Using " << d->m_maps.first().m_directory.dirName() << " as monav map";
            return d->m_maps.first().m_directory.absolutePath();
        }
    }

    return QString();
}

}

Q_EXPORT_PLUGIN2( MonavPlugin, Marble::MonavPlugin )

#include "MonavPlugin.moc"
<commit_msg>Replace unistd.h / usleep (not working under windows) with a qt solution.<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "signals.h"
#include "MonavPlugin.h"
#include "MonavRunner.h"
#include "MarbleDirs.h"
#include "MarbleDebug.h"
#include "GeoDataLatLonBox.h"
#include "GeoDataParser.h"
#include "GeoDataDocument.h"

#include <QtCore/QProcess>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QTimer>
#include <QtNetwork/QLocalSocket>
#include <QtCore/QThread>

namespace Marble
{

/** A helper class to have a portable sleep call */
class MonavWaiter : private QThread
{
public:
    static void msleep( unsigned long milliSeconds ) {
        QThread::msleep( milliSeconds );
    }

private:
    MonavWaiter();
    Q_DISABLE_COPY( MonavWaiter );
};

class MonavMap
{
public:
    QDir m_directory;

    GeoDataLatLonBox m_boundingBox;

    QVector<GeoDataLinearRing> m_tiles;

    void setDirectory( const QDir &dir );

    bool containsPoint( const GeoDataCoordinates &point ) const;

private:
    void parseBoundingBox( const QFileInfo &file );
};

class MonavPluginPrivate
{
public:
    QDir m_mapDir;

    QVector<MonavMap> m_maps;

    bool m_ownsServer;

    MonavPluginPrivate();

    ~MonavPluginPrivate();

    bool startDaemon();

    void stopDaemon();

    bool isDaemonRunning() const;

    void loadMaps();

    static bool areaLessThan( const MonavMap &first, const MonavMap &second );

private:
    void loadMap( const QString &path );
};

void MonavMap::setDirectory( const QDir &dir )
{
    m_directory = dir;
    QFileInfo boundingBox( dir, dir.dirName() + ".kml" );
    if ( boundingBox.exists() ) {
        parseBoundingBox( boundingBox );
    } else {
        mDebug() << "No monav bounding box given for " << boundingBox.absoluteFilePath();
    }
}

void MonavMap::parseBoundingBox( const QFileInfo &file )
{
    GeoDataLineString points;
    QFile input( file.absoluteFilePath() );
    if ( input.open( QFile::ReadOnly ) ) {
        GeoDataParser parser( GeoData_KML );
        if ( !parser.read( &input ) ) {
            mDebug() << "Could not parse file: " << parser.errorString();
            return;
        }

        GeoDocument *doc = parser.releaseDocument();
        GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( doc );
        QVector<GeoDataPlacemark*> placemarks = document->placemarkList();
        if ( placemarks.size() == 1 ) {
            GeoDataPlacemark* placemark = placemarks.first();
            GeoDataMultiGeometry* geometry = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() );
            for ( int i=0; geometry && i<geometry->size(); ++i ) {
                GeoDataLinearRing* poly = dynamic_cast<GeoDataLinearRing*>( geometry->child( i ) );
                if ( poly ) {
                    for ( int j=0; j<poly->size(); ++j ) {
                        points << poly->at( j );
                    }
                    m_tiles.push_back( *poly );
                }
            }
        } else {
            mDebug() << "File " << file.absoluteFilePath() << " does not contain one placemark, but " << placemarks.size();
        }
    }
    m_boundingBox = points.latLonAltBox();
}

bool MonavMap::containsPoint( const GeoDataCoordinates &point ) const
{
    // If we do not have a bounding box at all, we err on the safe side
    if ( m_tiles.isEmpty() ) {
        return true;
    }

    // Quick check for performance reasons
    if ( !m_boundingBox.contains( point ) ) {
        return false;
    }

    // GeoDataLinearRing does a 3D check, but we only have 2D data for
    // the map bounding box. Therefore the 3D info of e.g. the GPS position
    // must be ignored.
    GeoDataCoordinates flatPosition = point;
    flatPosition.setAltitude( 0.0 );
    foreach( const GeoDataLinearRing &box, m_tiles ) {
        if ( box.contains( flatPosition ) ) {
            return true;
        }
    }

    return false;
}

MonavPluginPrivate::MonavPluginPrivate() : m_ownsServer( false )
{
    // nothing to do
}

MonavPluginPrivate::~MonavPluginPrivate()
{
    stopDaemon();
}

bool MonavPluginPrivate::isDaemonRunning() const
{
    QLocalSocket socket;
    socket.connectToServer( "MoNavD" );
    return socket.waitForConnected();
}

bool MonavPluginPrivate::startDaemon()
{
    if ( !isDaemonRunning() ) {
        QProcess process;
        if ( process.startDetached( "MoNavD" ) ) {
            m_ownsServer = true;

            // Give MoNavD up to one second to set up its server
            // Without that, the first route request would fail
            for ( int i = 0; i < 10; ++i ) {
                if ( isDaemonRunning() ) {
                    break;
                }
                MonavWaiter::msleep( 100 );
            }

            return true;
        }

        return false;
    }

    return true;
}

void MonavPluginPrivate::stopDaemon()
{
    if ( m_ownsServer ) {
        m_ownsServer = false;
        QProcess process;
        process.startDetached( "MoNavD", QStringList() << "-t" );
    }
}

void MonavPluginPrivate::loadMaps()
{
    QString base = MarbleDirs::localPath() + "/maps/earth/monav/";
    loadMap( base );
    QDir::Filters filters = QDir::AllDirs | QDir::Readable | QDir::NoDotAndDotDot;
    QDirIterator::IteratorFlags flags = QDirIterator::Subdirectories | QDirIterator::FollowSymlinks;
    QDirIterator iter( base, filters, flags );
    while ( iter.hasNext() ) {
        iter.next();
        loadMap( iter.filePath() );
    }
    // Prefer maps where bounding boxes are known
    qSort( m_maps.begin(), m_maps.end(), MonavPluginPrivate::areaLessThan );
}

void MonavPluginPrivate::loadMap( const QString &path )
{
    QDir mapDir( path );
    QFileInfo pluginsFile( mapDir, "plugins.ini" );
    if ( pluginsFile.exists() ) {
        MonavMap map;
        map.setDirectory( mapDir );
        m_maps.append( map );
    }
}

bool MonavPluginPrivate::areaLessThan( const MonavMap &first, const MonavMap &second )
{
    if ( !first.m_tiles.isEmpty() && second.m_tiles.isEmpty() ) {
        return true;
    }

    if ( first.m_tiles.isEmpty() && !second.m_tiles.isEmpty() ) {
        return false;
    }

    qreal const areaOne = first.m_boundingBox.width() * first.m_boundingBox.height();
    qreal const areaTwo = second.m_boundingBox.width() * second.m_boundingBox.height();
    return areaOne < areaTwo;
}

MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent ), d( new MonavPluginPrivate )
{
    setSupportedCelestialBodies( QStringList() << "earth" );
    setCanWorkOffline( true );
    setName( tr( "Monav" ) );
    setNameId( "monav" );
    setDescription( tr( "Retrieves routes from monav" ) );
    setGuiString( tr( "Monav Routing" ) );

    // Check installation
    d->loadMaps();
    bool const haveMap = !d->m_maps.isEmpty();
    setCapabilities( haveMap ? Routing /*| ReverseGeocoding */ : None );
}

MonavPlugin::~MonavPlugin()
{
    delete d;
}

MarbleAbstractRunner* MonavPlugin::newRunner() const
{
    if ( !d->startDaemon() ) {
        mDebug() << "Failed to connect to MoNavD daemon";
    }

    return new MonavRunner( this );
}

QString MonavPlugin::mapDirectoryForRequest( RouteRequest* request ) const
{
    for ( int j=0; j<d->m_maps.size(); ++j ) {
        bool containsAllPoints = true;
        for ( int i = 0; i < request->size(); ++i ) {
            GeoDataCoordinates via = request->at( i );
            if ( !d->m_maps[j].containsPoint( via ) ) {
                containsAllPoints = false;
                break;
            }
        }

        if ( containsAllPoints ) {
            if ( j ) {
                // Subsequent route requests will likely be in the same country
                qSwap( d->m_maps[0], d->m_maps[j] );
            }
            // mDebug() << "Using " << d->m_maps.first().m_directory.dirName() << " as monav map";
            return d->m_maps.first().m_directory.absolutePath();
        }
    }

    return QString();
}

}

Q_EXPORT_PLUGIN2( MonavPlugin, Marble::MonavPlugin )

#include "MonavPlugin.moc"
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

#include "submiteditorfile.h"

using namespace VcsBase;
using namespace VcsBase::Internal;

/*!
    \class VcsBase::Internal::SubmitEditorFile

    \brief A non-saveable IDocument for submit editor files.
*/

SubmitEditorFile::SubmitEditorFile(const QString &mimeType, QObject *parent) :
    Core::IDocument(parent),
    m_mimeType(mimeType),
    m_modified(false)
{
}

void SubmitEditorFile::rename(const QString &newName)
{
    Q_UNUSED(newName);
    // We can't be renamed
    return;
}

void SubmitEditorFile::setFileName(const QString &name)
{
     m_fileName = name;
     emit changed();
}

void SubmitEditorFile::setModified(bool modified)
{
    if (m_modified == modified)
        return;
    m_modified = modified;
    emit changed();
}

bool SubmitEditorFile::save(QString *errorString, const QString &fileName, bool autoSave)
{
    emit saveMe(errorString, fileName, autoSave);
    if (!errorString->isEmpty())
        return false;
    emit changed();
    return true;
}

QString SubmitEditorFile::mimeType() const
{
    return m_mimeType;
}

Core::IDocument::ReloadBehavior SubmitEditorFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
    Q_UNUSED(state)
    Q_UNUSED(type)
    return BehaviorSilent;
}

bool SubmitEditorFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
{
    Q_UNUSED(errorString)
    Q_UNUSED(flag)
    Q_UNUSED(type)
    return true;
}
<commit_msg>Avoid sending signals if nothing changed<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

#include "submiteditorfile.h"

using namespace VcsBase;
using namespace VcsBase::Internal;

/*!
    \class VcsBase::Internal::SubmitEditorFile

    \brief A non-saveable IDocument for submit editor files.
*/

SubmitEditorFile::SubmitEditorFile(const QString &mimeType, QObject *parent) :
    Core::IDocument(parent),
    m_mimeType(mimeType),
    m_modified(false)
{
}

void SubmitEditorFile::rename(const QString &newName)
{
    Q_UNUSED(newName);
    // We can't be renamed
    return;
}

void SubmitEditorFile::setFileName(const QString &name)
{
    if (m_fileName == name)
        return;
    m_fileName = name;
    emit changed();
}

void SubmitEditorFile::setModified(bool modified)
{
    if (m_modified == modified)
        return;
    m_modified = modified;
    emit changed();
}

bool SubmitEditorFile::save(QString *errorString, const QString &fileName, bool autoSave)
{
    emit saveMe(errorString, fileName, autoSave);
    if (!errorString->isEmpty())
        return false;
    emit changed();
    return true;
}

QString SubmitEditorFile::mimeType() const
{
    return m_mimeType;
}

Core::IDocument::ReloadBehavior SubmitEditorFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
    Q_UNUSED(state)
    Q_UNUSED(type)
    return BehaviorSilent;
}

bool SubmitEditorFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
{
    Q_UNUSED(errorString)
    Q_UNUSED(flag)
    Q_UNUSED(type)
    return true;
}
<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 - 2011 Emmanuel Benazera <ebenazer@seeks-project.info>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_bing.h"
#include "miscutil.h"

#include <strings.h>
#include <iostream>

using sp::miscutil;

namespace seeks_plugins
{
  std::string se_parser_bing::_bing_stupid[2] =
  { "Document title", "Titre du document / Document title" };

  se_parser_bing::se_parser_bing(const std::string &url)
    :se_parser(url),_h1_sr_flag(false),_results_flag(false),_h3_flag(false),
    _link_flag(false),_p_flag(false),_cite_flag(false),_cached_flag(false)
  {
  }

  se_parser_bing::~se_parser_bing()
  {
  }

  void se_parser_bing::start_element(parser_context *pc,
  const xmlChar *name,
  const xmlChar **attributes)
  {
    const char *tag = (const char*)name;

    if (strcasecmp(tag,"h1") == 0)
      {
        _h1_sr_flag = true;
      }
    if (strcasecmp(tag,"div") == 0)
      {
        const char *a_class = se_parser::get_attribute((const char**)attributes,"class");

        if (a_class && strcasecmp(a_class,"sb_tlst") == 0)
          {
            if (pc->_snippets->empty())
              _results_flag = true;

            // assert previous snippet if any.
            if (pc->_current_snippet)
              {
                if (pc->_current_snippet->_title.empty()  // consider the parsing did fail on the snippet.
                || pc->_current_snippet->_url.empty()
                || pc->_current_snippet->_summary.empty()
                || pc->_current_snippet->_cite.empty())
                  {
                    delete pc->_current_snippet;
                    pc->_current_snippet = NULL;
                    _count--;
                    pc->_snippets->pop_back();
                  }
              }

            // create new snippet.
            search_snippet *sp = new search_snippet(_count+1);
            _count++;
            sp->_engine = feeds("bing",_url);
            pc->_current_snippet = sp;
            pc->_snippets->push_back(pc->_current_snippet);

            _cached_flag = false; // in case previous snippet did not close the cached flag.
          }
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"h3") == 0)
      {
        _h3_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && _h3_flag && strcasecmp(tag,"a") == 0)
      {
        _link_flag = true;
        const char *a_link = se_parser::get_attribute((const char**)attributes,"href");

        if (a_link)
          _link = std::string(a_link);
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"p") == 0)
      {
        _p_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"cite") == 0)
      {
        _cite_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && _cached_flag && strcasecmp(tag,"a") == 0) // may not be very robust...
      {
        _cached_flag = false;
        const char *a_link = se_parser::get_attribute((const char**)attributes,"href");
        if (a_link)
          pc->_current_snippet->_cached = std::string(a_link);
      }
  }

  void se_parser_bing::characters(parser_context *pc,
  const xmlChar *chars,
  int length)
  {
    handle_characters(pc, chars, length);
  }

  void se_parser_bing::cdata(parser_context *pc,
  const xmlChar *chars,
  int length)
  {
    handle_characters(pc, chars, length);
  }

  void se_parser_bing::handle_characters(parser_context *pc,
  const xmlChar *chars,
  int length)
  {
    if (_p_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        miscutil::replace_in_string(a_chars,"-"," ");
        miscutil::replace_in_string(a_chars,se_parser_bing::_bing_stupid[1],"");
        miscutil::replace_in_string(a_chars,se_parser_bing::_bing_stupid[0],"");
        _summary += a_chars;
      }
    else if (_cite_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        //miscutil::replace_in_string(a_chars,"-"," ");
        _cite += a_chars;
      }
    else if (_h3_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        _h3 += a_chars;
      }

  }

  void se_parser_bing::end_element(parser_context *pc,
  const xmlChar *name)
  {
    const char *tag = (const char*) name;

    if (!_results_flag)
      return;

    if (_h1_sr_flag && _h3_flag && strcasecmp(tag,"a") == 0)
      {
        _link_flag = false;
        pc->_current_snippet->set_url(_link);
        _link = "";
      }
    else if (_p_flag && strcasecmp(tag,"p") == 0)
      {
        _p_flag = false;
        pc->_current_snippet->set_summary(_summary);
        _summary = "";
      }
    else if (_cite_flag && strcasecmp(tag,"cite") == 0)
      {
        _cite_flag = false;
        pc->_current_snippet->set_cite(_cite);
        _cite = "";
        _cached_flag = true; // getting ready for the Cached link, if any.
      }
    else if (_h3_flag && strcasecmp(tag,"h3") == 0)
      {
        _h3_flag = false;
        pc->_current_snippet->set_title(_h3);
        _h3 = "";
      }

  }

} /* end of namespace. */
<commit_msg>fixed bug in Bing parser, rendering advertizing instead of results. refs #392<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 - 2011 Emmanuel Benazera <ebenazer@seeks-project.info>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_bing.h"
#include "miscutil.h"

#include <strings.h>
#include <iostream>

using sp::miscutil;

namespace seeks_plugins
{
  std::string se_parser_bing::_bing_stupid[2] =
  { "Document title", "Titre du document / Document title" };

  se_parser_bing::se_parser_bing(const std::string &url)
    :se_parser(url),_h1_sr_flag(false),_results_flag(false),_h3_flag(false),
     _link_flag(false),_p_flag(false),_cite_flag(false),_cached_flag(false)
  {
  }

  se_parser_bing::~se_parser_bing()
  {
  }

  void se_parser_bing::start_element(parser_context *pc,
                                     const xmlChar *name,
                                     const xmlChar **attributes)
  {
    const char *tag = (const char*)name;

    if (strcasecmp(tag,"h1") == 0)
      {
        _h1_sr_flag = true;
      }
    if (strcasecmp(tag,"div") == 0)
      {
        const char *a_class = se_parser::get_attribute((const char**)attributes,"class");

        if (a_class && strcasecmp(a_class,"sb_tlst") == 0)
          {
            if (pc->_snippets->empty())
              _results_flag = true;

            // assert previous snippet if any.
            if (pc->_current_snippet)
              {
                if (pc->_current_snippet->_title.empty()  // consider the parsing did fail on the snippet.
                    || pc->_current_snippet->_url.empty()
                    || pc->_current_snippet->_summary.empty()
                    || pc->_current_snippet->_cite.empty())
                  {
                    delete pc->_current_snippet;
                    pc->_current_snippet = NULL;
                    _count--;
                    pc->_snippets->pop_back();
                  }
              }

            // create new snippet.
            search_snippet *sp = new search_snippet(_count+1);
            _count++;
            sp->_engine = feeds("bing",_url);
            pc->_current_snippet = sp;
            pc->_snippets->push_back(pc->_current_snippet);

            _cached_flag = false; // in case previous snippet did not close the cached flag.
          }
      }
    else if (_results_flag && strcasecmp(tag,"h2") == 0)
      {
        _results_flag = false;
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"h3") == 0)
      {
        _h3_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && _h3_flag && strcasecmp(tag,"a") == 0)
      {
        _link_flag = true;
        const char *a_link = se_parser::get_attribute((const char**)attributes,"href");

        if (a_link)
          _link = std::string(a_link);
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"p") == 0)
      {
        _p_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && strcasecmp(tag,"cite") == 0)
      {
        _cite_flag = true;
      }
    else if (_results_flag && _h1_sr_flag && _cached_flag && strcasecmp(tag,"a") == 0) // may not be very robust...
      {
        _cached_flag = false;
        const char *a_link = se_parser::get_attribute((const char**)attributes,"href");
        if (a_link)
          pc->_current_snippet->_cached = std::string(a_link);
      }
  }

  void se_parser_bing::characters(parser_context *pc,
                                  const xmlChar *chars,
                                  int length)
  {
    handle_characters(pc, chars, length);
  }

  void se_parser_bing::cdata(parser_context *pc,
                             const xmlChar *chars,
                             int length)
  {
    handle_characters(pc, chars, length);
  }

  void se_parser_bing::handle_characters(parser_context *pc,
                                         const xmlChar *chars,
                                         int length)
  {
    if (_p_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        miscutil::replace_in_string(a_chars,"-"," ");
        miscutil::replace_in_string(a_chars,se_parser_bing::_bing_stupid[1],"");
        miscutil::replace_in_string(a_chars,se_parser_bing::_bing_stupid[0],"");
        _summary += a_chars;
      }
    else if (_cite_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        //miscutil::replace_in_string(a_chars,"-"," ");
        _cite += a_chars;
      }
    else if (_h3_flag)
      {
        std::string a_chars = std::string((char*)chars);
        miscutil::replace_in_string(a_chars,"\n"," ");
        miscutil::replace_in_string(a_chars,"\r"," ");
        _h3 += a_chars;
      }

  }

  void se_parser_bing::end_element(parser_context *pc,
                                   const xmlChar *name)
  {
    const char *tag = (const char*) name;

    if (!_results_flag)
      return;

    if (_h1_sr_flag && _h3_flag && strcasecmp(tag,"a") == 0)
      {
        _link_flag = false;
        pc->_current_snippet->set_url(_link);
        _link = "";
      }
    else if (_p_flag && strcasecmp(tag,"p") == 0)
      {
        _p_flag = false;
        pc->_current_snippet->set_summary(_summary);
        _summary = "";
      }
    else if (_cite_flag && strcasecmp(tag,"cite") == 0)
      {
        _cite_flag = false;
        pc->_current_snippet->set_cite(_cite);
        _cite = "";
        _cached_flag = true; // getting ready for the Cached link, if any.
      }
    else if (_h3_flag && strcasecmp(tag,"h3") == 0)
      {
        _h3_flag = false;
        pc->_current_snippet->set_title(_h3);
        _h3 = "";
      }

  }

} /* end of namespace. */
<|endoftext|>