<commit_before>#include "context.h"

#include <QAbstractEventDispatcher>
#include <QDebug>

#warning todo this needs to be a singleton as multiple contexts dont make sense and it makes it eaier to use from qml

static bool isGoodState(int eol)
{
    if (eol < 0) {
        // Error
        return false;
    }

    if (eol > 0) {
        // End of callback chain
        return false;
    }

    return true;
}

// --------------------------

static void sink_cb(pa_context *context, const pa_sink_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->sinkCallback(info);
}

static void sink_input_callback(pa_context *context, const pa_sink_input_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->sinkInputCallback(info);
}

static void client_cb(pa_context *context, const pa_client_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->clientCallback(info);
}

static void context_state_callback(pa_context *context, void *data)
{
    Q_ASSERT(data);
    ((Context *)data)->contextStateCallback(context);
}

static void subscribe_cb(pa_context *context, pa_subscription_event_type_t type, uint32_t index, void *data)
{
    Q_ASSERT(data);
    ((Context *)data)->subscribeCallback(context, type, index);
}

// --------------------------

Context::Context(QObject *parent)
    : QObject(parent)
    , m_context(nullptr)
    , m_mainloop(nullptr)
{
    // We require a glib event loop
    if (!QByteArray(QAbstractEventDispatcher::instance()->metaObject()->className()).contains("EventDispatcherGlib")) {
        qDebug() << "Disabling PulseAudio integration for lack of GLib event loop";
        return;
    }

    connectToDaemon();
}

Context::~Context()
{
    pa_context_unref(m_context);
    pa_glib_mainloop_free(m_mainloop);
}

void Context::subscribeCallback(pa_context *context, pa_subscription_event_type_t type, uint32_t index)
{
#warning fixme
//    Q_ASSERT(c == s_context);

    switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
#warning fixme
        case PA_SUBSCRIPTION_EVENT_SINK:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << "DEL Sink" << index;
                if (!m_sinks.contains(index)) {
                    m_recentlyDeletedSinks.insert(index);
                } else {
                    const int modelIndex = m_sinks.keys().indexOf(index);
                    m_sinks.take(index)->deleteLater();
                    emit sinkRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_info_by_index(context, index, sink_cb, this))) {
                    qWarning() << "pa_context_get_sink_info_by_index() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

//        case PA_SUBSCRIPTION_EVENT_SOURCE:
//            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
//                if (s_mixers.contains(KMIXPA_CAPTURE))
//                    s_mixers[KMIXPA_CAPTURE]->removeWidget(index);
//            } else {
//                pa_operation *o;
//                if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, NULL))) {
//                    qWarning() << "pa_context_get_source_info_by_index() failed";
//                    return;
//                }
//                pa_operation_unref(o);
//            }
//            break;

        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << Q_FUNC_INFO << "::: dropping :::" << index;
                if (!m_sinkInputs.contains(index)) {
                    m_recentlyDeletedSinkInputs.insert(index);
                } else {
                    const int modelIndex = m_sinkInputs.keys().indexOf(index);
                    m_sinkInputs.take(index)->deleteLater();
                    emit sinkInputRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_input_info(context, index, sink_input_callback, this))) {
                    qWarning() << "pa_context_get_sink_input_info() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

//        case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
//            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
//                if (s_mixers.contains(KMIXPA_APP_CAPTURE))
//                    s_mixers[KMIXPA_APP_CAPTURE]->removeWidget(index);
//            } else {
//                pa_operation *o;
//                if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, NULL))) {
//                    qWarning() << "pa_context_get_sink_input_info() failed";
//                    return;
//                }
//                pa_operation_unref(o);
//            }
//            break;

        case PA_SUBSCRIPTION_EVENT_CLIENT:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << "dropping client" << index;
                if (!m_clients.contains(index)) {
                    m_recentDeletedClients.insert(index);
                } else {
                    const int modelIndex = m_clients.keys().indexOf(index);
                    m_clients.take(index)->deleteLater();
                    emit clientRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_client_info(context, index, client_cb, this))) {
                    qWarning() << "pa_context_get_client_info() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

    }
}

void Context::contextStateCallback(pa_context *c)
{
    qDebug() << "state callback";
    pa_context_state_t state = pa_context_get_state(c);
    if (state == PA_CONTEXT_READY) {
        qDebug() << "ready";
        // Attempt to load things up
        pa_operation *o = nullptr;

        // 1. Register for the stream changes (except during probe)
        if (m_context == c) {
#warning fixme
            pa_context_set_subscribe_callback(c, subscribe_cb, this);

            if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
                                           (PA_SUBSCRIPTION_MASK_SINK|
                                            PA_SUBSCRIPTION_MASK_SOURCE|
                                            PA_SUBSCRIPTION_MASK_CLIENT|
                                            PA_SUBSCRIPTION_MASK_SINK_INPUT|
                                            PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) {
                qWarning() << "pa_context_subscribe() failed";
                return;
            }
            pa_operation_unref(o);
        }

#warning fixme
        if (!(o = pa_context_get_sink_info_list(c, sink_cb, this))) {
            qWarning() << "pa_context_get_sink_info_list() failed";
            return;
        }
        pa_operation_unref(o);

//        if (!(o = pa_context_get_source_info_list(c, source_cb, NULL))) {
//            qWarning() << "pa_context_get_source_info_list() failed";
//            return;
//        }
//        pa_operation_unref(o);

        if (!(o = pa_context_get_client_info_list(c, client_cb, this))) {
            qWarning() << "pa_context_client_info_list() failed";
            return;
        }
        pa_operation_unref(o);

        if (!(o = pa_context_get_sink_input_info_list(c, sink_input_callback, this))) {
            qWarning() << "pa_context_get_sink_input_info_list() failed";
            return;
        }
        pa_operation_unref(o);

//        if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, NULL))) {
//            qWarning() << "pa_context_get_source_output_info_list() failed";
//            return;
//        }
//        pa_operation_unref(o);

        /* These calls are not always supported */
//        if ((o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, NULL))) {
//            pa_operation_unref(o);

//            pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, NULL);

//            if ((o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL)))
//                pa_operation_unref(o);
//        } else {
//            qWarning() << "Failed to initialize stream_restore extension: " << pa_strerror(pa_context_errno(m_context));
//        }
    } else if (!PA_CONTEXT_IS_GOOD(state)) {
        qDebug() << "context kaput";
        // If this is our probe phase, exit our context immediately
        if (m_context != c) {
            pa_context_disconnect(c);
        } else {
            // If we're not probing, it means we've been disconnected from our
            // glib context
            pa_context_unref(m_context);
            m_context = nullptr;

#warning fixme
            // This one is not handled above.
//            clients.clear();
        }
    }
}

#warning data changed should possibly only be emitted once eol is >0 to avoid pointless redraws

template <typename C, typename PAInfo, typename AddedSignal, typename UpdatedSignal>
void Context::updateMap(QMap<quint32, C *> &map,
                        QSet<quint32> &exclusionSet,
                        const PAInfo *info,
                        AddedSignal addedSignal,
                        UpdatedSignal updatedSignal)
{
    Q_ASSERT(info);

    if (exclusionSet.remove(info->index)) {
        // Was already removed again.
        return;
    }

    const bool isNew = !map.contains(info->index);

    auto *obj = map.value(info->index, nullptr);
    if (!obj) {
        obj = new C;
    }
    obj->setInfo(info);
    map.insert(info->index, obj);

    const int modelIndex = map.keys().indexOf(info->index);
    Q_ASSERT(modelIndex >= 0);

    if (isNew) {
        emit (this->*addedSignal)(modelIndex);
    } else {
        emit (this->*updatedSignal)(modelIndex);
    }
}

#warning fixme recentlydeleted has the same type for everything making it easy to use the wrong one possibly
void Context::sinkCallback(const pa_sink_info *info)
{
    updateMap<Sink, pa_sink_info>(m_sinks, m_recentlyDeletedSinks,
                                  info,
                                  &Context::sinkAdded,
                                  &Context::sinkUpdated);
}

void Context::clientCallback(const pa_client_info *info)
{
    updateMap<Client, pa_client_info>(m_clients, m_recentDeletedClients,
                                      info,
                                      &Context::clientAdded,
                                      &Context::clientUpdated);
}

void Context::sinkInputCallback(const pa_sink_input_info *info)
{
    updateMap<SinkInput, pa_sink_input_info>(m_sinkInputs, m_recentlyDeletedSinkInputs,
                                             info,
                                             &Context::sinkInputAdded,
                                             &Context::sinkInputUpdated);
}

void Context::setSinkVolume(quint32 index, quint32 volume)
{
    qDebug() << Q_FUNC_INFO << index << volume;
#warning fixme volume limit enforcement needs review for sensibility
    if (volume > 65536)
        return;
    pa_operation *o;
    Sink *sink = m_sinks.value(index, nullptr);
    if (!sink)
        return;
    pa_cvolume newVolume = sink->volume();
    for (int i = 0; i < newVolume.channels; ++i) {
        newVolume.values[i] = volume;
    }
    if (!(o = pa_context_set_sink_volume_by_index(m_context, index, &newVolume, NULL, NULL))) {
        qWarning() <<  "pa_context_set_sink_volume_by_index() failed";
        return;
    }
    pa_operation_unref(o);
}

void Context::setSinkPort(quint32 portIndex)
{
    pa_operation *o;
    if (!(o = pa_context_set_sink_port_by_index(m_context, portIndex, nullptr, nullptr, nullptr))) {
        qWarning() << "pa_context_set_sink_port_by_index failed";
        return;
    }
}

void Context::setSinkInputVolume(quint32 index, quint32 volume)
{
    qDebug() << Q_FUNC_INFO << index << volume;
#warning fixme volume limit enforcement needs review for sensibility also this prevents overdrive
    if (volume > 65536)
        return;
    pa_operation *o;
    SinkInput *obj = m_sinkInputs.value(index, nullptr);
    if (!obj)
        return;
    pa_cvolume newVolume = obj->volume();
    for (int i = 0; i < newVolume.channels; ++i) {
        newVolume.values[i] = volume;
    }
    if (!(o = pa_context_set_sink_input_volume(m_context, index, &newVolume, NULL, NULL))) {
        qWarning() <<  "pa_context_set_sink_volume_by_index() failed";
        return;
    }
    pa_operation_unref(o);
}

void Context::connectToDaemon()
{
    Q_ASSERT(m_context == nullptr);
    Q_ASSERT(m_mainloop == nullptr);

    qDebug() <<  "Attempting connection to PulseAudio sound daemon";
    m_mainloop = pa_glib_mainloop_new(nullptr);
    pa_mainloop_api *api = pa_glib_mainloop_get_api(m_mainloop);
    Q_ASSERT(api);

    m_context = pa_context_new(api, "QPulse");
    Q_ASSERT(m_context);

    if (pa_context_connect(m_context, NULL, PA_CONTEXT_NOFAIL, 0) < 0) {
        pa_context_unref(m_context);
        m_context = nullptr;
        return;
    }
    pa_context_set_state_callback(m_context, &context_state_callback, this);
}
<commit_msg>align pa_operation constructs<commit_after>#include "context.h"

