<commit_before>/*
 *   Copyright 2012 Coherent Theory LLC
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, 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 General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "bodegamodel.h"

#include "session.h"
#include "channelsjob.h"

#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>

using namespace Bodega;

static const int DEFAULT_PAGE_SIZE = 50;

class Node
{
public:
    Node(ChannelInfo channelInfo, AssetInfo assetInfo, Node *parent = 0);
    ~Node();

    void appendChild(Node *child);

    Node *child(int row);
    int childCount() const;
    int row() const;
    Node *parent();

    bool isChannel() const;
    const AssetInfo& assetInfo() const;
    const ChannelInfo& channelInfo() const;

    void setCompletelyPopulated(bool complete);
    bool isCompletelyPopulated() const;

    int lastFetchedOffset() const;
    void setLastFetchedOffset(int offset);

private:
    QList<Node*> m_childNodes;
    Node *m_parentNode;
    ChannelInfo m_channelInfo;
    AssetInfo m_assetInfo;
    bool m_completelyPopulated;
    int m_lastFetchedOffset;
};

Node::Node(ChannelInfo channelInfo, AssetInfo assetInfo, Node *parent)
    : m_parentNode(parent),
      m_assetInfo(assetInfo),
      m_channelInfo(channelInfo),
      m_completelyPopulated(false),
      m_lastFetchedOffset(0)
{
}

Node::~Node()
{
    qDeleteAll(m_childNodes);
}

void Node::appendChild(Node *item)
{
    m_childNodes.append(item);
}

Node *Node::child(int row)
{
    return m_childNodes.value(row);
}

int Node::childCount() const
{
    return m_childNodes.count();
}

Node *Node::parent()
{
    return m_parentNode;
}

int Node::row() const
{
    if (m_parentNode)
        return m_parentNode->m_childNodes.indexOf(const_cast<Node*>(this));

    return 0;
}

const AssetInfo &Node::assetInfo() const
{
    return m_assetInfo;
}

const ChannelInfo &Node::channelInfo() const
{
    return m_channelInfo;
}

bool Node::isChannel() const
{
    return !m_channelInfo.id.isEmpty();
}

void Node::setCompletelyPopulated(bool complete)
{
    m_completelyPopulated = complete;
}

bool Node::isCompletelyPopulated() const
{
    return m_completelyPopulated;
}

int Node::lastFetchedOffset() const
{
    return m_lastFetchedOffset;
}

void Node::setLastFetchedOffset(int offset)
{
    m_lastFetchedOffset = offset;
}

class Model::Private {
public:
    Private()
    {}
    void init(Model *parent);
    void channelsJobFinished(Bodega::NetworkJob *job);
    void reloadFromNetwork();

    Model *q;
    Session *session;
    QString topChannel;
    QString searchQuery;
    Node *topNode;

    //NEVER access those values outside channelsJobFinished(), Session will delete them
    //QPersistentModelIndex parent of this ChannelsJob 1/1 correspondence with Node
    QHash<ChannelsJob *, QPersistentModelIndex> indexForJobs;
    //job correspondednt to this  index
    QHash<QPersistentModelIndex, QList<ChannelsJob *> > jobsForIndex;
};

void Model::Private::init(Model *parent)
{
    q = parent;
    ChannelInfo rootChanInfo;
    AssetInfo rootAssetInfo;
    topNode = new Node(rootChanInfo, rootAssetInfo, 0);
    session = 0;
}

void Model::Private::channelsJobFinished(Bodega::NetworkJob *job)
{
    ChannelsJob *channelsJob = qobject_cast<ChannelsJob *>(job);
    Q_ASSERT(channelsJob);
    Q_ASSERT(indexForJobs.contains(channelsJob));

    QPersistentModelIndex idx = indexForJobs.value(channelsJob);

    //remove from bookkeeping
    indexForJobs.remove(channelsJob);
    jobsForIndex[idx].removeAll(channelsJob);
    if (jobsForIndex[idx].isEmpty()) {
        jobsForIndex.remove(idx);
    }

    if (channelsJob->channels().isEmpty() && channelsJob->assets().isEmpty()) {
        return;
    }

    Node *node;
    if (idx.isValid()) {
        node = static_cast<Node*>(idx.internalPointer());
    } else {
        node = topNode;
    }
    node->setCompletelyPopulated(!channelsJob->hasMoreAssets());
    node->setLastFetchedOffset(channelsJob->offset() + DEFAULT_PAGE_SIZE);

    if (!channelsJob->channels().isEmpty()) {
        q->beginInsertRows(idx, node->childCount(),
                           node->childCount() + channelsJob->channels().count()-1);
        AssetInfo dummyAssetInfo;
        foreach (const ChannelInfo &info, channelsJob->channels()) {
            node->appendChild(new Node(info, dummyAssetInfo, node));
        }
        q->endInsertRows();
    }

    if (!channelsJob->assets().isEmpty()) {
        q->beginInsertRows(idx, node->childCount(),
                           node->childCount() + channelsJob->assets().count()-1);
        ChannelInfo dummyChannelInfo;
        foreach (const AssetInfo &info, channelsJob->assets()) {
            node->appendChild(new Node(dummyChannelInfo, info, node));
        }
        q->endInsertRows();
    }
}

void Model::Private::reloadFromNetwork()
{
    if (!session || !session->isAuthenticated()) {
        return;
    }

    //FIXME: not safe, at this point most of jobs will be deleted by session
    foreach (const QList<ChannelsJob *> &list, jobsForIndex) {
        foreach (ChannelsJob *job, list) {
            disconnect(job, 0, q, 0);
        }
    }
    jobsForIndex.clear();
    indexForJobs.clear();

    //reset topnode, remove all the contents of the model
    q->beginResetModel();
    delete topNode;
    ChannelInfo rootChanInfo;
    AssetInfo rootAssetInfo;
    topNode = new Node(rootChanInfo, rootAssetInfo, 0);
    q->endResetModel();

    ChannelsJob *channelsJob;
    if (searchQuery.isEmpty()) {
        channelsJob = session->channels(topChannel, 0, DEFAULT_PAGE_SIZE);
    } else {
        channelsJob = session->search(searchQuery, topChannel,
                                      0, DEFAULT_PAGE_SIZE);
    }

    connect(channelsJob, SIGNAL(jobFinished(Bodega::NetworkJob *)),
            q, SLOT(channelsJobFinished(Bodega::NetworkJob *)));
    //TODO: manage errors

    QPersistentModelIndex idx = QPersistentModelIndex(QModelIndex());
    indexForJobs[channelsJob] = idx;
    jobsForIndex[idx] << channelsJob;
}

Model::Model(QObject *parent)
    : QAbstractItemModel(parent),
      d(new Private)
{
    d->init(this);
    // set the role names based on the values of the DisplayRoles enum for
    //  the sake of QML
    QHash<int, QByteArray> roles;
    roles.insert(Qt::DisplayRole, "DisplayRole");
    roles.insert(Qt::DecorationRole, "DecorationRole");
    QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("DisplayRoles"));
    for (int i = 0; i < e.keyCount(); ++i) {
        roles.insert(e.value(i), e.key(i));
    }
    setRoleNames(roles);
}

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

bool Model::canFetchMore(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return false;
    }

    Node *node = static_cast<Node*>(parent.internalPointer());
    return node->isChannel() && !node->isCompletelyPopulated() &&
            !d->jobsForIndex.contains(parent);
}

int Model::columnCount(const QModelIndex &parent) const
{
    return 1;
}

QVariant Model::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

    Node *node = static_cast<Node*>(index.internalPointer());

    if (node->isChannel()) {
        switch (role) {
        case Qt::DisplayRole:
            return node->channelInfo().name;
        case ChannelIdRole:
            return node->channelInfo().id;
        case ChannelNameRole:
            return node->channelInfo().name;
        case ChannelDescriptionRole:
            return node->channelInfo().description;
        case ChannelAssetCountRole:
            return node->channelInfo().assetCount;
        case ImageTinyRole:
            return node->channelInfo().images.value(Bodega::ImageTiny);
        case ImageSmallRole:
            return node->channelInfo().images.value(Bodega::ImageSmall);
        case ImageMediumRole:
            return node->channelInfo().images.value(Bodega::ImageMedium);
        case ImageLargeRole:
            return node->channelInfo().images.value(Bodega::ImageLarge);
        case ImageHugeRole:
            return node->channelInfo().images.value(Bodega::ImageHuge);
        case ImagePreviewsRole:
            return node->channelInfo().images.value(Bodega::ImagePreviews);
        default:
            return QVariant();
        }
    } else {
        switch (role) {
        case Qt::DisplayRole:
            return node->assetInfo().name;
        case AssetIdRole:
            return node->assetInfo().id;
        case AssetNameRole:
            return node->assetInfo().name;
        case AssetVersionRole:
            return node->assetInfo().version;
        case AssetFilenameRole:
            return node->assetInfo().filename;
        case ImageTinyRole:
            return node->assetInfo().images.value(Bodega::ImageTiny);
        case ImageSmallRole:
            return node->assetInfo().images.value(Bodega::ImageSmall);
        case ImageMediumRole:
            return node->assetInfo().images.value(Bodega::ImageMedium);
        case ImageLargeRole:
            return node->assetInfo().images.value(Bodega::ImageLarge);
        case ImageHugeRole:
            return node->assetInfo().images.value(Bodega::ImageHuge);
        case ImagePreviewsRole:
            return node->assetInfo().images.value(Bodega::ImagePreviews);
        case AssetDescriptionRole:
            return node->assetInfo().description;
        case AssetPointsRole:
            return node->assetInfo().points;
        default:
            return QVariant();
        }
    }
}

void Model::fetchMore(const QModelIndex &parent)
{
    if (!parent.isValid() || !d->session || !canFetchMore(parent) ||
        !d->session->isAuthenticated()) {
        return;
    }

    QPersistentModelIndex idx = QPersistentModelIndex(parent);
    Node *node = static_cast<Node*>(idx.internalPointer());

    ChannelsJob *channelsJob;
    if (d->searchQuery.isEmpty()) {
        channelsJob = d->session->channels(node->channelInfo().id,
                                           node->lastFetchedOffset(),
                                           DEFAULT_PAGE_SIZE);
    } else {
        channelsJob = d->session->search(d->searchQuery,
                                         d->topChannel,
                                         node->lastFetchedOffset(),
                                         DEFAULT_PAGE_SIZE);
    }
    connect(channelsJob, SIGNAL(jobFinished(Bodega::NetworkJob *)),
            this, SLOT(channelsJobFinished(Bodega::NetworkJob *)));
    //TODO: manage errors

    d->indexForJobs[channelsJob] = idx;
    d->jobsForIndex[idx] << channelsJob;
}

Qt::ItemFlags Model::flags(const QModelIndex &index) const
{
    if (index.isValid()) {
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    } else {
        return Qt::NoItemFlags;
    }
}

bool Model::hasChildren(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return true;
    }
    return static_cast<Node*>(parent.internalPointer())->isChannel();
}

QVariant Model::headerData(int section, Qt::Orientation orientation,
                           int role) const
{
    return QVariant();
}

QModelIndex Model::index(int row, int column,
                         const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent)) {
        return QModelIndex();
    }

    Node *parentNode;

    if (!parent.isValid()) {
        parentNode = d->topNode;
    } else {
        parentNode = static_cast<Node*>(parent.internalPointer());
    }

    Node *childNode = parentNode->child(row);
    if (childNode) {
        return createIndex(row, column, childNode);
    } else {
        return QModelIndex();
    }
}

QMap<int, QVariant> Model::itemData(const QModelIndex &index) const
{
    return QMap<int, QVariant>();
}

QModelIndex Model::parent(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    Node *childNode = static_cast<Node*>(index.internalPointer());
    Node *parentNode = childNode->parent();

    if (parentNode == d->topNode) {
        return QModelIndex();
    }

    return createIndex(parentNode->row(), 0, parentNode);
}

int Model::rowCount(const QModelIndex &parent) const
{
    Node *parentNode;
    if (parent.column() > 0) {
        return 0;
    }

    if (!parent.isValid()) {
        parentNode = d->topNode;
    } else {
        parentNode = static_cast<Node*>(parent.internalPointer());
    }

    return parentNode->childCount();
}

void Model::setSession(Session *session)
{
    if (session == d->session) {
        return;
    }

    if (d->session) {
        //not connected directly, so disconnect everything
        //delete d->channelsJob;
        //TODO: delete all the jobs
    }

    d->session = session;
    connect(d->session, SIGNAL(authenticated(bool)),
            this, SLOT(reloadFromNetwork()));

    d->reloadFromNetwork();
}

Session *Model::session() const
{
    return d->session;
}

void Model::setTopChannel(const QString &topChannel)
{
    if (d->topChannel == topChannel) {
        return;
    }

    d->topChannel = topChannel;

    if (!d->session) {
        return;
    }

    //Search queries win against channel listing
    if (!d->searchQuery.isEmpty()) {
        d->reloadFromNetwork();
    }
    emit topChannelChanged();
}

QString Model::topChannel() const
{
    return d->topChannel;
}

void Model::setSearchQuery(const QString &query)
{
    if (d->searchQuery == query) {
        return;
    }

    d->searchQuery = query;

    if (!d->session) {
        return;
    }

    d->reloadFromNetwork();
    emit searchQueryChanged();
}

QString Model::searchQuery() const
{
    return d->searchQuery;
}

#include "bodegamodel.moc"
<commit_msg>handle setting a second session a little more gracefully<commit_after>/*
 *   Copyright 2012 Coherent Theory LLC
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, 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 General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "bodegamodel.h"

#include "session.h"
#include "channelsjob.h"

#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>

using namespace Bodega;

static const int DEFAULT_PAGE_SIZE = 50;

class Node
{
public:
    Node(ChannelInfo channelInfo, AssetInfo assetInfo, Node *parent = 0);
    ~Node();

    void appendChild(Node *child);

    Node *child(int row);
    int childCount() const;
    int row() const;
    Node *parent();

    bool isChannel() const;
    const AssetInfo& assetInfo() const;
    const ChannelInfo& channelInfo() const;

    void setCompletelyPopulated(bool complete);
    bool isCompletelyPopulated() const;

    int lastFetchedOffset() const;
    void setLastFetchedOffset(int offset);

private:
    QList<Node*> m_childNodes;
    Node *m_parentNode;
    ChannelInfo m_channelInfo;
    AssetInfo m_assetInfo;
    bool m_completelyPopulated;
    int m_lastFetchedOffset;
};

Node::Node(ChannelInfo channelInfo, AssetInfo assetInfo, Node *parent)
    : m_parentNode(parent),
      m_assetInfo(assetInfo),
      m_channelInfo(channelInfo),
      m_completelyPopulated(false),
      m_lastFetchedOffset(0)
{
}

Node::~Node()
{
    qDeleteAll(m_childNodes);
}

void Node::appendChild(Node *item)
{
    m_childNodes.append(item);
}

Node *Node::child(int row)
{
    return m_childNodes.value(row);
}

int Node::childCount() const
{
    return m_childNodes.count();
}

Node *Node::parent()
{
    return m_parentNode;
}

int Node::row() const
{
    if (m_parentNode) {
        return m_parentNode->m_childNodes.indexOf(const_cast<Node*>(this));
    }

    return 0;
}

const AssetInfo &Node::assetInfo() const
{
    return m_assetInfo;
}

const ChannelInfo &Node::channelInfo() const
{
    return m_channelInfo;
}

bool Node::isChannel() const
{
    return !m_channelInfo.id.isEmpty();
}

void Node::setCompletelyPopulated(bool complete)
{
    m_completelyPopulated = complete;
}

bool Node::isCompletelyPopulated() const
{
    return m_completelyPopulated;
}

int Node::lastFetchedOffset() const
{
    return m_lastFetchedOffset;
}

void Node::setLastFetchedOffset(int offset)
{
    m_lastFetchedOffset = offset;
}

class Model::Private {
public:
    Private(Model *parent) :
        q(parent),
        session(0),
        topNode(0)
    {
        init();
    }
    void init();
    void channelsJobFinished(Bodega::NetworkJob *job);
    void reloadFromNetwork();

    Model *q;
    Session *session;
    QString topChannel;
    QString searchQuery;
    Node *topNode;

    //NEVER access those values outside channelsJobFinished(), Session will delete them
    //QPersistentModelIndex parent of this ChannelsJob 1/1 correspondence with Node
    QHash<ChannelsJob *, QPersistentModelIndex> indexForJobs;
    //job correspondednt to this  index
    QHash<QPersistentModelIndex, QList<ChannelsJob *> > jobsForIndex;
};

void Model::Private::init()
{
    ChannelInfo rootChanInfo;
    AssetInfo rootAssetInfo;
    delete topNode;
    topNode = new Node(rootChanInfo, rootAssetInfo, 0);
    indexForJobs.clear();
    jobsForIndex.clear();
    session = 0;
}

void Model::Private::channelsJobFinished(Bodega::NetworkJob *job)
{
    ChannelsJob *channelsJob = qobject_cast<ChannelsJob *>(job);
    Q_ASSERT(channelsJob);
    Q_ASSERT(indexForJobs.contains(channelsJob));

    QPersistentModelIndex idx = indexForJobs.value(channelsJob);

    //remove from bookkeeping
    indexForJobs.remove(channelsJob);
    jobsForIndex[idx].removeAll(channelsJob);
    if (jobsForIndex[idx].isEmpty()) {
        jobsForIndex.remove(idx);
    }

    if (channelsJob->channels().isEmpty() && channelsJob->assets().isEmpty()) {
        return;
    }

    Node *node;
    if (idx.isValid()) {
        node = static_cast<Node*>(idx.internalPointer());
    } else {
        node = topNode;
    }
    node->setCompletelyPopulated(!channelsJob->hasMoreAssets());
    node->setLastFetchedOffset(channelsJob->offset() + DEFAULT_PAGE_SIZE);

    if (!channelsJob->channels().isEmpty()) {
        q->beginInsertRows(idx, node->childCount(),
                           node->childCount() + channelsJob->channels().count()-1);
        AssetInfo dummyAssetInfo;
        foreach (const ChannelInfo &info, channelsJob->channels()) {
            node->appendChild(new Node(info, dummyAssetInfo, node));
        }
        q->endInsertRows();
    }

    if (!channelsJob->assets().isEmpty()) {
        q->beginInsertRows(idx, node->childCount(),
                           node->childCount() + channelsJob->assets().count()-1);
        ChannelInfo dummyChannelInfo;
        foreach (const AssetInfo &info, channelsJob->assets()) {
            node->appendChild(new Node(dummyChannelInfo, info, node));
        }
        q->endInsertRows();
    }
}

void Model::Private::reloadFromNetwork()
{
    if (!session || !session->isAuthenticated()) {
        return;
    }

    //FIXME: not safe, at this point most of jobs will be deleted by session
    foreach (const QList<ChannelsJob *> &list, jobsForIndex) {
        foreach (ChannelsJob *job, list) {
            disconnect(job, 0, q, 0);
        }
    }
    jobsForIndex.clear();
    indexForJobs.clear();

    //reset topnode, remove all the contents of the model
    q->beginResetModel();
    delete topNode;
    ChannelInfo rootChanInfo;
    AssetInfo rootAssetInfo;
    topNode = new Node(rootChanInfo, rootAssetInfo, 0);
    q->endResetModel();

    ChannelsJob *channelsJob;
    if (searchQuery.isEmpty()) {
        channelsJob = session->channels(topChannel, 0, DEFAULT_PAGE_SIZE);
    } else {
        channelsJob = session->search(searchQuery, topChannel,
                                      0, DEFAULT_PAGE_SIZE);
    }

    connect(channelsJob, SIGNAL(jobFinished(Bodega::NetworkJob *)),
            q, SLOT(channelsJobFinished(Bodega::NetworkJob *)));
    //TODO: manage errors

    QPersistentModelIndex idx = QPersistentModelIndex(QModelIndex());
    indexForJobs[channelsJob] = idx;
    jobsForIndex[idx] << channelsJob;
}

Model::Model(QObject *parent)
    : QAbstractItemModel(parent),
      d(new Private(this))
{
    // set the role names based on the values of the DisplayRoles enum for
    //  the sake of QML
    QHash<int, QByteArray> roles;
    roles.insert(Qt::DisplayRole, "DisplayRole");
    roles.insert(Qt::DecorationRole, "DecorationRole");
    QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("DisplayRoles"));
    for (int i = 0; i < e.keyCount(); ++i) {
        roles.insert(e.value(i), e.key(i));
    }
    setRoleNames(roles);
}

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

bool Model::canFetchMore(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return false;
    }

    Node *node = static_cast<Node*>(parent.internalPointer());
    return node->isChannel() && !node->isCompletelyPopulated() &&
            !d->jobsForIndex.contains(parent);
}

int Model::columnCount(const QModelIndex &parent) const
{
    return 1;
}

QVariant Model::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

    Node *node = static_cast<Node*>(index.internalPointer());

    if (node->isChannel()) {
        switch (role) {
        case Qt::DisplayRole:
            return node->channelInfo().name;
        case ChannelIdRole:
            return node->channelInfo().id;
        case ChannelNameRole:
            return node->channelInfo().name;
        case ChannelDescriptionRole:
            return node->channelInfo().description;
        case ChannelAssetCountRole:
            return node->channelInfo().assetCount;
        case ImageTinyRole:
            return node->channelInfo().images.value(Bodega::ImageTiny);
        case ImageSmallRole:
            return node->channelInfo().images.value(Bodega::ImageSmall);
        case ImageMediumRole:
            return node->channelInfo().images.value(Bodega::ImageMedium);
        case ImageLargeRole:
            return node->channelInfo().images.value(Bodega::ImageLarge);
        case ImageHugeRole:
            return node->channelInfo().images.value(Bodega::ImageHuge);
        case ImagePreviewsRole:
            return node->channelInfo().images.value(Bodega::ImagePreviews);
        default:
            return QVariant();
        }
    } else {
        switch (role) {
        case Qt::DisplayRole:
            return node->assetInfo().name;
        case AssetIdRole:
            return node->assetInfo().id;
        case AssetNameRole:
            return node->assetInfo().name;
        case AssetVersionRole:
            return node->assetInfo().version;
        case AssetFilenameRole:
            return node->assetInfo().filename;
        case ImageTinyRole:
            return node->assetInfo().images.value(Bodega::ImageTiny);
        case ImageSmallRole:
            return node->assetInfo().images.value(Bodega::ImageSmall);
        case ImageMediumRole:
            return node->assetInfo().images.value(Bodega::ImageMedium);
        case ImageLargeRole:
            return node->assetInfo().images.value(Bodega::ImageLarge);
        case ImageHugeRole:
            return node->assetInfo().images.value(Bodega::ImageHuge);
        case ImagePreviewsRole:
            return node->assetInfo().images.value(Bodega::ImagePreviews);
        case AssetDescriptionRole:
            return node->assetInfo().description;
        case AssetPointsRole:
            return node->assetInfo().points;
        default:
            return QVariant();
        }
    }
}

void Model::fetchMore(const QModelIndex &parent)
{
    if (!parent.isValid() || !d->session || !canFetchMore(parent) ||
        !d->session->isAuthenticated()) {
        return;
    }

    QPersistentModelIndex idx = QPersistentModelIndex(parent);
    Node *node = static_cast<Node*>(idx.internalPointer());

    ChannelsJob *channelsJob;
    if (d->searchQuery.isEmpty()) {
        channelsJob = d->session->channels(node->channelInfo().id,
                                           node->lastFetchedOffset(),
                                           DEFAULT_PAGE_SIZE);
    } else {
        channelsJob = d->session->search(d->searchQuery,
                                         d->topChannel,
                                         node->lastFetchedOffset(),
                                         DEFAULT_PAGE_SIZE);
    }
    connect(channelsJob, SIGNAL(jobFinished(Bodega::NetworkJob *)),
            this, SLOT(channelsJobFinished(Bodega::NetworkJob *)));
    //TODO: manage errors

    d->indexForJobs[channelsJob] = idx;
    d->jobsForIndex[idx] << channelsJob;
}

Qt::ItemFlags Model::flags(const QModelIndex &index) const
{
    if (index.isValid()) {
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    } else {
        return Qt::NoItemFlags;
    }
}

bool Model::hasChildren(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return true;
    }
    return static_cast<Node*>(parent.internalPointer())->isChannel();
}

QVariant Model::headerData(int section, Qt::Orientation orientation,
                           int role) const
{
    return QVariant();
}

QModelIndex Model::index(int row, int column,
                         const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent)) {
        return QModelIndex();
    }

    Node *parentNode;

    if (!parent.isValid()) {
        parentNode = d->topNode;
    } else {
        parentNode = static_cast<Node*>(parent.internalPointer());
    }

    Node *childNode = parentNode->child(row);
    if (childNode) {
        return createIndex(row, column, childNode);
    } else {
        return QModelIndex();
    }
}

QMap<int, QVariant> Model::itemData(const QModelIndex &index) const
{
    return QMap<int, QVariant>();
}

QModelIndex Model::parent(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    Node *childNode = static_cast<Node*>(index.internalPointer());
    Node *parentNode = childNode->parent();

    if (parentNode == d->topNode) {
        return QModelIndex();
    }

    return createIndex(parentNode->row(), 0, parentNode);
}

int Model::rowCount(const QModelIndex &parent) const
{
    Node *parentNode;
    if (parent.column() > 0) {
        return 0;
    }

    if (!parent.isValid()) {
        parentNode = d->topNode;
    } else {
        parentNode = static_cast<Node*>(parent.internalPointer());
    }

    return parentNode->childCount();
}

void Model::setSession(Session *session)
{
    if (session == d->session) {
        return;
    }

    if (d->session) {
        disconnect(d->session, 0, this, 0);
        d->init();
        beginResetModel();
        endResetModel();
    }

    d->session = session;
    connect(d->session, SIGNAL(authenticated(bool)),
            this, SLOT(reloadFromNetwork()));

    d->reloadFromNetwork();
}

Session *Model::session() const
{
    return d->session;
}

void Model::setTopChannel(const QString &topChannel)
{
    if (d->topChannel == topChannel) {
        return;
    }

    d->topChannel = topChannel;

    if (!d->session) {
        return;
    }

    //Search queries win against channel listing
    if (!d->searchQuery.isEmpty()) {
        d->reloadFromNetwork();
    }
    emit topChannelChanged();
}

QString Model::topChannel() const
{
    return d->topChannel;
}

void Model::setSearchQuery(const QString &query)
{
    if (d->searchQuery == query) {
        return;
    }

    d->searchQuery = query;

    if (!d->session) {
        return;
    }

    d->reloadFromNetwork();
    emit searchQueryChanged();
}

QString Model::searchQuery() const
{
    return d->searchQuery;
}

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


<commit_before><commit_msg>Changed data file to start with ".", don't restore that<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/external_protocol/external_protocol_handler.h"

#include "content/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"

using content::BrowserThread;

class FakeExternalProtocolHandlerWorker
    : public ShellIntegration::DefaultProtocolClientWorker {
 public:
  FakeExternalProtocolHandlerWorker(
      ShellIntegration::DefaultWebClientObserver* observer,
      const std::string& protocol,
      ShellIntegration::DefaultWebClientState os_state)
      : ShellIntegration::DefaultProtocolClientWorker(observer, protocol),
        os_state_(os_state) {}

 private:
  virtual ShellIntegration::DefaultWebClientState CheckIsDefault() {
    return os_state_;
  }

  virtual void SetAsDefault() {}

  ShellIntegration::DefaultWebClientState os_state_;
};

class FakeExternalProtocolHandlerDelegate
    : public ExternalProtocolHandler::Delegate {
 public:
  FakeExternalProtocolHandlerDelegate()
      : block_state_(ExternalProtocolHandler::BLOCK),
        os_state_(ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT),
        has_launched_(false),
        has_prompted_(false),
        has_blocked_ (false) {}

  virtual ShellIntegration::DefaultProtocolClientWorker* CreateShellWorker(
      ShellIntegration::DefaultWebClientObserver* observer,
      const std::string& protocol) {
    return new FakeExternalProtocolHandlerWorker(observer, protocol, os_state_);
  }

  virtual ExternalProtocolHandler::BlockState GetBlockState(
      const std::string& scheme) { return block_state_; }

  virtual void BlockRequest() {
    ASSERT_TRUE(block_state_ == ExternalProtocolHandler::BLOCK ||
                os_state_ == ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_blocked_ = true;
  }

  virtual void RunExternalProtocolDialog(const GURL& url,
                                         int render_process_host_id,
                                         int routing_id) {
    ASSERT_EQ(block_state_, ExternalProtocolHandler::UNKNOWN);
    ASSERT_NE(os_state_, ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_prompted_ = true;
  }

  virtual void LaunchUrlWithoutSecurityCheck(const GURL& url) {
    ASSERT_EQ(block_state_, ExternalProtocolHandler::DONT_BLOCK);
    ASSERT_NE(os_state_, ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_launched_ = true;
  }

  virtual void FinishedProcessingCheck() {
    MessageLoop::current()->Quit();
  }

  void set_os_state(ShellIntegration::DefaultWebClientState value) {
    os_state_ = value;
  }

  void set_block_state(ExternalProtocolHandler::BlockState value) {
    block_state_ = value;
  }

  bool has_launched() { return has_launched_; }
  bool has_prompted() { return has_prompted_; }
  bool has_blocked() { return has_blocked_; }

 private:
  ExternalProtocolHandler::BlockState block_state_;
  ShellIntegration::DefaultWebClientState os_state_;
  bool has_launched_;
  bool has_prompted_;
  bool has_blocked_;
};

class ExternalProtocolHandlerTest : public testing::Test {
 protected:
  ExternalProtocolHandlerTest()
      : ui_thread_(BrowserThread::UI, MessageLoop::current()),
        file_thread_(BrowserThread::FILE) {}

  virtual void SetUp() {
    file_thread_.Start();
  }

  void DoTest(ExternalProtocolHandler::BlockState block_state,
              ShellIntegration::DefaultWebClientState os_state,
              bool should_prompt, bool should_launch, bool should_block) {
    GURL url("mailto:test@test.com");
    ASSERT_FALSE(delegate_.has_prompted());
    ASSERT_FALSE(delegate_.has_launched());
    ASSERT_FALSE(delegate_.has_blocked());

    delegate_.set_block_state(block_state);
    delegate_.set_os_state(os_state);
    ExternalProtocolHandler::LaunchUrlWithDelegate(url, 0, 0, &delegate_);
    if (block_state != ExternalProtocolHandler::BLOCK)
      MessageLoop::current()->Run();

    ASSERT_EQ(should_prompt, delegate_.has_prompted());
    ASSERT_EQ(should_launch, delegate_.has_launched());
    ASSERT_EQ(should_block, delegate_.has_blocked());
  }

  MessageLoopForUI ui_message_loop_;
  content::TestBrowserThread ui_thread_;
  content::TestBrowserThread file_thread_;

  FakeExternalProtocolHandlerDelegate delegate_;
};

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeDefault) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeNotDefault) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeUnknown) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeDefault) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeNotDefault) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         false, true, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeUnknown) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         false, true, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeDefault) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeNotDefault) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         true, false, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeUnknown) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         true, false, false);
}
<commit_msg>Isolate ExternalProtocolHandlerTest from other tests in the TearDown method.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/external_protocol/external_protocol_handler.h"

#include "content/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"

using content::BrowserThread;

class FakeExternalProtocolHandlerWorker
    : public ShellIntegration::DefaultProtocolClientWorker {
 public:
  FakeExternalProtocolHandlerWorker(
      ShellIntegration::DefaultWebClientObserver* observer,
      const std::string& protocol,
      ShellIntegration::DefaultWebClientState os_state)
      : ShellIntegration::DefaultProtocolClientWorker(observer, protocol),
        os_state_(os_state) {}

 private:
  virtual ShellIntegration::DefaultWebClientState CheckIsDefault() {
    return os_state_;
  }

  virtual void SetAsDefault() {}

  ShellIntegration::DefaultWebClientState os_state_;
};

class FakeExternalProtocolHandlerDelegate
    : public ExternalProtocolHandler::Delegate {
 public:
  FakeExternalProtocolHandlerDelegate()
      : block_state_(ExternalProtocolHandler::BLOCK),
        os_state_(ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT),
        has_launched_(false),
        has_prompted_(false),
        has_blocked_ (false) {}

  virtual ShellIntegration::DefaultProtocolClientWorker* CreateShellWorker(
      ShellIntegration::DefaultWebClientObserver* observer,
      const std::string& protocol) {
    return new FakeExternalProtocolHandlerWorker(observer, protocol, os_state_);
  }

  virtual ExternalProtocolHandler::BlockState GetBlockState(
      const std::string& scheme) { return block_state_; }

  virtual void BlockRequest() {
    ASSERT_TRUE(block_state_ == ExternalProtocolHandler::BLOCK ||
                os_state_ == ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_blocked_ = true;
  }

  virtual void RunExternalProtocolDialog(const GURL& url,
                                         int render_process_host_id,
                                         int routing_id) {
    ASSERT_EQ(block_state_, ExternalProtocolHandler::UNKNOWN);
    ASSERT_NE(os_state_, ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_prompted_ = true;
  }

  virtual void LaunchUrlWithoutSecurityCheck(const GURL& url) {
    ASSERT_EQ(block_state_, ExternalProtocolHandler::DONT_BLOCK);
    ASSERT_NE(os_state_, ShellIntegration::IS_DEFAULT_WEB_CLIENT);
    has_launched_ = true;
  }

  virtual void FinishedProcessingCheck() {
    MessageLoop::current()->Quit();
  }

  void set_os_state(ShellIntegration::DefaultWebClientState value) {
    os_state_ = value;
  }

  void set_block_state(ExternalProtocolHandler::BlockState value) {
    block_state_ = value;
  }

  bool has_launched() { return has_launched_; }
  bool has_prompted() { return has_prompted_; }
  bool has_blocked() { return has_blocked_; }

 private:
  ExternalProtocolHandler::BlockState block_state_;
  ShellIntegration::DefaultWebClientState os_state_;
  bool has_launched_;
  bool has_prompted_;
  bool has_blocked_;
};

class ExternalProtocolHandlerTest : public testing::Test {
 protected:
  ExternalProtocolHandlerTest()
      : ui_thread_(BrowserThread::UI, MessageLoop::current()),
        file_thread_(BrowserThread::FILE) {}

  virtual void SetUp() {
    file_thread_.Start();
  }

  virtual void TearDown() {
    // Ensure that g_accept_requests gets set back to true after test execution.
    ExternalProtocolHandler::PermitLaunchUrl();
  }

  void DoTest(ExternalProtocolHandler::BlockState block_state,
              ShellIntegration::DefaultWebClientState os_state,
              bool should_prompt, bool should_launch, bool should_block) {
    GURL url("mailto:test@test.com");
    ASSERT_FALSE(delegate_.has_prompted());
    ASSERT_FALSE(delegate_.has_launched());
    ASSERT_FALSE(delegate_.has_blocked());

    delegate_.set_block_state(block_state);
    delegate_.set_os_state(os_state);
    ExternalProtocolHandler::LaunchUrlWithDelegate(url, 0, 0, &delegate_);
    if (block_state != ExternalProtocolHandler::BLOCK)
      MessageLoop::current()->Run();

    ASSERT_EQ(should_prompt, delegate_.has_prompted());
    ASSERT_EQ(should_launch, delegate_.has_launched());
    ASSERT_EQ(should_block, delegate_.has_blocked());
  }

  MessageLoopForUI ui_message_loop_;
  content::TestBrowserThread ui_thread_;
  content::TestBrowserThread file_thread_;

  FakeExternalProtocolHandlerDelegate delegate_;
};

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeDefault) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeNotDefault) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeUnknown) {
  DoTest(ExternalProtocolHandler::BLOCK,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeDefault) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeNotDefault) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         false, true, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeUnknown) {
  DoTest(ExternalProtocolHandler::DONT_BLOCK,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         false, true, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeDefault) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::IS_DEFAULT_WEB_CLIENT,
         false, false, true);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeNotDefault) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::NOT_DEFAULT_WEB_CLIENT,
         true, false, false);
}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeUnknown) {
  DoTest(ExternalProtocolHandler::UNKNOWN,
         ShellIntegration::UNKNOWN_DEFAULT_WEB_CLIENT,
         true, false, false);
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03, c++11, c++14

// <memory>

// template <class _Tp>
// void destroy_at(_Tp*);

#include <memory>
#include <cstdlib>
#include <cassert>

struct Counted {
  static int count;
  static void reset() { count = 0; }
  Counted() { ++count; }
  Counted(Counted const&) { ++count; }
  ~Counted() { --count; }
  friend void operator&(Counted) = delete;
};
int Counted::count = 0;

struct VCounted {
  static int count;
  static void reset() { count = 0; }
  VCounted() { ++count; }
  VCounted(VCounted const&) { ++count; }
  virtual ~VCounted() { --count; }
  friend void operator&(VCounted) = delete;
};
int VCounted::count = 0;

struct DCounted : VCounted {
    friend void operator&(DCounted) = delete;
};

int main()
{
    {
    void* mem1 = std::malloc(sizeof(Counted));
    void* mem2 = std::malloc(sizeof(Counted));
    assert(mem1 && mem2);
    assert(Counted::count == 0);
    Counted* ptr1 = ::new(mem1) Counted();
    Counted* ptr2 = ::new(mem2) Counted();
    assert(Counted::count == 2);
    std::destroy_at(ptr1);
    assert(Counted::count == 1);
    std::destroy_at(ptr2);
    assert(Counted::count == 0);
    }
    {
    void* mem1 = std::malloc(sizeof(DCounted));
    void* mem2 = std::malloc(sizeof(DCounted));
    assert(mem1 && mem2);
    assert(DCounted::count == 0);
    DCounted* ptr1 = ::new(mem1) DCounted();
    DCounted* ptr2 = ::new(mem2) DCounted();
    assert(DCounted::count == 2);
    assert(VCounted::count == 2);
    std::destroy_at(ptr1);
    assert(VCounted::count == 1);
    std::destroy_at(ptr2);
    assert(VCounted::count == 0);
    }
}
<commit_msg>Fix memory leak in test.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03, c++11, c++14

// <memory>

// template <class _Tp>
// void destroy_at(_Tp*);

#include <memory>
#include <cstdlib>
#include <cassert>

struct Counted {
  static int count;
  static void reset() { count = 0; }
  Counted() { ++count; }
  Counted(Counted const&) { ++count; }
  ~Counted() { --count; }
  friend void operator&(Counted) = delete;
};
int Counted::count = 0;

struct VCounted {
  static int count;
  static void reset() { count = 0; }
  VCounted() { ++count; }
  VCounted(VCounted const&) { ++count; }
  virtual ~VCounted() { --count; }
  friend void operator&(VCounted) = delete;
};
int VCounted::count = 0;

struct DCounted : VCounted {
    friend void operator&(DCounted) = delete;
};

int main()
{
    {
    void* mem1 = std::malloc(sizeof(Counted));
    void* mem2 = std::malloc(sizeof(Counted));
    assert(mem1 && mem2);
    assert(Counted::count == 0);
    Counted* ptr1 = ::new(mem1) Counted();
    Counted* ptr2 = ::new(mem2) Counted();
    assert(Counted::count == 2);
    std::destroy_at(ptr1);
    assert(Counted::count == 1);
    std::destroy_at(ptr2);
    assert(Counted::count == 0);
    std::free(mem1);
    std::free(mem2);
    }
    {
    void* mem1 = std::malloc(sizeof(DCounted));
    void* mem2 = std::malloc(sizeof(DCounted));
    assert(mem1 && mem2);
    assert(DCounted::count == 0);
    DCounted* ptr1 = ::new(mem1) DCounted();
    DCounted* ptr2 = ::new(mem2) DCounted();
    assert(DCounted::count == 2);
    assert(VCounted::count == 2);
    std::destroy_at(ptr1);
    assert(VCounted::count == 1);
    std::destroy_at(ptr2);
    assert(VCounted::count == 0);
    std::free(mem1);
    std::free(mem2);
    }
}
<|endoftext|>


<commit_before>/**
 * @brief Handle on the StdAir library context
 * @author Anh Quan Nguyen <quannaus@users.sourceforge.net>
 * @date 20/01/2010
 * @detail StdAir aims at providing a clean API, and the corresponding
 *         C++ implementation, for the basis of Airline IT Business Object
 *         Model (BOM), that is, to be used by several other Open Source
 *         projects, such as RMOL and OpenTREP

 *         Install the StdAir library for Airline IT Standard C++ fundaments.
 */
#ifndef __STDAIR_STDAIR_HPP
#define __STDAIR_STDAIR_HPP

// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>

namespace stdair {

  /// Forward declarations
  class BomRoot;

  /**
   * @brief Interface for the STDAIR Services
   */
  class STDAIR_Service {
  public:
    // ////////// Constructors and destructors //////////
    /**
     * @brief Default constructor.
     */
    STDAIR_Service ();

    /**
     * @brief Constructor.
     *
The init() method is called; see the corresponding
     * documentation for more details.
     *
Moreover, a reference on an output stream is given, so
     * that log outputs can be directed onto that stream.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     */
    STDAIR_Service (const BasLogParams&);

    /**
     * @brief Constructor.
     *
The init() method is called; see the corresponding
     * documentation for more details.
     *
A reference on an output stream is given, so
     * that log outputs can be directed onto that stream.
     *
Moreover, database connection parameters are given, so
     * that database requests can use the corresponding access.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     * @param[in] const BasDBParams& Parameters for the database session.
     */
    STDAIR_Service (const BasLogParams&, const BasDBParams&);

    /**
     * @brief Destructor.
     */
    ~STDAIR_Service();

    // ///////////////// Getters ///////////////////
    /**
     * @brief Get a reference on the BomRoot object.
     *
If the service context has not been initialised, that
     * method throws an exception (failing assertion).
     * @param[out] BomRoot& Reference on the BomRoot.
     */
    BomRoot& getBomRoot () const {
      return _bomRoot;
    }