#include <QAbstractEventDispatcher>
#include <QDebug>

#warning todo this needs to be a singleton as multiple contexts dont make sense and it makes it eaier to use from qml

static bool isGoodState(int eol)
{
    if (eol < 0) {
        // Error
        return false;
    }

    if (eol > 0) {
        // End of callback chain
        return false;
    }

    return true;
}

// --------------------------

static void sink_cb(pa_context *context, const pa_sink_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->sinkCallback(info);
}

static void sink_input_callback(pa_context *context, const pa_sink_input_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->sinkInputCallback(info);
}

static void client_cb(pa_context *context, const pa_client_info *info, int eol, void *data)
{
    if (!isGoodState(eol))
        return;
    Q_ASSERT(context);
    Q_ASSERT(data);
    ((Context *)data)->clientCallback(info);
}

static void context_state_callback(pa_context *context, void *data)
{
    Q_ASSERT(data);
    ((Context *)data)->contextStateCallback(context);
}

static void subscribe_cb(pa_context *context, pa_subscription_event_type_t type, uint32_t index, void *data)
{
    Q_ASSERT(data);
    ((Context *)data)->subscribeCallback(context, type, index);
}

// --------------------------

Context::Context(QObject *parent)
    : QObject(parent)
    , m_context(nullptr)
    , m_mainloop(nullptr)
{
    // We require a glib event loop
    if (!QByteArray(QAbstractEventDispatcher::instance()->metaObject()->className()).contains("EventDispatcherGlib")) {
        qDebug() << "Disabling PulseAudio integration for lack of GLib event loop";
        return;
    }

    connectToDaemon();
}

Context::~Context()
{
    pa_context_unref(m_context);
    pa_glib_mainloop_free(m_mainloop);
}

void Context::subscribeCallback(pa_context *context, pa_subscription_event_type_t type, uint32_t index)
{
#warning fixme
//    Q_ASSERT(c == s_context);

    switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
#warning fixme
        case PA_SUBSCRIPTION_EVENT_SINK:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << "DEL Sink" << index;
                if (!m_sinks.contains(index)) {
                    m_recentlyDeletedSinks.insert(index);
                } else {
                    const int modelIndex = m_sinks.keys().indexOf(index);
                    m_sinks.take(index)->deleteLater();
                    emit sinkRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_info_by_index(context, index, sink_cb, this))) {
                    qWarning() << "pa_context_get_sink_info_by_index() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

//        case PA_SUBSCRIPTION_EVENT_SOURCE:
//            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
//                if (s_mixers.contains(KMIXPA_CAPTURE))
//                    s_mixers[KMIXPA_CAPTURE]->removeWidget(index);
//            } else {
//                pa_operation *o;
//                if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, NULL))) {
//                    qWarning() << "pa_context_get_source_info_by_index() failed";
//                    return;
//                }
//                pa_operation_unref(o);
//            }
//            break;

        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << Q_FUNC_INFO << "::: dropping :::" << index;
                if (!m_sinkInputs.contains(index)) {
                    m_recentlyDeletedSinkInputs.insert(index);
                } else {
                    const int modelIndex = m_sinkInputs.keys().indexOf(index);
                    m_sinkInputs.take(index)->deleteLater();
                    emit sinkInputRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_sink_input_info(context, index, sink_input_callback, this))) {
                    qWarning() << "pa_context_get_sink_input_info() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

//        case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
//            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
//                if (s_mixers.contains(KMIXPA_APP_CAPTURE))
//                    s_mixers[KMIXPA_APP_CAPTURE]->removeWidget(index);
//            } else {
//                pa_operation *o;
//                if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, NULL))) {
//                    qWarning() << "pa_context_get_sink_input_info() failed";
//                    return;
//                }
//                pa_operation_unref(o);
//            }
//            break;

        case PA_SUBSCRIPTION_EVENT_CLIENT:
            if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
                qDebug() << "dropping client" << index;
                if (!m_clients.contains(index)) {
                    m_recentDeletedClients.insert(index);
                } else {
                    const int modelIndex = m_clients.keys().indexOf(index);
                    m_clients.take(index)->deleteLater();
                    emit clientRemoved(modelIndex);
                }
            } else {
                pa_operation *o;
                if (!(o = pa_context_get_client_info(context, index, client_cb, this))) {
                    qWarning() << "pa_context_get_client_info() failed";
                    return;
                }
                pa_operation_unref(o);
            }
            break;

    }
}

void Context::contextStateCallback(pa_context *c)
{
    qDebug() << "state callback";
    pa_context_state_t state = pa_context_get_state(c);
    if (state == PA_CONTEXT_READY) {
        qDebug() << "ready";
        // Attempt to load things up
        pa_operation *o = nullptr;

        // 1. Register for the stream changes (except during probe)
        if (m_context == c) {
#warning fixme
            pa_context_set_subscribe_callback(c, subscribe_cb, this);

            if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
                                           (PA_SUBSCRIPTION_MASK_SINK|
                                            PA_SUBSCRIPTION_MASK_SOURCE|
                                            PA_SUBSCRIPTION_MASK_CLIENT|
                                            PA_SUBSCRIPTION_MASK_SINK_INPUT|
                                            PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) {
                qWarning() << "pa_context_subscribe() failed";
                return;
            }
            pa_operation_unref(o);
        }

#warning fixme
        if (!(o = pa_context_get_sink_info_list(c, sink_cb, this))) {
            qWarning() << "pa_context_get_sink_info_list() failed";
            return;
        }
        pa_operation_unref(o);

//        if (!(o = pa_context_get_source_info_list(c, source_cb, NULL))) {
//            qWarning() << "pa_context_get_source_info_list() failed";
//            return;
//        }
//        pa_operation_unref(o);

        if (!(o = pa_context_get_client_info_list(c, client_cb, this))) {
            qWarning() << "pa_context_client_info_list() failed";
            return;
        }
        pa_operation_unref(o);

        if (!(o = pa_context_get_sink_input_info_list(c, sink_input_callback, this))) {
            qWarning() << "pa_context_get_sink_input_info_list() failed";
            return;
        }
        pa_operation_unref(o);

//        if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, NULL))) {
//            qWarning() << "pa_context_get_source_output_info_list() failed";
//            return;
//        }
//        pa_operation_unref(o);

        /* These calls are not always supported */
//        if ((o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, NULL))) {
//            pa_operation_unref(o);

//            pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, NULL);

//            if ((o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL)))
//                pa_operation_unref(o);
//        } else {
//            qWarning() << "Failed to initialize stream_restore extension: " << pa_strerror(pa_context_errno(m_context));
//        }
    } else if (!PA_CONTEXT_IS_GOOD(state)) {
        qDebug() << "context kaput";
        // If this is our probe phase, exit our context immediately
        if (m_context != c) {
            pa_context_disconnect(c);
        } else {
            // If we're not probing, it means we've been disconnected from our
            // glib context
            pa_context_unref(m_context);
            m_context = nullptr;

#warning fixme
            // This one is not handled above.
//            clients.clear();
        }
    }
}

#warning data changed should possibly only be emitted once eol is >0 to avoid pointless redraws

template <typename C, typename PAInfo, typename AddedSignal, typename UpdatedSignal>
void Context::updateMap(QMap<quint32, C *> &map,
                        QSet<quint32> &exclusionSet,
                        const PAInfo *info,
                        AddedSignal addedSignal,
                        UpdatedSignal updatedSignal)
{
    Q_ASSERT(info);

    if (exclusionSet.remove(info->index)) {
        // Was already removed again.
        return;
    }

    const bool isNew = !map.contains(info->index);

    auto *obj = map.value(info->index, nullptr);
    if (!obj) {
        obj = new C;
    }
    obj->setInfo(info);
    map.insert(info->index, obj);

    const int modelIndex = map.keys().indexOf(info->index);
    Q_ASSERT(modelIndex >= 0);

    if (isNew) {
        emit (this->*addedSignal)(modelIndex);
    } else {
        emit (this->*updatedSignal)(modelIndex);
    }
}

#warning fixme recentlydeleted has the same type for everything making it easy to use the wrong one possibly
void Context::sinkCallback(const pa_sink_info *info)
{
    updateMap<Sink, pa_sink_info>(m_sinks, m_recentlyDeletedSinks,
                                  info,
                                  &Context::sinkAdded,
                                  &Context::sinkUpdated);
}

void Context::clientCallback(const pa_client_info *info)
{
    updateMap<Client, pa_client_info>(m_clients, m_recentDeletedClients,
                                      info,
                                      &Context::clientAdded,
                                      &Context::clientUpdated);
}

void Context::sinkInputCallback(const pa_sink_input_info *info)
{
    updateMap<SinkInput, pa_sink_input_info>(m_sinkInputs, m_recentlyDeletedSinkInputs,
                                             info,
                                             &Context::sinkInputAdded,
                                             &Context::sinkInputUpdated);
}

void Context::setSinkVolume(quint32 index, quint32 volume)
{
    qDebug() << Q_FUNC_INFO << index << volume;
#warning fixme volume limit enforcement needs review for sensibility
    if (volume > 65536)
        return;
    Sink *sink = m_sinks.value(index, nullptr);
    if (!sink)
        return;
    pa_cvolume newVolume = sink->volume();
    for (int i = 0; i < newVolume.channels; ++i) {
        newVolume.values[i] = volume;
    }
    pa_operation *o;
    if (!(o = pa_context_set_sink_volume_by_index(m_context, index, &newVolume, NULL, NULL))) {
        qWarning() <<  "pa_context_set_sink_volume_by_index() failed";
        return;
    }
    pa_operation_unref(o);
}

void Context::setSinkPort(quint32 portIndex)
{
    pa_operation *o;
    if (!(o = pa_context_set_sink_port_by_index(m_context, portIndex, nullptr, nullptr, nullptr))) {
        qWarning() << "pa_context_set_sink_port_by_index failed";
        return;
    }
}

void Context::setSinkInputVolume(quint32 index, quint32 volume)
{
    qDebug() << Q_FUNC_INFO << index << volume;
#warning fixme volume limit enforcement needs review for sensibility also this prevents overdrive
    if (volume > 65536)
        return;
    pa_operation *o;
    SinkInput *obj = m_sinkInputs.value(index, nullptr);
    if (!obj)
        return;
    pa_cvolume newVolume = obj->volume();
    for (int i = 0; i < newVolume.channels; ++i) {
        newVolume.values[i] = volume;
    }
    if (!(o = pa_context_set_sink_input_volume(m_context, index, &newVolume, NULL, NULL))) {
        qWarning() <<  "pa_context_set_sink_volume_by_index() failed";
        return;
    }
    pa_operation_unref(o);
}