  private:
    // /////// Construction and Destruction helper methods ///////
    /**
     * @brief Default copy constructor.
     * @param[in] const STDAIR_Service& Reference on the STDAIR_Service handler
     *            to be copied.
     */
    STDAIR_Service (const STDAIR_Service&);

    /**
     * @brief Initialise the log.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     */
    void logInit (const BasLogParams&);

    /**
     * @brief Initialise the database session.
     * @param[in] const BasDBParams& Parameters for the database session.
     */
    void dbInit (const BasDBParams&);

    /**
     * @brief Initialise.
     *
The static instance of the log service (Logger object) is created.
     *
The static instance of the database session manager
     * (DBSessionManager object) is created.
     *
The static instance of the FacSupervisor object, itself referencing
     * all the other objects (factories and BOM), is created.
     *
As those three objects are static, there is no need to store them
     * in any service context. However, some lock mechanism may be needed
     * in order to secure the access to the corresponding resources.
     */
    void init ();

    /**
     * @brief Finalise.
     */
    void finalise ();

  private:
    // /////////////// Attributes ///////////////
    /**
     * @brief Root of the BOM tree.
     */
    BomRoot& _bomRoot;
  };
}
#endif // __STDAIR_STDAIR_HPP
<commit_msg>[Branch 0.9.0][API] Fixed a few compilation errors with the new API.<commit_after>/**
 * @brief Handle on the StdAir library context
 * @author Anh Quan Nguyen <quannaus@users.sourceforge.net>
 * @date 20/01/2010
 * @detail StdAir aims at providing a clean API, and the corresponding
 *         C++ implementation, for the basis of Airline IT Business Object
 *         Model (BOM), that is, to be used by several other Open Source
 *         projects, such as RMOL and OpenTREP

 *         Install the StdAir library for Airline IT Standard C++ fundaments.
 */
#ifndef __STDAIR_STDAIR_HPP
#define __STDAIR_STDAIR_HPP

// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>
#include <stdair/stdair_service_types.hpp>

namespace stdair {

  /// Forward declarations
  class BomRoot;

  /**
   * @brief Interface for the STDAIR Services
   */
  class STDAIR_Service {
  public:
    // ////////// Constructors and destructors //////////
    /**
     * @brief Default constructor.
     */
    STDAIR_Service ();

    /**
     * @brief Constructor.
     *
The init() method is called; see the corresponding
     * documentation for more details.
     *
Moreover, a reference on an output stream is given, so
     * that log outputs can be directed onto that stream.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     */
    STDAIR_Service (const BasLogParams&);

    /**
     * @brief Constructor.
     *
The init() method is called; see the corresponding
     * documentation for more details.
     *
A reference on an output stream is given, so
     * that log outputs can be directed onto that stream.
     *
Moreover, database connection parameters are given, so
     * that database requests can use the corresponding access.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     * @param[in] const BasDBParams& Parameters for the database session.
     */
    STDAIR_Service (const BasLogParams&, const BasDBParams&);

    /**
     * @brief Destructor.
     */
    ~STDAIR_Service();

    // ///////////////// Getters ///////////////////
    /**
     * @brief Get a reference on the BomRoot object.
     *
If the service context has not been initialised, that
     * method throws an exception (failing assertion).
     * @param[out] BomRoot& Reference on the BomRoot.
     */
    BomRoot& getBomRoot () const {
      return _bomRoot;
    }