void Context::connectToDaemon()
{
    Q_ASSERT(m_context == nullptr);
    Q_ASSERT(m_mainloop == nullptr);

    qDebug() <<  "Attempting connection to PulseAudio sound daemon";
    m_mainloop = pa_glib_mainloop_new(nullptr);
    pa_mainloop_api *api = pa_glib_mainloop_get_api(m_mainloop);
    Q_ASSERT(api);

    m_context = pa_context_new(api, "QPulse");
    Q_ASSERT(m_context);

    if (pa_context_connect(m_context, NULL, PA_CONTEXT_NOFAIL, 0) < 0) {
        pa_context_unref(m_context);
        m_context = nullptr;
        return;
    }
    pa_context_set_state_callback(m_context, &context_state_callback, this);
}
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include <mutex>
#include <array>
#include <string>

#include "r200.h"
#include "f200.h"
#include "sr300.h"
#include "zr300.h"
#include "ds5d.h"
#include "ds5c.h"
#include "ds5t.h"
#include "uvc.h"
#include "context.h"

#define constexpr_support 1

#ifdef _MSC_VER
#if (_MSC_VER <= 1800) // constexpr is not supported in MSVC2013
#undef constexpr_support
#define constexpr_support 0
#endif
#endif

#if (constexpr_support == 1)
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

constexpr auto rs_api_version = concat("VERSION: ",RS_API_VERSION_STR);

#else    // manual version tracking is required
static const std::string rs_api_version("VERSION: 1.9.3");

#endif

bool is_compatible(std::shared_ptr<rs_device> device)
{
    return device->supports(RS_CAPABILITIES_ENUMERATION);
}

rs_context_base::rs_context_base()
{
    context = rsimpl::uvc::create_context();

    for(auto device : query_devices(context))
    {
        LOG_INFO("UVC device detected with VID = 0x" << std::hex << get_vendor_id(*device) << " PID = 0x" << get_product_id(*device));

        if (get_vendor_id(*device) != VID_INTEL_CAMERA)
            continue;

        std::shared_ptr<rs_device> rs_dev;

        switch(get_product_id(*device))
        {
            case R200_PRODUCT_ID:  	rs_dev = rsimpl::make_r200_device(device); break;
            case LR200_PRODUCT_ID: 	rs_dev = rsimpl::make_lr200_device(device); break;
            case ZR300_PRODUCT_ID: 	rs_dev = rsimpl::make_zr300_device(device); break;
            case F200_PRODUCT_ID:  	rs_dev = rsimpl::make_f200_device(device); break;
            case SR300_PRODUCT_ID: 	rs_dev = rsimpl::make_sr300_device(device); break;
            case DS5_PSR_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5d_passive_device(device); break;
            case DS5_ASR_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5d_active_device(device); break;
            case DS5_ASRC_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5c_rolling_device(device); break;
            case DS5_AWGC_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5c_global_wide_device(device); break;
            case DS5_AWGCT_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5t_device(device); break;
        }

        if (rs_dev && is_compatible(rs_dev))
        {
            devices.push_back(rs_dev);
        }
        else
        {
            LOG_ERROR("Device is not supported by librealsense!");
        }
    }
}

// Enforce singleton semantics on rs_context
rs_context* rs_context_base::instance = nullptr;
int rs_context_base::ref_count = 0;
std::mutex rs_context_base::instance_lock;
std::string rs_context_base::api_version = std::string(rs_api_version.begin(),rs_api_version.end());

rs_context* rs_context_base::acquire_instance()
{
    std::lock_guard<std::mutex> lock(instance_lock);
    if (ref_count++ == 0)
    {
        instance = new rs_context_base();
    }
    return instance;
}

void rs_context_base::release_instance()
{
    std::lock_guard<std::mutex> lock(instance_lock);
    if (--ref_count == 0)
    {
        delete instance;
    }
}

rs_context_base::~rs_context_base()
{
    assert(ref_count == 0);
}

size_t rs_context_base::get_device_count() const
{
    return devices.size();
}

rs_device* rs_context_base::get_device(int index) const
{
    return devices[index].get();
}
<commit_msg>Fix version string for VS2013 build<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include <mutex>
#include <array>
#include <string>

#include "r200.h"
#include "f200.h"
#include "sr300.h"
#include "zr300.h"
#include "ds5d.h"
#include "ds5c.h"
#include "ds5t.h"
#include "uvc.h"
#include "context.h"

#define constexpr_support 1

#ifdef _MSC_VER
#if (_MSC_VER <= 1800) // constexpr is not supported in MSVC2013
#undef constexpr_support
#define constexpr_support 0
#endif
#endif

#if (constexpr_support == 1)
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

constexpr auto rs_api_version = concat("VERSION: ",RS_API_VERSION_STR);

#else    // manual version tracking is required
static const std::string rs_api_version("VERSION: 1.9.5");

#endif

bool is_compatible(std::shared_ptr<rs_device> device)
{
    return device->supports(RS_CAPABILITIES_ENUMERATION);
}

rs_context_base::rs_context_base()
{
    context = rsimpl::uvc::create_context();

    for(auto device : query_devices(context))
    {
        LOG_INFO("UVC device detected with VID = 0x" << std::hex << get_vendor_id(*device) << " PID = 0x" << get_product_id(*device));

        if (get_vendor_id(*device) != VID_INTEL_CAMERA)
            continue;

        std::shared_ptr<rs_device> rs_dev;

        switch(get_product_id(*device))
        {
            case R200_PRODUCT_ID:  	rs_dev = rsimpl::make_r200_device(device); break;
            case LR200_PRODUCT_ID: 	rs_dev = rsimpl::make_lr200_device(device); break;
            case ZR300_PRODUCT_ID: 	rs_dev = rsimpl::make_zr300_device(device); break;
            case F200_PRODUCT_ID:  	rs_dev = rsimpl::make_f200_device(device); break;
            case SR300_PRODUCT_ID: 	rs_dev = rsimpl::make_sr300_device(device); break;
            case DS5_PSR_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5d_passive_device(device); break;
            case DS5_ASR_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5d_active_device(device); break;
            case DS5_ASRC_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5c_rolling_device(device); break;
            case DS5_AWGC_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5c_global_wide_device(device); break;
            case DS5_AWGCT_PRODUCT_ID: 	rs_dev = rsimpl::make_ds5t_device(device); break;
        }

        if (rs_dev && is_compatible(rs_dev))
        {
            devices.push_back(rs_dev);
        }
        else
        {
            LOG_ERROR("Device is not supported by librealsense!");
        }
    }
}

// Enforce singleton semantics on rs_context
rs_context* rs_context_base::instance = nullptr;
int rs_context_base::ref_count = 0;
std::mutex rs_context_base::instance_lock;
std::string rs_context_base::api_version = std::string(rs_api_version.begin(),rs_api_version.end());

rs_context* rs_context_base::acquire_instance()
{
    std::lock_guard<std::mutex> lock(instance_lock);
    if (ref_count++ == 0)
    {
        instance = new rs_context_base();
    }
    return instance;
}

void rs_context_base::release_instance()
{
    std::lock_guard<std::mutex> lock(instance_lock);
    if (--ref_count == 0)
    {
        delete instance;
    }
}

rs_context_base::~rs_context_base()
{
    assert(ref_count == 0);
}

size_t rs_context_base::get_device_count() const
{
    return devices.size();
}

rs_device* rs_context_base::get_device(int index) const
{
    return devices[index].get();
}
<|endoftext|>


<commit_before>/*
 * JSDX Framework
 *
 * Copyright(c) 2012 Fred Chien <fred@mandice.com>
 *
 */

#include <v8.h>
#include <node.h>

#include "jsdx_toolkit.hpp"
#include "context.hpp"

namespace JSDXToolkit {

	using namespace node;
	using namespace v8;

	static struct gcontext g_context;
	static uv_prepare_t prepare_handle;
	static uv_check_t check_handle;

	Context::Context() {}

	void Context::Init()
	{
		GMainContext *gc = g_main_context_default();

		struct gcontext *ctx = &g_context;

		if (!g_thread_supported())
			g_thread_init(NULL);

		g_main_context_acquire(gc);
		ctx->gc = g_main_context_ref(gc);
		ctx->nfds = 0;
		ctx->fds = NULL;

		/* Prepare */
		uv_prepare_init(uv_default_loop(), &prepare_handle);
		uv_prepare_start(&prepare_handle, prepare_cb);

		/* Check */
		uv_check_init(uv_default_loop(), &check_handle);
		uv_check_start(&check_handle, check_cb);
	}

	void Context::Uninit()
	{
		struct gcontext *ctx = &g_context;

		uv_check_stop(&check_handle);
		uv_close((uv_handle_t *)&check_handle, NULL);

		uv_prepare_stop(&prepare_handle);
		uv_close((uv_handle_t *)&prepare_handle, NULL);

		g_main_context_unref(ctx->gc);
	}

	void Context::poll_cb(uv_poll_t *handle, int status, int events)
	{
		struct gcontext_pollfd *_pfd = (struct gcontext_pollfd *)handle->data;

		GPollFD *pfd = _pfd->pfd;

		pfd->revents |= pfd->events & ((events & UV_READABLE ? G_IO_IN : 0) | (events & UV_WRITABLE ? G_IO_OUT : 0));

		uv_poll_stop(handle);
		uv_close((uv_handle_t *)handle, NULL);
		delete _pfd;
	}

	void Context::prepare_cb(uv_prepare_t *handle, int status)
	{
		gint i;
		gint timeout;
		struct gcontext *ctx = &g_context;

		g_main_context_wakeup(ctx->gc);
		g_main_context_prepare(ctx->gc, &ctx->max_priority);

		/* Getting all sources from GLib main context */
		while((ctx->nfds = g_main_context_query(ctx->gc, ctx->max_priority, &timeout, ctx->fds, ctx->allocated_nfds)) > ctx->allocated_nfds) {
			g_free(ctx->fds);
			g_free(ctx->poll_handles);

			ctx->allocated_nfds = 1;
			while (ctx->allocated_nfds < ctx->nfds) {
				ctx->allocated_nfds <<= 1;
			}

			ctx->fds = g_new(GPollFD, ctx->allocated_nfds);
			ctx->poll_handles = g_new(uv_poll_t, ctx->allocated_nfds);
		}

		/* Poll */
		for (i = 0; i < ctx->nfds; ++i) {
			GPollFD *pfd = ctx->fds + i;
			uv_poll_t *pt = ctx->poll_handles + i;

			struct gcontext_pollfd *data = new gcontext_pollfd;
			data->pfd = pfd;
			pt->data = data;

			pfd->revents = 0;

			uv_poll_init(uv_default_loop(), pt, pfd->fd);
			uv_poll_start(pt, UV_READABLE | UV_WRITABLE, poll_cb);
		}
	}

	void Context::check_cb(uv_check_t *handle, int status)
	{
		gint i;
		struct gcontext *ctx = &g_context;

		/* Release all polling events which aren't finished yet. */
		for (i = 0; i < ctx->nfds; ++i) {
			uv_poll_t *pt = ctx->poll_handles + i;

			if (uv_is_active((uv_handle_t *)pt)) {
				uv_poll_stop(pt);
				uv_close((uv_handle_t *)pt, NULL);
				delete (struct gcontext_pollfd *)pt->data;
			}
		}

		if (ctx->nfds)
			g_main_context_check(ctx->gc, ctx->max_priority, ctx->fds, ctx->nfds);

		g_main_context_dispatch(ctx->gc);
	}
}
<commit_msg>Little fixes<commit_after>/*
 * JSDX Framework
 *
 * Copyright(c) 2012 Fred Chien <fred@mandice.com>
 *
 */