  private:
    // /////// Construction and Destruction helper methods ///////
    /**
     * @brief Default copy constructor.
     * @param[in] const STDAIR_Service& Reference on the STDAIR_Service handler
     *            to be copied.
     */
    STDAIR_Service (const STDAIR_Service&);

    /**
     * @brief Initialise the log.
     * @param[in] const BasLogParams& Parameters for the output log stream.
     */
    void logInit (const BasLogParams&);

    /**
     * @brief Initialise the database session.
     * @param[in] const BasDBParams& Parameters for the database session.
     */
    void dbInit (const BasDBParams&);

    /**
     * @brief Initialise.
     *
The static instance of the log service (Logger object) is created.
     *
The static instance of the database session manager
     * (DBSessionManager object) is created.
     *
The static instance of the FacSupervisor object, itself referencing
     * all the other objects (factories and BOM), is created.
     *
As those three objects are static, there is no need to store them
     * in any service context. However, some lock mechanism may be needed
     * in order to secure the access to the corresponding resources.
     */
    void init ();

    /**
     * @brief Finalise.
     */
    void finalise ();

  private:
    // /////////////// Attributes ///////////////
    /**
     * @brief Root of the BOM tree.
     */
    BomRoot& _bomRoot;
  };
}
#endif // __STDAIR_STDAIR_HPP
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <algorithm>
#include <iterator>
#include <map>
#include <string>

#include "caf/string_view.hpp"

namespace caf {

/// Maps strings to values of type `V`, but unlike `std::map<std::string, V>`
/// accepts `string_view` for looking up keys efficiently.
template <class V>
class dictionary {
public:
  // -- member types ----------------------------------------------------------

  using map_type = std::map<std::string, V>;

  using key_type = typename map_type::key_type;

  using mapped_type = typename map_type::mapped_type;

  using value_type = typename map_type::value_type;

  using allocator_type = typename map_type::allocator_type;

  using size_type = typename map_type::size_type;

  using difference_type = typename map_type::difference_type;

  using reference = typename map_type::reference;

  using const_reference = typename map_type::const_reference;

  using pointer = typename map_type::pointer;

  using const_pointer = typename map_type::const_pointer;

  using iterator = typename map_type::iterator;

  using const_iterator = typename map_type::const_iterator;

  using reverse_iterator = typename map_type::reverse_iterator;

  using const_reverse_iterator = typename map_type::const_reverse_iterator;

  using iterator_bool_pair = std::pair<iterator, bool>;

  struct mapped_type_less {
    inline bool operator()(const value_type& x, string_view y) const {
      return x.first < y;
    }

    inline bool operator()(const value_type& x, const value_type& y) const {
      return x.first < y.first;
    }

    inline bool operator()(string_view x, const value_type& y) const {
      return x < y.first;
    }
  };

  // -- constructors, destructors, and assignment operators -------------------

  dictionary() = default;