#include <v8.h>
#include <node.h>

#include "jsdx_toolkit.hpp"
#include "context.hpp"

namespace JSDXToolkit {

	using namespace node;
	using namespace v8;

	static struct gcontext g_context;
	static uv_prepare_t prepare_handle;
	static uv_check_t check_handle;

	Context::Context() {}

	void Context::Init()
	{
		GMainContext *gc = g_main_context_default();

		struct gcontext *ctx = &g_context;

		if (!g_thread_supported())
			g_thread_init(NULL);

		g_main_context_acquire(gc);
		ctx->gc = g_main_context_ref(gc);
		ctx->nfds = 0;
		ctx->fds = NULL;

		/* Prepare */
		uv_prepare_init(uv_default_loop(), &prepare_handle);
		uv_prepare_start(&prepare_handle, prepare_cb);

		/* Check */
		uv_check_init(uv_default_loop(), &check_handle);
		uv_check_start(&check_handle, check_cb);
	}

	void Context::Uninit()
	{
		struct gcontext *ctx = &g_context;

		uv_check_stop(&check_handle);
		uv_close((uv_handle_t *)&check_handle, NULL);

		uv_prepare_stop(&prepare_handle);
		uv_close((uv_handle_t *)&prepare_handle, NULL);

		g_main_context_unref(ctx->gc);
	}

	void Context::poll_cb(uv_poll_t *handle, int status, int events)
	{
		struct gcontext_pollfd *_pfd = (struct gcontext_pollfd *)handle->data;

		GPollFD *pfd = _pfd->pfd;

		pfd->revents |= pfd->events & ((events & UV_READABLE ? G_IO_IN : 0) | (events & UV_WRITABLE ? G_IO_OUT : 0));

		uv_poll_stop(handle);
		uv_close((uv_handle_t *)handle, NULL);
		delete _pfd;
	}

	void Context::prepare_cb(uv_prepare_t *handle, int status)
	{
		gint i;
		gint timeout;
		struct gcontext *ctx = &g_context;

		g_main_context_prepare(ctx->gc, &ctx->max_priority);

		/* Getting all sources from GLib main context */
		while((ctx->nfds = g_main_context_query(ctx->gc, ctx->max_priority, &timeout, ctx->fds, ctx->allocated_nfds)) > ctx->allocated_nfds) {
			g_free(ctx->fds);
			g_free(ctx->poll_handles);

			ctx->allocated_nfds = ctx->nfds;

			ctx->fds = g_new(GPollFD, ctx->nfds);
			ctx->poll_handles = g_new(uv_poll_t, ctx->nfds);
		}

		/* Poll */
		for (i = 0; i < ctx->nfds; ++i) {
			GPollFD *pfd = ctx->fds + i;
			uv_poll_t *pt = ctx->poll_handles + i;

			struct gcontext_pollfd *data = new gcontext_pollfd;
			data->pfd = pfd;
			pt->data = data;

			pfd->revents = 0;

			uv_poll_init(uv_default_loop(), pt, pfd->fd);
			uv_poll_start(pt, UV_READABLE | UV_WRITABLE, poll_cb);
		}
	}

	void Context::check_cb(uv_check_t *handle, int status)
	{
		gint i;
		struct gcontext *ctx = &g_context;

		/* Release all polling events which aren't finished yet. */
		for (i = 0; i < ctx->nfds; ++i) {
			GPollFD *pfd = ctx->fds + i;
			uv_poll_t *pt = ctx->poll_handles + i;

			if (uv_is_active((uv_handle_t *)pt)) {
				uv_poll_stop(pt);
				uv_close((uv_handle_t *)pt, NULL);
				delete (struct gcontext_pollfd *)pt->data;
			}
		}

		g_main_context_check(ctx->gc, ctx->max_priority, ctx->fds, ctx->nfds);
		g_main_context_dispatch(ctx->gc);
	}
}
<|endoftext|>


<commit_before>#include "control.hpp"
#include "model.hpp"

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <sstream>

#include "omp.h"

namespace Control {
	bool control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		using namespace Model;
		mesh_t mesh(50, 50,
		[](float s, float t, std::vector<float> &vertices) {
			vertices.emplace_back(-s*s-t*t); // X
			vertices.emplace_back(2*s-1); // Y
			vertices.emplace_back(2*t-1); // Z
		});

		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size(),
			(void*) &mesh.vertices[0], GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_fbuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
			viewer.ids[view::e_id_fbuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.faces.size(),
			(void*) &mesh.faces[0], GL_STATIC_DRAW);
		viewer.nTriangles = mesh.faces.size()/3;
		return alive;
		/*
		// Task 2: wavefront obj model loading
		using namespace Model;
		obj_t object;
		auto status = obj_t::load(this -> mpath, object);
		if(status != obj_t::e_ok) {
			errors.push_back("The model failed to load.");
			return alive = false;
		}

		glGenBuffers(view::e_id_model-view::e_id_vbuf,
				&viewer.ids[view::e_id_vbuf]);
		// TODO Use more than first range of each obj type
		if(object.v_beg.size() == 0) {
			errors.push_back("The loaded model does not contain vertices.");
			return alive = false;
		} else {
			auto v0 = object.v_beg[0], v1 = object.v_end[0];
			glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
			glBufferData(GL_ARRAY_BUFFER, v1-v0,
					(void*)(&object.floats[v0]), GL_STATIC_DRAW);
		}
		if(object.vn_beg.size() != 0) {
			auto vn0 = object.vn_beg[0], vn1 = object.vn_end[0];
			glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vnbuf]);
			glBufferData(GL_ARRAY_BUFFER, vn1-vn0,
					(void*)(&object.floats[vn0]), GL_STATIC_DRAW);
		}
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_fbuf]);
		int f0, f1;
		if(object.f0_beg.size() != 0) {
			f0 = object.f0_beg[0];
			f1 = object.f0_end[0];
		} else if(object.f1_beg.size() != 0) {
			f0 = object.f1_beg[0];
			f1 = object.f1_end[0];
		} else if(object.f2_beg.size() != 0) {
			f0 = object.f2_beg[0];
			f1 = object.f2_end[0];
		} else if(object.f3_beg.size() != 0) {
			f0 = object.f3_beg[0];
			f1 = object.f3_end[0];
		} else {
			errors.push_back("The loaded model does not contain faces.");
			return alive = false;
		}
		viewer.nTriangles = (f1-f0)/3;
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, viewer.nTriangles*3,
				(void*)(&object.ints[f0]), GL_STATIC_DRAW);*/

		/*
		// Task 2: model loading
		using namespace Model::Ply;
 		Header model(this -> mpath);
 		if(model.status) {
			std::cout << model.statusContext << std::endl;
			return;
		}
		auto start = begin(model.elements),
				 stop = end(model.elements);
		auto vertices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				// TODO Change behavior based on the number of elements
				return el.name == "vertex" && !el.has_list;
		}), indices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				int sz = el.properties.size();
				return el.name == "face"
					&& (el.has_list ? sz==1 : sz==3);
		});
		if(vertices == stop || indices == stop) {
			std::cout << "The model is valid, but does not match "
				"the anticipated structure." << std::endl;
			return;
		Task 3: view after model
		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, vertices->data.size(),
				(void*)(&vertices->data[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices->data.size(),
				(void*)(&indices->data[0]), GL_STATIC_DRAW);
		viewer.nTriangles = indices -> instances;
		glUseProgram(viewer.ids[view::e_id_prog]);*/
	}

	bool control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			for(int i = 0; i < nButtons; i++) {
				bool pressed = buttons[i] == GLFW_PRESS;
				if(i==8 && pressed)
					alive = false;
			}
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			for(int i = 0; i < nAxes; i++) {
				if(i == 0) {
					viewer.theta = axes[i]*2 + 1.5;
				} else if(i == 1) {
					viewer.phi = axes[i];
				}
			}
		}
		return alive;
	}

	bool control::run(std::atomic_bool &alive) {
		using namespace Model::Ply;
		auto delay = std::chrono::milliseconds(150);

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			if(poll(alive)) viewer.run(alive);
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
		return alive;
	}

	control::control(std::atomic_bool &alive, const char *mpath):
		task(), mpath(mpath), viewer(alive) {}
}
<commit_msg>Updated to use x,y parameters<commit_after>#include "control.hpp"
#include "model.hpp"

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <sstream>

#include "omp.h"

namespace Control {
	bool control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		using namespace Model;
		mesh_t mesh(50, 50,
		[](float s, float t, std::vector<float> &vertices) {
			vertices.emplace_back(2*s-1);   // X
			vertices.emplace_back(s*s+t*t); // Y
			vertices.emplace_back(2*t-1);   // Z
		});

		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size(),
			(void*) &mesh.vertices[0], GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_fbuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
			viewer.ids[view::e_id_fbuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.faces.size(),
			(void*) &mesh.faces[0], GL_STATIC_DRAW);
		viewer.nTriangles = mesh.faces.size()/3;
		return alive;
		/*
		// Task 2: wavefront obj model loading
		using namespace Model;
		obj_t object;
		auto status = obj_t::load(this -> mpath, object);
		if(status != obj_t::e_ok) {
			errors.push_back("The model failed to load.");
			return alive = false;
		}

		glGenBuffers(view::e_id_model-view::e_id_vbuf,
				&viewer.ids[view::e_id_vbuf]);
		// TODO Use more than first range of each obj type
		if(object.v_beg.size() == 0) {
			errors.push_back("The loaded model does not contain vertices.");
			return alive = false;
		} else {
			auto v0 = object.v_beg[0], v1 = object.v_end[0];
			glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
			glBufferData(GL_ARRAY_BUFFER, v1-v0,
					(void*)(&object.floats[v0]), GL_STATIC_DRAW);
		}
		if(object.vn_beg.size() != 0) {
			auto vn0 = object.vn_beg[0], vn1 = object.vn_end[0];
			glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vnbuf]);
			glBufferData(GL_ARRAY_BUFFER, vn1-vn0,
					(void*)(&object.floats[vn0]), GL_STATIC_DRAW);
		}
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_fbuf]);
		int f0, f1;
		if(object.f0_beg.size() != 0) {
			f0 = object.f0_beg[0];
			f1 = object.f0_end[0];
		} else if(object.f1_beg.size() != 0) {
			f0 = object.f1_beg[0];
			f1 = object.f1_end[0];
		} else if(object.f2_beg.size() != 0) {
			f0 = object.f2_beg[0];
			f1 = object.f2_end[0];
		} else if(object.f3_beg.size() != 0) {
			f0 = object.f3_beg[0];
			f1 = object.f3_end[0];
		} else {
			errors.push_back("The loaded model does not contain faces.");
			return alive = false;
		}
		viewer.nTriangles = (f1-f0)/3;
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, viewer.nTriangles*3,
				(void*)(&object.ints[f0]), GL_STATIC_DRAW);*/