  dictionary(dictionary&&) = default;

  dictionary(const dictionary&) = default;

  dictionary(std::initializer_list<value_type> xs) : xs_(xs) {
    // nop
  }

  template <class InputIterator>
  dictionary(InputIterator first, InputIterator last) : xs_(first, last) {
    // nop
  }

  dictionary& operator=(dictionary&&) = default;

  dictionary& operator=(const dictionary&) = default;

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return begin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator crbegin() const noexcept {
    return rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  const_reverse_iterator crend() const noexcept {
    return rend();
  }

  // -- size -------------------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  map_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const map_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(dictionary& other) {
    xs_.swap(other.xs_);
  }

  // -- insertion --------------------------------------------------------------

  template <class K, class T>
  iterator_bool_pair emplace(K&& key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)});
    if (i->first == key)
      return {i, false};
    return {xs_.emplace_hint(i, copy(std::forward<K>(key)),
                             V{std::forward<T>(value)}),
            true};
  }

  iterator_bool_pair insert(value_type kvp) {
    return emplace(kvp.first, std::move(kvp.second));
  }

  iterator insert(iterator hint, value_type kvp) {
    return emplace_hint(hint, kvp.first, std::move(kvp.second));
  }

  template <class T>
  iterator_bool_pair insert(string_view key, T&& value) {
    return emplace(key, V{std::forward<T>(value)});
  }

  template <class K, class T>
  iterator emplace_hint(iterator hint, K&& key, T&& value) {
    if (hint == end() || hint->first > key)
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)})
             .first;
    if (hint->first == key)
      return hint;
    return xs_.emplace_hint(hint, copy(std::forward<K>(key)),
                            V{std::forward<T>(value)});
  }

  template <class T>
  iterator insert(iterator hint, string_view key, T&& value) {
    return emplace_hint(hint, key, std::forward<T>(value));
  }

  void insert(const_iterator first, const_iterator last) {
    xs_.insert(first, last);
  }

  template <class T>
  iterator_bool_pair insert_or_assign(string_view key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(key), V{std::forward<T>(value)});
    if (i->first == key) {
      i->second = V{std::forward<T>(value)};
      return {i, false};
    }
    return {xs_.emplace_hint(i, copy(key), V{std::forward<T>(value)}), true};
  }

  template <class T>
  iterator insert_or_assign(iterator hint, string_view key, T&& value) {
    if (hint == end() || hint->first > key)
      return insert_or_assign(key, std::forward<T>(value)).first;
    hint = lower_bound(hint, key);
    if (hint != end() && hint->first == key) {
      hint->second = std::forward<T>(value);
      return hint;
    }
    return xs_.emplace_hint(hint, copy(key), V{std::forward<T>(value)});
  }

  // -- lookup -----------------------------------------------------------------

  bool contains(string_view key) const noexcept {
    auto i = lower_bound(key);
    return !(i == end() || i->first != key);
  }

  size_t count(string_view key) const noexcept {
    return contains(key) ? 1u : 0u;
  }

  iterator find(string_view key) noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  const_iterator find(string_view key) const noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  iterator lower_bound(string_view key) {
    return lower_bound(begin(), key);
  }

  const_iterator lower_bound(string_view key) const {
    return lower_bound(begin(), key);
  }

  iterator upper_bound(string_view key) {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  const_iterator upper_bound(string_view key) const {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  // -- element access ---------------------------------------------------------

  mapped_type& operator[](string_view key) {
    return insert(key, mapped_type{}).first->second;
  }

private:
  iterator lower_bound(iterator from, string_view key) {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  const_iterator lower_bound(const_iterator from, string_view key) const {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  template <size_t N>
  static inline std::string copy(const char (&str)[N]) {
    return std::string{str};
  }

  // Copies the content of `str` into a new string.
  static inline std::string copy(string_view str) {
    return std::string{str.begin(), str.end()};
  }

  // Moves the content of `str` into a new string.
  static inline std::string copy(std::string str) {
    return str;
  }

  map_type xs_;
};

// -- operators ----------------------------------------------------------------

// @relates dictionary
template <class T>
bool operator==(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() == ys.container();
}

// @relates dictionary
template <class T>
bool operator!=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() != ys.container();
}

// @relates dictionary
template <class T>
bool operator<(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() < ys.container();
}

// @relates dictionary
template <class T>
bool operator<=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() <= ys.container();
}

// @relates dictionary
template <class T>
bool operator>(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() > ys.container();
}

// @relates dictionary
template <class T>
bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() >= ys.container();
}

// -- free functions -----------------------------------------------------------

/// Convenience function for calling `dict.insert_or_assign(key, value)`.
// @relates dictionary
template <class T>
void put(dictionary<T>& dict, string_view key, T value) {
  dict.insert_or_assign(key, std::move(value));
}

} // namespace caf
<commit_msg>Use perfect forwarding for put parameter<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <algorithm>
#include <iterator>
#include <map>
#include <string>

#include "caf/string_view.hpp"

namespace caf {

/// Maps strings to values of type `V`, but unlike `std::map<std::string, V>`
/// accepts `string_view` for looking up keys efficiently.
template <class V>
class dictionary {
public:
  // -- member types ----------------------------------------------------------

  using map_type = std::map<std::string, V>;

  using key_type = typename map_type::key_type;

  using mapped_type = typename map_type::mapped_type;

  using value_type = typename map_type::value_type;

  using allocator_type = typename map_type::allocator_type;

  using size_type = typename map_type::size_type;

  using difference_type = typename map_type::difference_type;

  using reference = typename map_type::reference;

  using const_reference = typename map_type::const_reference;

  using pointer = typename map_type::pointer;

  using const_pointer = typename map_type::const_pointer;

  using iterator = typename map_type::iterator;

  using const_iterator = typename map_type::const_iterator;

  using reverse_iterator = typename map_type::reverse_iterator;

  using const_reverse_iterator = typename map_type::const_reverse_iterator;

  using iterator_bool_pair = std::pair<iterator, bool>;

  struct mapped_type_less {
    inline bool operator()(const value_type& x, string_view y) const {
      return x.first < y;
    }

    inline bool operator()(const value_type& x, const value_type& y) const {
      return x.first < y.first;
    }

    inline bool operator()(string_view x, const value_type& y) const {
      return x < y.first;
    }
  };

  // -- constructors, destructors, and assignment operators -------------------

  dictionary() = default;

  dictionary(dictionary&&) = default;

  dictionary(const dictionary&) = default;

  dictionary(std::initializer_list<value_type> xs) : xs_(xs) {
    // nop
  }

  template <class InputIterator>
  dictionary(InputIterator first, InputIterator last) : xs_(first, last) {
    // nop
  }

  dictionary& operator=(dictionary&&) = default;

  dictionary& operator=(const dictionary&) = default;

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return begin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator crbegin() const noexcept {
    return rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  const_reverse_iterator crend() const noexcept {
    return rend();
  }

  // -- size -------------------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  map_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const map_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(dictionary& other) {
    xs_.swap(other.xs_);
  }

  // -- insertion --------------------------------------------------------------

  template <class K, class T>
  iterator_bool_pair emplace(K&& key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)});
    if (i->first == key)
      return {i, false};
    return {xs_.emplace_hint(i, copy(std::forward<K>(key)),
                             V{std::forward<T>(value)}),
            true};
  }

  iterator_bool_pair insert(value_type kvp) {
    return emplace(kvp.first, std::move(kvp.second));
  }

  iterator insert(iterator hint, value_type kvp) {
    return emplace_hint(hint, kvp.first, std::move(kvp.second));
  }

  template <class T>
  iterator_bool_pair insert(string_view key, T&& value) {
    return emplace(key, V{std::forward<T>(value)});
  }

  template <class K, class T>
  iterator emplace_hint(iterator hint, K&& key, T&& value) {
    if (hint == end() || hint->first > key)
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)})
             .first;
    if (hint->first == key)
      return hint;
    return xs_.emplace_hint(hint, copy(std::forward<K>(key)),
                            V{std::forward<T>(value)});
  }

  template <class T>
  iterator insert(iterator hint, string_view key, T&& value) {
    return emplace_hint(hint, key, std::forward<T>(value));
  }

  void insert(const_iterator first, const_iterator last) {
    xs_.insert(first, last);
  }

  template <class T>
  iterator_bool_pair insert_or_assign(string_view key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(key), V{std::forward<T>(value)});
    if (i->first == key) {
      i->second = V{std::forward<T>(value)};
      return {i, false};
    }
    return {xs_.emplace_hint(i, copy(key), V{std::forward<T>(value)}), true};
  }

  template <class T>
  iterator insert_or_assign(iterator hint, string_view key, T&& value) {
    if (hint == end() || hint->first > key)
      return insert_or_assign(key, std::forward<T>(value)).first;
    hint = lower_bound(hint, key);
    if (hint != end() && hint->first == key) {
      hint->second = std::forward<T>(value);
      return hint;
    }
    return xs_.emplace_hint(hint, copy(key), V{std::forward<T>(value)});
  }

  // -- lookup -----------------------------------------------------------------

  bool contains(string_view key) const noexcept {
    auto i = lower_bound(key);
    return !(i == end() || i->first != key);
  }

  size_t count(string_view key) const noexcept {
    return contains(key) ? 1u : 0u;
  }

  iterator find(string_view key) noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  const_iterator find(string_view key) const noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  iterator lower_bound(string_view key) {
    return lower_bound(begin(), key);
  }

  const_iterator lower_bound(string_view key) const {
    return lower_bound(begin(), key);
  }

  iterator upper_bound(string_view key) {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  const_iterator upper_bound(string_view key) const {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  // -- element access ---------------------------------------------------------

  mapped_type& operator[](string_view key) {
    return insert(key, mapped_type{}).first->second;
  }

private:
  iterator lower_bound(iterator from, string_view key) {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  const_iterator lower_bound(const_iterator from, string_view key) const {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  template <size_t N>
  static inline std::string copy(const char (&str)[N]) {
    return std::string{str};
  }

  // Copies the content of `str` into a new string.
  static inline std::string copy(string_view str) {
    return std::string{str.begin(), str.end()};
  }

  // Moves the content of `str` into a new string.
  static inline std::string copy(std::string str) {
    return str;
  }

  map_type xs_;
};

// -- operators ----------------------------------------------------------------

// @relates dictionary
template <class T>
bool operator==(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() == ys.container();
}

// @relates dictionary
template <class T>
bool operator!=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() != ys.container();
}

// @relates dictionary
template <class T>
bool operator<(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() < ys.container();
}

// @relates dictionary
template <class T>
bool operator<=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() <= ys.container();
}

// @relates dictionary
template <class T>
bool operator>(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() > ys.container();
}

// @relates dictionary
template <class T>
bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() >= ys.container();
}

// -- free functions -----------------------------------------------------------

/// Convenience function for calling `dict.insert_or_assign(key, value)`.
// @relates dictionary
template <class T, class V>
void put(dictionary<T>& dict, string_view key, V&& value) {
  dict.insert_or_assign(key, std::forward<V>(value));
}

} // namespace caf
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: map.cpp 17 2005-03-08 23:58:43Z pavlenko $,

#include <mapnik/style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/filter_featureset.hpp>
#include <mapnik/hit_test_filter.hpp>
#include <mapnik/map.hpp>

namespace mapnik
{
    Map::Map()
        : width_(400),
          height_(400),
          srs_("+proj=latlong +datum=WGS84") {}

    Map::Map(int width,int height, std::string const& srs)
        : width_(width),
          height_(height),
          srs_(srs),
          background_(Color(255,255,255)) {}

    Map::Map(const Map& rhs)
        : width_(rhs.width_),
          height_(rhs.height_),
          srs_(rhs.srs_),
          background_(rhs.background_),
          styles_(rhs.styles_),
          layers_(rhs.layers_),
          currentExtent_(rhs.currentExtent_) {}

    Map& Map::operator=(const Map& rhs)
    {
        if (this==&rhs) return *this;
        width_=rhs.width_;
        height_=rhs.height_;
        srs_=rhs.srs_;
        background_=rhs.background_;
        styles_=rhs.styles_;
        layers_=rhs.layers_;
        return *this;
    }

    Map::style_iterator  Map::begin_styles() const
    {
        return styles_.begin();
    }
    Map::style_iterator  Map::end_styles() const
    {
        return styles_.end();
    }

    bool Map::insert_style(std::string const& name,feature_type_style const& style)
    {
        return styles_.insert(make_pair(name,style)).second;
    }

    void Map::remove_style(std::string const& name)
    {
        styles_.erase(name);
    }

    feature_type_style const& Map::find_style(std::string const& name) const
    {
        std::map<std::string,feature_type_style>::const_iterator itr = styles_.find(name);
        if (itr!=styles_.end())
            return itr->second;
        static feature_type_style default_style;
        return default_style;
    }

    size_t Map::layerCount() const
    {
        return layers_.size();
    }

    void Map::addLayer(const Layer& l)
    {
        layers_.push_back(l);
    }
    void Map::removeLayer(size_t index)
    {
        layers_.erase(layers_.begin()+index);
    }

    void Map::remove_all()
    {
        layers_.clear();
        styles_.clear();
    }

    const Layer& Map::getLayer(size_t index) const
    {
        return layers_[index];
    }

    Layer& Map::getLayer(size_t index)
    {
        return layers_[index];
    }

    std::vector<Layer> const& Map::layers() const
    {
        return layers_;
    }

    std::vector<Layer> & Map::layers()
    {
        return layers_;
    }

    unsigned Map::getWidth() const
    {
        return width_;
    }

    unsigned Map::getHeight() const
    {
        return height_;
    }

    void Map::setWidth(unsigned width)
    {
        if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE)
        {
            width_=width;
            fixAspectRatio();
        }
    }

    void Map::setHeight(unsigned height)
    {
        if (height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
        {
            height_=height;
            fixAspectRatio();
        }
    }

    void Map::resize(unsigned width,unsigned height)
    {
        if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE &&
            height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
        {
            width_=width;
            height_=height;
            fixAspectRatio();
        }
    }

    std::string const&  Map::srs() const
    {
        return srs_;
    }

    void Map::set_srs(std::string const& srs)
    {
        srs_ = srs;
    }

    void Map::setBackground(const Color& c)
    {
        background_=c;
    }

    const Color& Map::getBackground() const
    {
        return background_;
    }

    void Map::zoom(double factor)
    {
        coord2d center = currentExtent_.center();
        double w = factor * currentExtent_.width();
        double h = factor * currentExtent_.height();
        currentExtent_ = Envelope<double>(center.x - 0.5 * w,
                                          center.y - 0.5 * h,
                                          center.x + 0.5 * w,
                                          center.y + 0.5 * h);
        fixAspectRatio();
    }

    void Map::zoom_all()
    {
        try
        {
            projection proj0(srs_);
            Envelope<double> ext;
            bool first = true;
            std::vector<Layer>::const_iterator itr = layers_.begin();
            std::vector<Layer>::const_iterator end = layers_.end();
            while (itr != end)
            {
                std::string const& layer_srs = itr->srs();
                projection proj1(layer_srs);
                proj_transform prj_trans(proj0,proj1);

                Envelope<double> layerExt = itr->envelope();
                double x0 = layerExt.minx();
                double y0 = layerExt.miny();
                double z0 = 0.0;
                double x1 = layerExt.maxx();
                double y1 = layerExt.maxy();
                double z1 = 0.0;
                prj_trans.backward(x0,y0,z0);
                prj_trans.backward(x1,y1,z1);

                Envelope<double> layerExt2(x0,y0,x1,y1);
#ifdef MAPNIK_DEBUG
                std::clog << " layer1 - > " << layerExt << "\n";
                std::clog << " layer2 - > " << layerExt2 << "\n";
#endif
                if (first)
                {
                    ext = layerExt2;
                    first = false;
                }
                else
                {
                    ext.expand_to_include(layerExt2);
                }
                ++itr;
            }
            zoomToBox(ext);
        }
        catch (proj_init_error & ex)
        {
            std::clog << ex.what() << '\n';
        }
    }

    void Map::zoomToBox(const Envelope<double> &box)
    {
        currentExtent_=box;
        fixAspectRatio();
    }

    void Map::fixAspectRatio()
    {
        double ratio1 = (double) width_ / (double) height_;
        double ratio2 = currentExtent_.width() / currentExtent_.height();

        if (ratio2 > ratio1)
        {
            currentExtent_.height(currentExtent_.width() / ratio1);
        }
        else if (ratio2 < ratio1)
        {
            currentExtent_.width(currentExtent_.height() * ratio1);
        }
    }

    const Envelope<double>& Map::getCurrentExtent() const
    {
        return currentExtent_;
    }

    void Map::pan(int x,int y)
    {
        int dx = x - int(0.5 * width_);
        int dy = int(0.5 * height_) - y;
        double s = width_/currentExtent_.width();
        double minx  = currentExtent_.minx() + dx/s;
        double maxx  = currentExtent_.maxx() + dx/s;
        double miny  = currentExtent_.miny() + dy/s;
        double maxy  = currentExtent_.maxy() + dy/s;
        currentExtent_.init(minx,miny,maxx,maxy);
    }

    void Map::pan_and_zoom(int x,int y,double factor)
    {
        pan(x,y);
        zoom(factor);
    }

    double Map::scale() const
    {
        if (width_>0)
            return currentExtent_.width()/width_;
        return currentExtent_.width();
    }

    CoordTransform Map::view_transform() const
    {
        return CoordTransform(width_,height_,currentExtent_);
    }

    featureset_ptr Map::query_point(unsigned index, double lat, double lon) const
    {
        if ( index< layers_.size())
        {
            mapnik::Layer const& layer = layers_[index];
            try
            {
                double x = lon;
                double y = lat;
                double z = 0;
                mapnik::projection dest(srs_);
                dest.forward(x,y);
                mapnik::projection source(layer.srs());
                proj_transform prj_trans(source,dest);
                prj_trans.backward(x,y,z);

                double minx = currentExtent_.minx();
                double miny = currentExtent_.miny();
                double maxx = currentExtent_.maxx();
                double maxy = currentExtent_.maxy();

                prj_trans.backward(minx,miny,z);
                prj_trans.backward(maxx,maxy,z);
                double tol = (maxx - minx) / width_ * 3;
                mapnik::datasource_ptr ds = layer.datasource();
                if (ds)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n";
#endif
                    featureset_ptr fs(new filter_featureset<hit_test_filter>(ds->features_at_point(mapnik::coord2d(x,y)),
                                                                             hit_test_filter(x,y,tol)));
                    return fs;
                }
            }
            catch (...)
            {
#ifdef MAPNIK_DEBUG
                std::clog << "exception caught in \"query_map_point\"\n";
#endif
            }
        }
        return featureset_ptr();
    }

    featureset_ptr Map::query_map_point(unsigned index, double x, double y) const
    {
        if ( index< layers_.size())
        {
            mapnik::Layer const& layer = layers_[index];
            CoordTransform tr = view_transform();
            tr.backward(&x,&y);

            try
            {
                mapnik::projection dest(srs_);
                mapnik::projection source(layer.srs());
                proj_transform prj_trans(source,dest);
                double z = 0;
                prj_trans.backward(x,y,z);

                double minx = currentExtent_.minx();
                double miny = currentExtent_.miny();
                double maxx = currentExtent_.maxx();
                double maxy = currentExtent_.maxy();

                prj_trans.backward(minx,miny,z);
                prj_trans.backward(maxx,maxy,z);
                double tol = (maxx - minx) / width_ * 3;
                mapnik::datasource_ptr ds = layer.datasource();
                if (ds)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n";
#endif

                    featureset_ptr fs(new filter_featureset<hit_test_filter>(ds->features_at_point(mapnik::coord2d(x,y)),
                                                                             hit_test_filter(x,y,tol)));
                    return fs;
                }
            }
            catch (...)
            {
#ifdef MAPNIK_DEBUG
                std::clog << "exception caught in \"query_map_point\"\n";
#endif
            }
        }
        return featureset_ptr();
    }

    Map::~Map() {}
}
<commit_msg>check if featureset is valid before passing to filter_featureset<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: map.cpp 17 2005-03-08 23:58:43Z pavlenko $,