		/*
		// Task 2: model loading
		using namespace Model::Ply;
 		Header model(this -> mpath);
 		if(model.status) {
			std::cout << model.statusContext << std::endl;
			return;
		}
		auto start = begin(model.elements),
				 stop = end(model.elements);
		auto vertices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				// TODO Change behavior based on the number of elements
				return el.name == "vertex" && !el.has_list;
		}), indices = std::find_if(start, stop,
			[](Element const& el) -> bool {
				int sz = el.properties.size();
				return el.name == "face"
					&& (el.has_list ? sz==1 : sz==3);
		});
		if(vertices == stop || indices == stop) {
			std::cout << "The model is valid, but does not match "
				"the anticipated structure." << std::endl;
			return;
		Task 3: view after model
		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, vertices->data.size(),
				(void*)(&vertices->data[0]), GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_ibuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
				viewer.ids[view::e_id_ibuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices->data.size(),
				(void*)(&indices->data[0]), GL_STATIC_DRAW);
		viewer.nTriangles = indices -> instances;
		glUseProgram(viewer.ids[view::e_id_prog]);*/
	}

	bool control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			for(int i = 0; i < nButtons; i++) {
				if(buttons[i] == GLFW_PRESS) {
					if(i == 8) alive = false;
					else std::cout << i << std::endl;
				}
			}
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			for(int i = 0; i < nAxes; i++) {
				if(i == 0) {
					viewer.theta = axes[i]*M_PI;
				} else if(i == 1) {
					viewer.phi = axes[i]*M_PI;
				} else if(i == 6) {
					viewer.x += axes[i]/10;
				} else if(i == 7) {
					viewer.y += axes[i]/10;
				}
			}
		}
		return alive;
	}

	bool control::run(std::atomic_bool &alive) {
		using namespace Model::Ply;
		auto delay = std::chrono::milliseconds(150);

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			if(poll(alive)) viewer.run(alive);
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
		return alive;
	}

	control::control(std::atomic_bool &alive, const char *mpath):
		task(), mpath(mpath), viewer(alive) {}
}
<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "test.h"

#if (_JNC_OS_WIN)
int
wmain (
	int argc,
	wchar_t* argv []
	)
#else
int
main (
	int argc,
	char* argv []
	)
#endif
{
#if _AXL_OS_POSIX
	setvbuf (stdout, NULL, _IOLBF, 1024);
#endif

	printf ("Initializing...\n");

	if (argc < 2)
	{
		printf ("usage: jnc_test_abi <script.jnc>\n");
		return -1;
	}

#if (_JNC_OS_WIN)
	sl::String sourcefileName = argv [1];
#else
	sl::StringRef sourcefileName = argv [1];
#endif

	bool result;

	g::getModule ()->setTag ("jnc_test_abi");
	jnc::initialize ("jnc_dll:jnc_test_abi");
	jnc::setErrorRouter (err::getErrorMgr ());
	lex::registerParseErrorProvider ();

	srand ((int) sys::getTimestamp ());

	jnc::AutoModule module;
	jnc::AutoRuntime runtime;

	module->initialize ("jnc_module");
	module->addStaticLib (jnc::StdLib_getLib ());
	module->addStaticLib (TestLib_getLib ());

	printf ("Compiling...\n");

	result =
		module->parseFile (sourcefileName) &&
		module->parseImports () &&
		module->compile () &&
		module->jit ();

	if (!result)
	{
		printf ("Error: %s\n", err::getLastErrorDescription ().sz ());
		return -1;
	}

	printf ("Starting up runtime...\n");

	result = runtime->startup (module);
	if (!result)
	{
		printf ("Error: %s\n", err::getLastErrorDescription ().sz ());
		return -1;
	}

	int retval = 0;

	JNC_BEGIN_CALL_SITE (runtime)

	c2jnc::testInt32 (module);
	c2jnc::testInt64 (module);
	c2jnc::testStruct32 (module);
	c2jnc::testStruct64 (module);
	c2jnc::testStruct128 (module);
	c2jnc::testVariant (module);
	c2jnc::testFloat (module);
	c2jnc::testDouble (module);

	jnc2c::test (module, "jnc2c.testInt32");
	jnc2c::test (module, "jnc2c.testInt64");
	jnc2c::test (module, "jnc2c.testStruct32");
	jnc2c::test (module, "jnc2c.testStruct64");
	jnc2c::test (module, "jnc2c.testStruct128");
	jnc2c::test (module, "jnc2c.testVariant");
	jnc2c::test (module, "jnc2c.testPtr");
	jnc2c::test (module, "jnc2c.testFloat");
	jnc2c::test (module, "jnc2c.testDouble");

	JNC_CALL_SITE_CATCH ()

	printf ("Runtime exception caught: %s\n", err::getLastErrorDescription ().sz ());
	retval = -1;

	JNC_END_CALL_SITE ()

	printf ("Shutting down...\n");
	runtime->shutdown ();

	printf ("Done.\n");
	return retval;
}

//..............................................................................
<commit_msg>[test] minor compile erro fix on posix<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "test.h"

#if (_JNC_OS_WIN)
int
wmain (
	int argc,
	wchar_t* argv []
	)
#else
int
main (
	int argc,
	char* argv []
	)
#endif
{
#if _AXL_OS_POSIX
	setvbuf (stdout, NULL, _IOLBF, 1024);
#endif

	printf ("Initializing...\n");

	if (argc < 2)
	{
		printf ("usage: jnc_test_abi <script.jnc>\n");
		return -1;
	}

#if (_JNC_OS_WIN)
	sl::String sourceFileName = argv [1]; // utf16 -> utf8
#else
	const char* sourceFileName = argv [1];
#endif

	bool result;

	g::getModule ()->setTag ("jnc_test_abi");
	jnc::initialize ("jnc_dll:jnc_test_abi");
	jnc::setErrorRouter (err::getErrorMgr ());
	lex::registerParseErrorProvider ();

	srand ((int) sys::getTimestamp ());

	jnc::AutoModule module;
	jnc::AutoRuntime runtime;

	module->initialize ("jnc_module");
	module->addStaticLib (jnc::StdLib_getLib ());
	module->addStaticLib (TestLib_getLib ());

	printf ("Compiling...\n");

	result =
		module->parseFile (sourceFileName) &&
		module->parseImports () &&
		module->compile () &&
		module->jit ();

	if (!result)
	{
		printf ("Error: %s\n", err::getLastErrorDescription ().sz ());
		return -1;
	}

	printf ("Starting up runtime...\n");

	result = runtime->startup (module);
	if (!result)
	{
		printf ("Error: %s\n", err::getLastErrorDescription ().sz ());
		return -1;
	}

	int retval = 0;

	JNC_BEGIN_CALL_SITE (runtime)

	c2jnc::testInt32 (module);
	c2jnc::testInt64 (module);
	c2jnc::testStruct32 (module);
	c2jnc::testStruct64 (module);
	c2jnc::testStruct128 (module);
	c2jnc::testVariant (module);
	c2jnc::testFloat (module);
	c2jnc::testDouble (module);

	jnc2c::test (module, "jnc2c.testInt32");
	jnc2c::test (module, "jnc2c.testInt64");
	jnc2c::test (module, "jnc2c.testStruct32");
	jnc2c::test (module, "jnc2c.testStruct64");
	jnc2c::test (module, "jnc2c.testStruct128");
	jnc2c::test (module, "jnc2c.testVariant");
	jnc2c::test (module, "jnc2c.testPtr");
	jnc2c::test (module, "jnc2c.testFloat");
	jnc2c::test (module, "jnc2c.testDouble");

	JNC_CALL_SITE_CATCH ()

	printf ("Runtime exception caught: %s\n", err::getLastErrorDescription ().sz ());
	retval = -1;

	JNC_END_CALL_SITE ()

	printf ("Shutting down...\n");
	runtime->shutdown ();

	printf ("Done.\n");
	return retval;
}

//..............................................................................
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2017 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *  @file SinogramCreatorMC.cpp
 */

#include "SinogramCreatorMC.h"
#include <TH1F.h>
#include <TH2I.h>
using namespace jpet_options_tools;

SinogramCreatorMC::SinogramCreatorMC(const char* name) : SinogramCreator(name) {}

SinogramCreatorMC::~SinogramCreatorMC() {}

bool SinogramCreatorMC::init()
{
  SinogramCreatorMC::setUpOptions();
  fOutputEvents = new JPetTimeWindow("JPetEvent");

  getStatistics().createHistogram(new TH2I("reconstruction_histogram", "reconstruction_histogram histogram",
                                  std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1, 0.f,
                                  fMaxReconstructionLayerRadius, kReconstructionMaxAngle, 0, kReconstructionMaxAngle));

  getStatistics().createHistogram(
    new TH1F("pos_dis", "Position distance real data", (fMaxReconstructionLayerRadius) * 10 * 5, 0.f, fMaxReconstructionLayerRadius));
  getStatistics().createHistogram(new TH1F("angle", "Position angle real data", kReconstructionMaxAngle, 0, kReconstructionMaxAngle));

#if ROOT_VERSION_CODE < ROOT_VERSION(6, 0, 0)
  getStatistics().getObject<TH2I>("reconstruction_histogram")->SetBit(TH2::kCanRebin);
  getStatistics().getObject<TH1F>("angle")->SetBit(TH1::kCanRebin);
  getStatistics().getObject<TH1F>("pos_dis")->SetBit(TH1::kCanRebin);
#else
  getStatistics().getObject<TH2I>("reconstruction_histogram")->SetCanExtend(TH1::kAllAxes);
  getStatistics().getObject<TH1F>("angle")->SetCanExtend(TH1::kAllAxes);
  getStatistics().getObject<TH1F>("pos_dis")->SetCanExtend(TH1::kAllAxes);
#endif

  generateSinogram();
  return true;
}

void SinogramCreatorMC::generateSinogram()
{
  float firstX = 0.f;
  float firstY = 0.f;
  float secondX = 0.f;
  float secondY = 0.f;
  float firstZ = 0.f;
  float secondZ = 0.f;
  float firstT = 0.f;
  float secondT = 0.f;
  float skip = 0.f;
  int coincidence = 0;

  int numberOfCorrectHits = 0;
  int totalHits = 1; // to make sure that we do not divide by 0

  const int maxDistanceNumber = std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1;
  if (fSinogram == nullptr) {
    fSinogram = new JPetRecoImageTools::Matrix2DProj*[fZSplitNumber];
    for (int i = 0; i < fZSplitNumber; i++) {
      fSinogram[i] = new JPetRecoImageTools::Matrix2DProj(maxDistanceNumber, kReconstructionMaxAngle, 0);
    }
  }

  for (const auto& inputPath : fInputData) {
    std::ifstream in(inputPath);
    while (in.peek() != EOF) {

      in >> firstX >> firstY >> firstZ >> firstT >> secondX >> secondY >> secondZ >> secondT >> skip >> skip >> skip >> skip >> coincidence >> skip >>
          skip >> skip;

        if(coincidence != 1) // 1 == true event
          continue;

      if (analyzeHits(firstX, firstY, firstZ, firstT, secondX, secondY, secondZ, secondT)) {
        numberOfCorrectHits++;
      }
      totalHits++;
    }
  }

  std::cout << "Correct hits: " << numberOfCorrectHits << " total hits: " << totalHits
            << " (correct percentage: " << (((float)numberOfCorrectHits * 100.f) / (float)totalHits) << "%)" << std::endl;
}

bool SinogramCreatorMC::exec()
{
  return true;
}

bool SinogramCreatorMC::terminate()
{
  for (int i = 0; i < fZSplitNumber; i++) {
    saveResult((*fSinogram[i]), fOutFileName + "_" + std::to_string(i) + ".ppm");
  }

  JPetFilterNone noneFilter;
  JPetRecoImageTools::FourierTransformFunction f = JPetRecoImageTools::doFFTW;

  for (int i = 0; i < fZSplitNumber; i++) {
    //JPetRecoImageTools::Matrix2DProj result =
    //  JPetRecoImageTools::backProjectWithTOF((*fSinogram[i]), fTOFInformation[i], (*fSinogram[i])[0].size(), JPetRecoImageTools::nonRescale, 0, 255);

    //saveResult(result, fOutFileName + "reconstruction_with_tof_" + std::to_string(i) + ".ppm");
    JPetRecoImageTools::Matrix2DProj filteredSinogram = JPetRecoImageTools::FilterSinogram(f, noneFilter, (*fSinogram[i]));
    JPetRecoImageTools::Matrix2DProj resultBP =
      JPetRecoImageTools::backProject(filteredSinogram, (*fSinogram[i])[0].size(), JPetRecoImageTools::nonRescale, 0, 255);

    saveResult(resultBP, fOutFileName + "reconstruction_" + std::to_string(i) + ".ppm");
  }

  delete[] fSinogram;
  delete[] fMaxValueInSinogram;

  return true;
}

void SinogramCreatorMC::setUpOptions()
{
  auto opts = getOptions();
  if (isOptionSet(opts, kOutFileNameKey)) {
    fOutFileName = getOptionAsString(opts, kOutFileNameKey);
  }

  if (isOptionSet(opts, kReconstructionDistanceAccuracy)) {
    fReconstructionDistanceAccuracy = getOptionAsFloat(opts, kReconstructionDistanceAccuracy);
  }

  if (isOptionSet(opts, kZSplitNumber)) {
    fZSplitNumber = getOptionAsInt(opts, kZSplitNumber);
  }

  if (isOptionSet(opts, kScintillatorLenght)) {
    fScintillatorLenght = getOptionAsFloat(opts, kScintillatorLenght);
  }

  if (isOptionSet(opts, kMaxReconstructionRadius)) {
    fMaxReconstructionLayerRadius = getOptionAsFloat(opts, kMaxReconstructionRadius);
  }

  if (isOptionSet(opts, kInputDataKey)) {
    fInputData = getOptionAsVectorOfStrings(opts, kInputDataKey);
  }

  if (isOptionSet(opts, kEnableObliqueLORRemapping)) {
    fEnableObliqueLORRemapping = getOptionAsBool(opts, kEnableObliqueLORRemapping);
  }

  if (isOptionSet(opts, kEnableTOFReconstruction)) {
    fEnableKDEReconstruction = getOptionAsBool(opts, kEnableTOFReconstruction);
  }

  fTOFInformation = new JPetRecoImageTools::Matrix2DTOF[fZSplitNumber];
  fMaxValueInSinogram = new int[fZSplitNumber];
  fCurrentValueInSinogram = new int[fZSplitNumber];
  const float maxZRange = fScintillatorLenght / 2.f;
  float range = (2.f * maxZRange) / fZSplitNumber;
  for (int i = 0; i < fZSplitNumber; i++) {
    float rangeStart = (i * range) - maxZRange;
    float rangeEnd = ((i + 1) * range) - maxZRange;
    fZSplitRange.push_back(std::make_pair(rangeStart, rangeEnd));
    fCurrentValueInSinogram[i] = 0;
    fMaxValueInSinogram[i] = 0;
  }

  fMaxDistanceNumber = std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1;
}<commit_msg>Fix multipe input files<commit_after>/**
 *  @copyright Copyright 2017 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *  @file SinogramCreatorMC.cpp
 */

#include "SinogramCreatorMC.h"
#include <TH1F.h>
#include <TH2I.h>
using namespace jpet_options_tools;

SinogramCreatorMC::SinogramCreatorMC(const char* name) : SinogramCreator(name) {}

SinogramCreatorMC::~SinogramCreatorMC() {}

bool SinogramCreatorMC::init()
{
  SinogramCreatorMC::setUpOptions();
  fOutputEvents = new JPetTimeWindow("JPetEvent");

  getStatistics().createHistogram(new TH2I("reconstruction_histogram", "reconstruction_histogram histogram",
                                  std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1, 0.f,
                                  fMaxReconstructionLayerRadius, kReconstructionMaxAngle, 0, kReconstructionMaxAngle));

  getStatistics().createHistogram(
    new TH1F("pos_dis", "Position distance real data", (fMaxReconstructionLayerRadius) * 10 * 5, 0.f, fMaxReconstructionLayerRadius));
  getStatistics().createHistogram(new TH1F("angle", "Position angle real data", kReconstructionMaxAngle, 0, kReconstructionMaxAngle));

#if ROOT_VERSION_CODE < ROOT_VERSION(6, 0, 0)
  getStatistics().getObject<TH2I>("reconstruction_histogram")->SetBit(TH2::kCanRebin);
  getStatistics().getObject<TH1F>("angle")->SetBit(TH1::kCanRebin);
  getStatistics().getObject<TH1F>("pos_dis")->SetBit(TH1::kCanRebin);
#else
  getStatistics().getObject<TH2I>("reconstruction_histogram")->SetCanExtend(TH1::kAllAxes);
  getStatistics().getObject<TH1F>("angle")->SetCanExtend(TH1::kAllAxes);
  getStatistics().getObject<TH1F>("pos_dis")->SetCanExtend(TH1::kAllAxes);
#endif

  generateSinogram();
  return true;
}

void SinogramCreatorMC::generateSinogram()
{
  float firstX = 0.f;
  float firstY = 0.f;
  float secondX = 0.f;
  float secondY = 0.f;
  float firstZ = 0.f;
  float secondZ = 0.f;
  float firstT = 0.f;
  float secondT = 0.f;
  float skip = 0.f;
  int coincidence = 0;

  int numberOfCorrectHits = 0;
  int totalHits = 1; // to make sure that we do not divide by 0

  const int maxDistanceNumber = std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1;
  if (fSinogram == nullptr) {
    fSinogram = new JPetRecoImageTools::Matrix2DProj *[fZSplitNumber];
    for (int i = 0; i < fZSplitNumber; i++) {
      fSinogram[i] = new JPetRecoImageTools::Matrix2DProj(fMaxDistanceNumber, (std::vector<double>(kReconstructionMaxAngle, 0)));
    }
  }

  for (const auto& inputPath : fInputData) {
    std::ifstream in(inputPath);
    while (in.peek() != EOF) {

      in >> firstX >> firstY >> firstZ >> firstT >> secondX >> secondY >> secondZ >> secondT >> skip >> skip >> skip >> skip >> coincidence >> skip >>
          skip >> skip;

        if(coincidence != 1) // 1 == true event
          continue;

      if (analyzeHits(firstX, firstY, firstZ, firstT, secondX, secondY, secondZ, secondT)) {
        numberOfCorrectHits++;
      }
      totalHits++;
    }
  }

  std::cout << "Correct hits: " << numberOfCorrectHits << " total hits: " << totalHits
            << " (correct percentage: " << (((float)numberOfCorrectHits * 100.f) / (float)totalHits) << "%)" << std::endl;
}

bool SinogramCreatorMC::exec()
{
  return true;
}

bool SinogramCreatorMC::terminate()
{
  for (int i = 0; i < fZSplitNumber; i++) {
    saveResult((*fSinogram[i]), fOutFileName + "_" + std::to_string(i) + ".ppm");
  }

  JPetFilterNone noneFilter;
  JPetRecoImageTools::FourierTransformFunction f = JPetRecoImageTools::doFFTW;

  for (int i = 0; i < fZSplitNumber; i++) {
    //JPetRecoImageTools::Matrix2DProj result =
    //  JPetRecoImageTools::backProjectWithTOF((*fSinogram[i]), fTOFInformation[i], (*fSinogram[i])[0].size(), JPetRecoImageTools::nonRescale, 0, 255);

    //saveResult(result, fOutFileName + "reconstruction_with_tof_" + std::to_string(i) + ".ppm");
    JPetRecoImageTools::Matrix2DProj filteredSinogram = JPetRecoImageTools::FilterSinogram(f, noneFilter, (*fSinogram[i]));
    JPetRecoImageTools::Matrix2DProj resultBP =
      JPetRecoImageTools::backProject(filteredSinogram, (*fSinogram[i])[0].size(), JPetRecoImageTools::nonRescale, 0, 255);

    saveResult(resultBP, fOutFileName + "reconstruction_" + std::to_string(i) + ".ppm");
  }

  delete[] fSinogram;
  delete[] fMaxValueInSinogram;

  return true;
}

void SinogramCreatorMC::setUpOptions()
{
  auto opts = getOptions();
  if (isOptionSet(opts, kOutFileNameKey)) {
    fOutFileName = getOptionAsString(opts, kOutFileNameKey);
  }

  if (isOptionSet(opts, kReconstructionDistanceAccuracy)) {
    fReconstructionDistanceAccuracy = getOptionAsFloat(opts, kReconstructionDistanceAccuracy);
  }

  if (isOptionSet(opts, kZSplitNumber)) {
    fZSplitNumber = getOptionAsInt(opts, kZSplitNumber);
  }

  if (isOptionSet(opts, kScintillatorLenght)) {
    fScintillatorLenght = getOptionAsFloat(opts, kScintillatorLenght);
  }

  if (isOptionSet(opts, kMaxReconstructionRadius)) {
    fMaxReconstructionLayerRadius = getOptionAsFloat(opts, kMaxReconstructionRadius);
  }

  if (isOptionSet(opts, kInputDataKey)) {
    fInputData = getOptionAsVectorOfStrings(opts, kInputDataKey);
  }

  if (isOptionSet(opts, kEnableObliqueLORRemapping)) {
    fEnableObliqueLORRemapping = getOptionAsBool(opts, kEnableObliqueLORRemapping);
  }

  if (isOptionSet(opts, kEnableTOFReconstruction)) {
    fEnableKDEReconstruction = getOptionAsBool(opts, kEnableTOFReconstruction);
  }

  fTOFInformation = new JPetRecoImageTools::Matrix2DTOF[fZSplitNumber];
  fMaxValueInSinogram = new int[fZSplitNumber];
  fCurrentValueInSinogram = new int[fZSplitNumber];
  const float maxZRange = fScintillatorLenght / 2.f;
  float range = (2.f * maxZRange) / fZSplitNumber;
  for (int i = 0; i < fZSplitNumber; i++) {
    float rangeStart = (i * range) - maxZRange;
    float rangeEnd = ((i + 1) * range) - maxZRange;
    fZSplitRange.push_back(std::make_pair(rangeStart, rangeEnd));
    fCurrentValueInSinogram[i] = 0;
    fMaxValueInSinogram[i] = 0;
  }

  fMaxDistanceNumber = std::ceil(fMaxReconstructionLayerRadius * 2 * (1.f / fReconstructionDistanceAccuracy)) + 1;
}<|endoftext|>