#include <mapnik/style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/filter_featureset.hpp>
#include <mapnik/hit_test_filter.hpp>
#include <mapnik/map.hpp>

namespace mapnik
{
    Map::Map()
        : width_(400),
          height_(400),
          srs_("+proj=latlong +datum=WGS84") {}

    Map::Map(int width,int height, std::string const& srs)
        : width_(width),
          height_(height),
          srs_(srs),
          background_(Color(255,255,255)) {}

    Map::Map(const Map& rhs)
        : width_(rhs.width_),
          height_(rhs.height_),
          srs_(rhs.srs_),
          background_(rhs.background_),
          styles_(rhs.styles_),
          layers_(rhs.layers_),
          currentExtent_(rhs.currentExtent_) {}

    Map& Map::operator=(const Map& rhs)
    {
        if (this==&rhs) return *this;
        width_=rhs.width_;
        height_=rhs.height_;
        srs_=rhs.srs_;
        background_=rhs.background_;
        styles_=rhs.styles_;
        layers_=rhs.layers_;
        return *this;
    }

    Map::style_iterator  Map::begin_styles() const
    {
        return styles_.begin();
    }
    Map::style_iterator  Map::end_styles() const
    {
        return styles_.end();
    }

    bool Map::insert_style(std::string const& name,feature_type_style const& style)
    {
        return styles_.insert(make_pair(name,style)).second;
    }

    void Map::remove_style(std::string const& name)
    {
        styles_.erase(name);
    }

    feature_type_style const& Map::find_style(std::string const& name) const
    {
        std::map<std::string,feature_type_style>::const_iterator itr = styles_.find(name);
        if (itr!=styles_.end())
            return itr->second;
        static feature_type_style default_style;
        return default_style;
    }

    size_t Map::layerCount() const
    {
        return layers_.size();
    }

    void Map::addLayer(const Layer& l)
    {
        layers_.push_back(l);
    }
    void Map::removeLayer(size_t index)
    {
        layers_.erase(layers_.begin()+index);
    }

    void Map::remove_all()
    {
        layers_.clear();
        styles_.clear();
    }

    const Layer& Map::getLayer(size_t index) const
    {
        return layers_[index];
    }

    Layer& Map::getLayer(size_t index)
    {
        return layers_[index];
    }

    std::vector<Layer> const& Map::layers() const
    {
        return layers_;
    }

    std::vector<Layer> & Map::layers()
    {
        return layers_;
    }

    unsigned Map::getWidth() const
    {
        return width_;
    }

    unsigned Map::getHeight() const
    {
        return height_;
    }

    void Map::setWidth(unsigned width)
    {
        if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE)
        {
            width_=width;
            fixAspectRatio();
        }
    }

    void Map::setHeight(unsigned height)
    {
        if (height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
        {
            height_=height;
            fixAspectRatio();
        }
    }

    void Map::resize(unsigned width,unsigned height)
    {
        if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE &&
            height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
        {
            width_=width;
            height_=height;
            fixAspectRatio();
        }
    }

    std::string const&  Map::srs() const
    {
        return srs_;
    }

    void Map::set_srs(std::string const& srs)
    {
        srs_ = srs;
    }

    void Map::setBackground(const Color& c)
    {
        background_=c;
    }

    const Color& Map::getBackground() const
    {
        return background_;
    }

    void Map::zoom(double factor)
    {
        coord2d center = currentExtent_.center();
        double w = factor * currentExtent_.width();
        double h = factor * currentExtent_.height();
        currentExtent_ = Envelope<double>(center.x - 0.5 * w,
                                          center.y - 0.5 * h,
                                          center.x + 0.5 * w,
                                          center.y + 0.5 * h);
        fixAspectRatio();
    }

    void Map::zoom_all()
    {
        try
        {
            projection proj0(srs_);
            Envelope<double> ext;
            bool first = true;
            std::vector<Layer>::const_iterator itr = layers_.begin();
            std::vector<Layer>::const_iterator end = layers_.end();
            while (itr != end)
            {
                std::string const& layer_srs = itr->srs();
                projection proj1(layer_srs);
                proj_transform prj_trans(proj0,proj1);

                Envelope<double> layerExt = itr->envelope();
                double x0 = layerExt.minx();
                double y0 = layerExt.miny();
                double z0 = 0.0;
                double x1 = layerExt.maxx();
                double y1 = layerExt.maxy();
                double z1 = 0.0;
                prj_trans.backward(x0,y0,z0);
                prj_trans.backward(x1,y1,z1);

                Envelope<double> layerExt2(x0,y0,x1,y1);
#ifdef MAPNIK_DEBUG
                std::clog << " layer1 - > " << layerExt << "\n";
                std::clog << " layer2 - > " << layerExt2 << "\n";
#endif
                if (first)
                {
                    ext = layerExt2;
                    first = false;
                }
                else
                {
                    ext.expand_to_include(layerExt2);
                }
                ++itr;
            }
            zoomToBox(ext);
        }
        catch (proj_init_error & ex)
        {
            std::clog << ex.what() << '\n';
        }
    }

    void Map::zoomToBox(const Envelope<double> &box)
    {
        currentExtent_=box;
        fixAspectRatio();
    }

    void Map::fixAspectRatio()
    {
        double ratio1 = (double) width_ / (double) height_;
        double ratio2 = currentExtent_.width() / currentExtent_.height();

        if (ratio2 > ratio1)
        {
            currentExtent_.height(currentExtent_.width() / ratio1);
        }
        else if (ratio2 < ratio1)
        {
            currentExtent_.width(currentExtent_.height() * ratio1);
        }
    }

    const Envelope<double>& Map::getCurrentExtent() const
    {
        return currentExtent_;
    }

    void Map::pan(int x,int y)
    {
        int dx = x - int(0.5 * width_);
        int dy = int(0.5 * height_) - y;
        double s = width_/currentExtent_.width();
        double minx  = currentExtent_.minx() + dx/s;
        double maxx  = currentExtent_.maxx() + dx/s;
        double miny  = currentExtent_.miny() + dy/s;
        double maxy  = currentExtent_.maxy() + dy/s;
        currentExtent_.init(minx,miny,maxx,maxy);
    }

    void Map::pan_and_zoom(int x,int y,double factor)
    {
        pan(x,y);
        zoom(factor);
    }

    double Map::scale() const
    {
        if (width_>0)
            return currentExtent_.width()/width_;
        return currentExtent_.width();
    }

    CoordTransform Map::view_transform() const
    {
        return CoordTransform(width_,height_,currentExtent_);
    }

    featureset_ptr Map::query_point(unsigned index, double lat, double lon) const
    {
        if ( index< layers_.size())
        {
            mapnik::Layer const& layer = layers_[index];
            try
            {
                double x = lon;
                double y = lat;
                double z = 0;
                mapnik::projection dest(srs_);
                dest.forward(x,y);
                mapnik::projection source(layer.srs());
                proj_transform prj_trans(source,dest);
                prj_trans.backward(x,y,z);

                double minx = currentExtent_.minx();
                double miny = currentExtent_.miny();
                double maxx = currentExtent_.maxx();
                double maxy = currentExtent_.maxy();

                prj_trans.backward(minx,miny,z);
                prj_trans.backward(maxx,maxy,z);
                double tol = (maxx - minx) / width_ * 3;
                mapnik::datasource_ptr ds = layer.datasource();
                if (ds)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n";
#endif
                    featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
                    if (fs)
                        return featureset_ptr(new filter_featureset<hit_test_filter>(fs,hit_test_filter(x,y,tol)));
                }
            }
            catch (...)
            {
#ifdef MAPNIK_DEBUG
                std::clog << "exception caught in \"query_map_point\"\n";
#endif
            }
        }
        return featureset_ptr();
    }

    featureset_ptr Map::query_map_point(unsigned index, double x, double y) const
    {
        if ( index< layers_.size())
        {
            mapnik::Layer const& layer = layers_[index];
            CoordTransform tr = view_transform();
            tr.backward(&x,&y);

            try
            {
                mapnik::projection dest(srs_);
                mapnik::projection source(layer.srs());
                proj_transform prj_trans(source,dest);
                double z = 0;
                prj_trans.backward(x,y,z);

                double minx = currentExtent_.minx();
                double miny = currentExtent_.miny();
                double maxx = currentExtent_.maxx();
                double maxy = currentExtent_.maxy();

                prj_trans.backward(minx,miny,z);
                prj_trans.backward(maxx,maxy,z);
                double tol = (maxx - minx) / width_ * 3;
                mapnik::datasource_ptr ds = layer.datasource();
                if (ds)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n";
#endif
                    featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
                    if (fs)
                        return featureset_ptr(new filter_featureset<hit_test_filter>(fs,hit_test_filter(x,y,tol)));
                }
            }
            catch (...)
            {
#ifdef MAPNIK_DEBUG
                std::clog << "exception caught in \"query_map_point\"\n";
#endif
            }
        }
        return featureset_ptr();
    }

    Map::~Map() {}
}
<|endoftext|>