<commit_before>//===--- PassManagerVerifierAnalysis.cpp ----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-passmanager-verifier-analysis"
#include "swift/SILOptimizer/Analysis/PassManagerVerifierAnalysis.h"
#include "swift/SIL/SILModule.h"
#include "llvm/Support/CommandLine.h"

static llvm::cl::opt<bool>
    EnableVerifier("enable-sil-passmanager-verifier-analysis",
                   llvm::cl::desc("Enable verification of the passmanagers "
                                  "function notification infrastructure"),
                   llvm::cl::init(false));

using namespace swift;

PassManagerVerifierAnalysis::PassManagerVerifierAnalysis(SILModule *mod)
    : SILAnalysis(SILAnalysisKind::PassManagerVerifier), mod(*mod) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  for (auto &fn : *mod) {
    LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add: " << fn.getName()
                            << '\n');
    liveFunctionNames.insert(fn.getName());
  }
#endif
}

/// Validate that the analysis is able to look up all functions and that those
/// functions are live.
void PassManagerVerifierAnalysis::invalidate() {}

/// Validate that the analysis is able to look up the given function.
void PassManagerVerifierAnalysis::invalidate(SILFunction *f,
                                             InvalidationKind k) {}

/// If a function has not yet been seen start tracking it.
void PassManagerVerifierAnalysis::notifyAddedOrModifiedFunction(
    SILFunction *f) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add|Mod: " << f->getName()
                          << '\n');
  liveFunctionNames.insert(f->getName());
#endif
}

/// Stop tracking a function.
void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Delete: " << f->getName()
                          << '\n');
  if (liveFunctionNames.erase(f->getName()))
    return;

  llvm::errs()
      << "Error! Tried to delete function that analysis was not aware of: "
      << f->getName() << '\n';
  llvm_unreachable("triggering standard assertion failure routine");
#endif
}

/// Make sure that when we invalidate a function table, make sure we can find
/// all functions for all witness tables.
void PassManagerVerifierAnalysis::invalidateFunctionTables() {}

/// Run the entire verification.
void PassManagerVerifierAnalysis::verifyFull() const {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;

  // We check that liveFunctionNames is in sync with the module's function list
  // by going through the module's function list and attempting to remove all
  // functions in the module. If we fail to remove fn, then we know that a
  // function was added to the module without an appropriate message being sent
  // by the pass manager.
  bool foundError = false;

  unsigned count = 0;
  for (auto &fn : mod) {
    if (liveFunctionNames.count(fn.getName())) {
      ++count;
      continue;
    }
    llvm::errs() << "Found function in module that was not added to verifier: "
                 << fn.getName() << '\n';
    foundError = true;
  }

  // Ok, so now we know that function(mod) is a subset of
  // liveFunctionNames. Relying on the uniqueness provided by the module's
  // function list, we know that liveFunction should be exactly count in
  // size. Otherwise, we must have an error. If and only if we detect this
  // error, do the expensive work of finding the missing deletes. This is an
  // important performance optimization to avoid a large copy on the hot path.
  if (liveFunctionNames.size() != count) {
    auto liveFunctionNamesCopy = llvm::StringSet<>(liveFunctionNames);
    for (auto &fn : mod) {
      liveFunctionNamesCopy.erase(fn.getName());
    }
    for (auto &iter : liveFunctionNamesCopy) {
      llvm::errs() << "Missing delete message for function: " << iter.first()
                   << '\n';
      foundError = true;
    }
  }

  // We assert here so we emit /all/ errors before asserting.
  assert(!foundError && "triggering standard assertion failure routine");
#endif
}

//===----------------------------------------------------------------------===//
//                              Main Entry Point
//===----------------------------------------------------------------------===//

SILAnalysis *swift::createPassManagerVerifierAnalysis(SILModule *m) {
  return new PassManagerVerifierAnalysis(m);
}
<commit_msg>[analysis] Turn on the pass manager notification verifier analysis.<commit_after>//===--- PassManagerVerifierAnalysis.cpp ----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-passmanager-verifier-analysis"
#include "swift/SILOptimizer/Analysis/PassManagerVerifierAnalysis.h"
#include "swift/SIL/SILModule.h"
#include "llvm/Support/CommandLine.h"

static llvm::cl::opt<bool>
    EnableVerifier("enable-sil-passmanager-verifier-analysis",
                   llvm::cl::desc("Enable verification of the passmanagers "
                                  "function notification infrastructure"),
                   llvm::cl::init(true));

using namespace swift;

PassManagerVerifierAnalysis::PassManagerVerifierAnalysis(SILModule *mod)
    : SILAnalysis(SILAnalysisKind::PassManagerVerifier), mod(*mod) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  for (auto &fn : *mod) {
    LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add: " << fn.getName()
                            << '\n');
    liveFunctionNames.insert(fn.getName());
  }
#endif
}

/// Validate that the analysis is able to look up all functions and that those
/// functions are live.
void PassManagerVerifierAnalysis::invalidate() {}

/// Validate that the analysis is able to look up the given function.
void PassManagerVerifierAnalysis::invalidate(SILFunction *f,
                                             InvalidationKind k) {}

/// If a function has not yet been seen start tracking it.
void PassManagerVerifierAnalysis::notifyAddedOrModifiedFunction(
    SILFunction *f) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add|Mod: " << f->getName()
                          << '\n');
  liveFunctionNames.insert(f->getName());
#endif
}

/// Stop tracking a function.
void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;
  LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Delete: " << f->getName()
                          << '\n');
  if (liveFunctionNames.erase(f->getName()))
    return;

  llvm::errs()
      << "Error! Tried to delete function that analysis was not aware of: "
      << f->getName() << '\n';
  llvm_unreachable("triggering standard assertion failure routine");
#endif
}

/// Make sure that when we invalidate a function table, make sure we can find
/// all functions for all witness tables.
void PassManagerVerifierAnalysis::invalidateFunctionTables() {}

/// Run the entire verification.
void PassManagerVerifierAnalysis::verifyFull() const {
#ifndef NDEBUG
  if (!EnableVerifier)
    return;

  // We check that liveFunctionNames is in sync with the module's function list
  // by going through the module's function list and attempting to remove all
  // functions in the module. If we fail to remove fn, then we know that a
  // function was added to the module without an appropriate message being sent
  // by the pass manager.
  bool foundError = false;

  unsigned count = 0;
  for (auto &fn : mod) {
    if (liveFunctionNames.count(fn.getName())) {
      ++count;
      continue;
    }
    llvm::errs() << "Found function in module that was not added to verifier: "
                 << fn.getName() << '\n';
    foundError = true;
  }

  // Ok, so now we know that function(mod) is a subset of
  // liveFunctionNames. Relying on the uniqueness provided by the module's
  // function list, we know that liveFunction should be exactly count in
  // size. Otherwise, we must have an error. If and only if we detect this
  // error, do the expensive work of finding the missing deletes. This is an
  // important performance optimization to avoid a large copy on the hot path.
  if (liveFunctionNames.size() != count) {
    auto liveFunctionNamesCopy = llvm::StringSet<>(liveFunctionNames);
    for (auto &fn : mod) {
      liveFunctionNamesCopy.erase(fn.getName());
    }
    for (auto &iter : liveFunctionNamesCopy) {
      llvm::errs() << "Missing delete message for function: " << iter.first()
                   << '\n';
      foundError = true;
    }
  }

  // We assert here so we emit /all/ errors before asserting.
  assert(!foundError && "triggering standard assertion failure routine");
#endif
}

//===----------------------------------------------------------------------===//
//                              Main Entry Point
//===----------------------------------------------------------------------===//

SILAnalysis *swift::createPassManagerVerifierAnalysis(SILModule *m) {
  return new PassManagerVerifierAnalysis(m);
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 * CommandPrompt.cpp
 *
 *  Created on: Jan 18, 2011
 *      Author: Dimitar Asenov
 **********************************************************************************************************************/

#include "vis/CommandPrompt.h"
#include "vis/TextAndDescription.h"
#include "handlers/GenericHandler.h"
#include "commands/CommandExecutionEngine.h"

#include "VisualizationBase/headers/Scene.h"

using namespace Visualization;

namespace Interaction {

/**
 * Specifies the minimal height of the commandReceiver item which will make a new prompt appear in the center of the
 * item.
 *
 * If the receiver item's height is less than this number, then the prompt will be placed directly under the item.
 * Otherwise the prompt will be centered inside the item.
 */
const int COMMAND_RECEIVER_ITEM_MIN_PROMPT_CENTER_HEIGHT = 50;

/**
 * The distance between a prompt which is shown under the command receiver item and that item.
 */
const int PROMPT_TO_RECEIVER_DISTANCE = 3;

ITEM_COMMON_DEFINITIONS(CommandPrompt)

CommandPrompt::CommandPrompt(Item* commandReceiver, const CommandPromptStyle* style) :
	Item(NULL, style),
	commandReceiver_(commandReceiver),
	layout(new SequentialLayout(this, &style->layout())),
	suggestionContainer(new SequentialLayout(NULL, &style->suggestionContainer())),
	errorContainer(new SequentialLayout(NULL, &style->errorContainer())),
	command( new Text(NULL, &style->commandText())),
	result_(NULL),
	justCreated(true)
{
	setFlag(QGraphicsItem::ItemIsMovable);

	layout->append(command);
	layout->append(errorContainer);
	layout->append(suggestionContainer);
}

CommandPrompt::~CommandPrompt()
{
	commandReceiver_ = NULL; // This item is completely out of our control, we just know about it.

	removeResult();
	removeSuggestions();

	SAFE_DELETE_ITEM(layout);

	// These are deleted by layout's destructor
	command = NULL;
	suggestionContainer = NULL;
	errorContainer = NULL;
}

void CommandPrompt::initializeCommand()
{
	command->setText("Type a command");
	command->setFocus();
	command->selectAll();
}

void CommandPrompt::takeSuggestion(CommandSuggestion* suggestion)
{
	command->setText(suggestion->suggestion());
	command->setFocus();
	command->setCaretPosition(suggestion->suggestion().size());
}

void CommandPrompt::showPrompt()
{
	show();
	command->setFocus();
	command->setSelectedCharacters(commandSelectedFirst, commandSelectedLast);
}

void CommandPrompt::hidePrompt()
{
	commandSelectedFirst = command->selectionFirstInxed();
	commandSelectedLast = command->selectionLastIndex();
	hide();
	commandReceiver_->setFocus();
}

void CommandPrompt::determineChildren()
{
	GenericHandler* h = dynamic_cast<GenericHandler*> (handler());

	if (h)
	{
		removeSuggestions();
		addSuggestions( h->executionEngine()->autoComplete(commandReceiver_, command->getText()));
	}
}

void CommandPrompt::updateGeometry(int availableWidth, int availableHeight)
{
	Item::updateGeometry(layout, availableWidth, availableHeight);

	// Set the position of the prompt
	if (justCreated)
	{
		QPointF promptPos = commandReceiver_->mapToScene(0,0);
		if (commandReceiver_->height() < COMMAND_RECEIVER_ITEM_MIN_PROMPT_CENTER_HEIGHT)
		{
			// Show the prompt under the receiver item.
			promptPos.setY( promptPos.y() + commandReceiver_->height() + PROMPT_TO_RECEIVER_DISTANCE);
		}
		else
		{
			// Show the prompt at the center of the receiver item.
			promptPos.setX( (commandReceiver_->width()-width()) / 2 );
			promptPos.setY( (commandReceiver_->height()-height()) / 2 );
		}

		setPos(promptPos);
		justCreated = false;
	}
}

void CommandPrompt::setResult(CommandResult* result)
{
	removeResult();
	result_ = result;

	// Add the errors to the list
	for (int i = 0; i<result->errors().size(); ++i)
	{
		// Create visualization if one is missing.
		if (result->errors()[i]->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultError());
			vis->setContents(result->errors()[i]->message(), result->errors()[i]->resolutionTips().join(" OR "));
			result->errors()[i]->setVisualization(vis);
		}

		// Add the visualization to the container layout
		errorContainer->append(result->errors()[i]->visualization());
	}

	// Add the suggestions to the list
	for (int i = 0; i<result->suggestions().size(); ++i)
	{
		// Create visualization if one is missing.
		if (result->suggestions()[i]->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
			vis->setContents(result->suggestions()[i]->suggestion(), result->suggestions()[i]->description());
			result->suggestions()[i]->setVisualization(vis);
		}

		// Add the visualization to the container layout
		suggestionContainer->append(result->suggestions()[i]->visualization());
	}
	setUpdateNeeded();
}

void CommandPrompt::removeResult()
{
	if (result_)
	{
		// Remove all suggestion visual items contributed by the result.
		for (int i = 0; i<result_->suggestions().size(); ++i)
			suggestionContainer->removeAll(result_->suggestions().at(i)->visualization(), false);

		// Remove all error visual items contributed by the result.
		for (int i = 0; i<result_->errors().size(); ++i)
			errorContainer->removeAll(result_->errors().at(i)->visualization(), false);
	}
	SAFE_DELETE(result_);
	setUpdateNeeded();
}

void CommandPrompt::addSuggestion(CommandSuggestion* suggestion)
{
	suggestions_.append(suggestion);

	// Create visualization if one is missing.
	if (suggestion->visualization() == NULL)
	{
		TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
		vis->setContents(suggestion->suggestion(), suggestion->description());
		suggestion->setVisualization(vis);
	}

	// Add the visualization to the container layout
	suggestionContainer->append(suggestion->visualization());

	setUpdateNeeded();
}

void CommandPrompt::addSuggestions(const QList<CommandSuggestion*>& suggestions)
{
	for (int i = 0; i < suggestions.size(); ++i)
	{
		suggestions_.append(suggestions[i]);

		// Create visualization if one is missing.
		if (suggestions_.last()->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
			vis->setContents(suggestions_.last()->suggestion(), suggestions_.last()->description());
			suggestions_.last()->setVisualization(vis);
		}

		// Add the visualization to the container layout
		suggestionContainer->append(suggestions_.last()->visualization());
	}
	setUpdateNeeded();
}

void CommandPrompt::removeSuggestions()
{
	for (int i = 0; i<suggestions_.size(); ++i)
	{
		suggestionContainer->removeAll(suggestions_.at(i)->visualization(), false);
		SAFE_DELETE(suggestions_[i]);
	}
	suggestions_.clear();
	setUpdateNeeded();
}

}
<commit_msg>Changed the command text to be editable.<commit_after>/***********************************************************************************************************************
 * CommandPrompt.cpp
 *
 *  Created on: Jan 18, 2011
 *      Author: Dimitar Asenov
 **********************************************************************************************************************/

#include "vis/CommandPrompt.h"
#include "vis/TextAndDescription.h"
#include "handlers/GenericHandler.h"
#include "commands/CommandExecutionEngine.h"

#include "VisualizationBase/headers/Scene.h"

using namespace Visualization;

namespace Interaction {

/**
 * Specifies the minimal height of the commandReceiver item which will make a new prompt appear in the center of the
 * item.
 *
 * If the receiver item's height is less than this number, then the prompt will be placed directly under the item.
 * Otherwise the prompt will be centered inside the item.
 */
const int COMMAND_RECEIVER_ITEM_MIN_PROMPT_CENTER_HEIGHT = 50;

/**
 * The distance between a prompt which is shown under the command receiver item and that item.
 */
const int PROMPT_TO_RECEIVER_DISTANCE = 3;

ITEM_COMMON_DEFINITIONS(CommandPrompt)

CommandPrompt::CommandPrompt(Item* commandReceiver, const CommandPromptStyle* style) :
	Item(NULL, style),
	commandReceiver_(commandReceiver),
	layout(new SequentialLayout(this, &style->layout())),
	suggestionContainer(new SequentialLayout(NULL, &style->suggestionContainer())),
	errorContainer(new SequentialLayout(NULL, &style->errorContainer())),
	command( new Text(NULL, &style->commandText())),
	result_(NULL),
	justCreated(true)
{
	setFlag(QGraphicsItem::ItemIsMovable);
	command->setEditable(true);

	layout->append(command);
	layout->append(errorContainer);
	layout->append(suggestionContainer);
}

CommandPrompt::~CommandPrompt()
{
	commandReceiver_ = NULL; // This item is completely out of our control, we just know about it.

	removeResult();
	removeSuggestions();

	SAFE_DELETE_ITEM(layout);

	// These are deleted by layout's destructor
	command = NULL;
	suggestionContainer = NULL;
	errorContainer = NULL;
}

void CommandPrompt::initializeCommand()
{
	command->setText("Type a command");
	command->setFocus();
	command->selectAll();
}

void CommandPrompt::takeSuggestion(CommandSuggestion* suggestion)
{
	command->setText(suggestion->suggestion());
	command->setFocus();
	command->setCaretPosition(suggestion->suggestion().size());
}

void CommandPrompt::showPrompt()
{
	show();
	command->setFocus();
	command->setSelectedCharacters(commandSelectedFirst, commandSelectedLast);
}

void CommandPrompt::hidePrompt()
{
	commandSelectedFirst = command->selectionFirstInxed();
	commandSelectedLast = command->selectionLastIndex();
	hide();
	commandReceiver_->setFocus();
}

void CommandPrompt::determineChildren()
{
	GenericHandler* h = dynamic_cast<GenericHandler*> (handler());

	if (h)
	{
		removeSuggestions();
		addSuggestions( h->executionEngine()->autoComplete(commandReceiver_, command->getText()));
	}
}

void CommandPrompt::updateGeometry(int availableWidth, int availableHeight)
{
	Item::updateGeometry(layout, availableWidth, availableHeight);

	// Set the position of the prompt
	if (justCreated)
	{
		QPointF promptPos = commandReceiver_->mapToScene(0,0);
		if (commandReceiver_->height() < COMMAND_RECEIVER_ITEM_MIN_PROMPT_CENTER_HEIGHT)
		{
			// Show the prompt under the receiver item.
			promptPos.setY( promptPos.y() + commandReceiver_->height() + PROMPT_TO_RECEIVER_DISTANCE);
		}
		else
		{
			// Show the prompt at the center of the receiver item.
			promptPos.setX( (commandReceiver_->width()-width()) / 2 );
			promptPos.setY( (commandReceiver_->height()-height()) / 2 );
		}

		setPos(promptPos);
		justCreated = false;
	}
}

void CommandPrompt::setResult(CommandResult* result)
{
	removeResult();
	result_ = result;

	// Add the errors to the list
	for (int i = 0; i<result->errors().size(); ++i)
	{
		// Create visualization if one is missing.
		if (result->errors()[i]->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultError());
			vis->setContents(result->errors()[i]->message(), result->errors()[i]->resolutionTips().join(" OR "));
			result->errors()[i]->setVisualization(vis);
		}

		// Add the visualization to the container layout
		errorContainer->append(result->errors()[i]->visualization());
	}

	// Add the suggestions to the list
	for (int i = 0; i<result->suggestions().size(); ++i)
	{
		// Create visualization if one is missing.
		if (result->suggestions()[i]->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
			vis->setContents(result->suggestions()[i]->suggestion(), result->suggestions()[i]->description());
			result->suggestions()[i]->setVisualization(vis);
		}

		// Add the visualization to the container layout
		suggestionContainer->append(result->suggestions()[i]->visualization());
	}
	setUpdateNeeded();
}

void CommandPrompt::removeResult()
{
	if (result_)
	{
		// Remove all suggestion visual items contributed by the result.
		for (int i = 0; i<result_->suggestions().size(); ++i)
			suggestionContainer->removeAll(result_->suggestions().at(i)->visualization(), false);

		// Remove all error visual items contributed by the result.
		for (int i = 0; i<result_->errors().size(); ++i)
			errorContainer->removeAll(result_->errors().at(i)->visualization(), false);
	}
	SAFE_DELETE(result_);
	setUpdateNeeded();
}

void CommandPrompt::addSuggestion(CommandSuggestion* suggestion)
{
	suggestions_.append(suggestion);

	// Create visualization if one is missing.
	if (suggestion->visualization() == NULL)
	{
		TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
		vis->setContents(suggestion->suggestion(), suggestion->description());
		suggestion->setVisualization(vis);
	}

	// Add the visualization to the container layout
	suggestionContainer->append(suggestion->visualization());

	setUpdateNeeded();
}

void CommandPrompt::addSuggestions(const QList<CommandSuggestion*>& suggestions)
{
	for (int i = 0; i < suggestions.size(); ++i)
	{
		suggestions_.append(suggestions[i]);

		// Create visualization if one is missing.
		if (suggestions_.last()->visualization() == NULL)
		{
			TextAndDescription* vis = new TextAndDescription(NULL, &style()->defaultSuggestion());
			vis->setContents(suggestions_.last()->suggestion(), suggestions_.last()->description());
			suggestions_.last()->setVisualization(vis);
		}

		// Add the visualization to the container layout
		suggestionContainer->append(suggestions_.last()->visualization());
	}
	setUpdateNeeded();
}

void CommandPrompt::removeSuggestions()
{
	for (int i = 0; i<suggestions_.size(); ++i)
	{
		suggestionContainer->removeAll(suggestions_.at(i)->visualization(), false);
		SAFE_DELETE(suggestions_[i]);
	}
	suggestions_.clear();
	setUpdateNeeded();
}

}
<|endoftext|>